春天顶部

通过参考,使用Spring 5和Spring Boot 2开始学习春天课程:

>>学习春天

1.介绍

在本文中,我们将使用Spring以及如何优化它们的集成测试进行整体讨论。金宝搏官网188be

首先,我们将简要讨论集成测试的重要性以及它们在现代软件中的地位,重点放在Spring生态系统上。

稍后,我们将介绍多种方案,专注于Web-Apps。

接下来,我们将讨论一些改善测试速度的策略,通过了解可以影响我们塑造我金宝搏官网188be们的测试的不同方法以及我们塑造应用程序本身的方式。

在开始之前,重要的是要记住这是一个基于经验的意见文章。其中一些可能适合你,有些可能不是。

最后,本文使用Kotlin为代码样本来保持它们尽可能简洁,但该概念不具体对此语言而且代码片段应该对Java和Kotlin开发人员感到有意义。

2.集成试验

集成测试是自动化测试套件的基础部分。虽然如果我们遵循一个,但它们不应该像单位测试一样多健康的测试金字塔。依靠春天的框架让我们需要一个相当数量的整合测试,以便对我们的系统的某些行为进行风险。

我们通过使用Spring模块(数据,安全性,社交......)来简化我们的代码越多,需要集成测试的需求越大。当我们把基础设施的零零碎碎的东西@ configuration课程。

我们不应该“测试框架”,但我们肯定应该验证框架是否配置以满足我们的需求。

集成测试帮助我们建立信心,但它们是有代价的:

  • 这是一种较慢的执行速度,这意味着较慢的构建
  • 此外,集成测试意味着更广泛的测试范围,这在大多数情况下并不理想

考虑到这一点,我们将试图找到一些解决方案来缓解上述问题。

3.测试Web应用程序

Spring带来了一些选项才能测试Web应用程序,而大多数春天开发人员熟悉它们,这些是:

  • mockmvc.:模拟servlet API,对非响应性web应用很有用
  • testresttemplate.:可以指向我们的应用程序,对非反应性Web应用程序有用,其中嘲笑的servlet是不可取的
  • WebTestClient.:是反应性Web应用程序的测试工具,都是模拟的请求/响应或击中真实服务器

由于我们已经有了涉及这些主题的文章,我们将不再花时间讨论它们。金宝搏官网188be

如果你想深入挖掘,请随意看看。

4.优化执行时间

集成测试很棒。他们给我们一个很好的信心。此外,如果适当实施,他们也可以以非常明确的方式描述我们应用的意图,较少的嘲弄和设置噪声。

但是,随着我们的应用程序成熟和发展堆积,建立时间不可避免地上升。随着建筑时间的增加,每次运行所有测试都可能变得不切实际。

此后,影响我们的反馈循环并妨碍了最佳的发展实践。

此外,集成测试本质上是昂贵的。启动某种类型的持久性,通过(即使他们永远不会离开)localhost.),或者做一些IO只是需要时间。

密切关注我们的建筑时间,包括测试执行是至关重要的。有一些技巧我们可以在春天申请,保持它低。

在下一节中,我们将涵盖几点,以帮助我们优化我们的建筑时间以及可能影响其速度的一些陷阱:

  • 明智地使用配置文件 - 如何概况影响性能
  • 重新考虑@mockbean -嘲笑是如何打击绩效的
  • 重构@MockBean.- 改善性能的替代方案
  • 仔细思考@金宝搏官网188bedirtiescontext -一个有用但危险的注释以及如何不要使用它
  • 使用测试切片 - 一个可以帮助或继续我们的酷工具
  • 使用类继承 - 以安全的方式组织测试的方法
  • 国家管理 - 避免Flakey Tests的良好做法
  • 重构进入单元测试 - 获得稳固和旋转构建的最佳方式

让我们开始吧!

4.1。明智地使用配置文件

概要文件是一个很好的工具。也就是说,简单的标签可以启用或禁用我们的应用程序的某些区域实现功能的旗帜跟他们!

随着我们的档案越来越富裕,它现在正在交换,然后在我们的集成测试中令人诱人。有方便的工具可以这样做@activeprofiles.。然而,每次使用新档案进行测试,新的档案ApplicationContext.创建。

创建应用程序上下文可能与vanilla Spring Boot应用程序类似于其中的内容。添加ORM和一些模块,它将快速飙升到7秒。

添加一堆配置文件,并通过一些测试来分散它们,我们将快速获得60秒以上的构建(假设我们作为我们构建的一部分运行测试 - 我们应该)。

一旦我们面对足够复杂的应用,修复这是令人生畏的。但是,如果我们提前仔细计划,保持明智的建筑时间变得微不足道。

在集成测试中涉及概况时,我们可以记住一些技巧:

  • 创建聚合配置文件,即测试,包括在粘附到我们的测试配置文件中的所有必需的配置文件
  • 在设计概要文件时要考虑到可测试性。如果我们最终不得不交换配置文件,也许还有更好的办法
  • 在一个集中的地方声明我们的测试概要文件——我们稍后将讨论这个问题金宝搏官网188be
  • 避免测试所有配置文件组合。或者,我们可以使用每个环境测试套件,并使用特定的配置文件集测试应用程序

4.2。问题@MockBean.

@MockBean.是一个非常强大的工具。

当我们需要一些春季魔法但想要模拟特定的组件时,@MockBean.真的很方便。但它以价格为例。

每一次@MockBean.类出现在类中ApplicationContext.缓存可显示为脏污,因此runner将在完成测试类后清理缓存。这又为我们的构建增加了额外的时间。

这是一个有争议的问题,但尝试使用实际的应用程序,而不是嘲笑这个特定的场景可能会有帮助。当然,这里没有什么灵丹妙药。当我们不允许自己模仿依赖关系时,边界就变得模糊了。

我们可能会思考:为什么我们想要测试的只是我们的休息层?这是一个公平的一点,总是妥协。

但是,通过少数原则,这实际上可能变成了一个优势,导致更好地设计测试和我们的应用并减少测试时间。

4.3。重构@MockBean.

在本节中,我们将尝试使用“慢速”测试使用@MockBean.使它重用缓存ApplicationContext.

让我们假设要测试一个创建用户的POST。如果我们是嘲笑-使用@MockBean.,我们可以简单地验证我们的服务已经被一个良好的序列化用户调用。

如果我们正确地测试了我们的服务,这种方法就足够了:

类UsersControllerIntegrationTest: AbstractSpringIntegrationTest() {@Autowired lateinit var mvc: MockMvc @MockBean lateinit var userService:UserService @Test fun links() {mvc.perform(post("/users") .contentType(MediaType.APPLICATION_JSON) .content("""{"name":"jose"}""")) .and期望(status().isCreated) verify(UserService).save("jose")}} interface UserService {fun save(name: String)}}

我们要避免@MockBean.尽管。所以我们最终坚持不懈地坚持(假设这是服务的影响)。

这里最天真的方法是测试副作用:发布后,我的用户在我的数据库中,在我们的例子中,这将使用JDBC。

然而,这违反了测试边界:

@test有趣的链接(){mvc.perform(post(“/用户”).contenttype(mediatype.application_json).Content(“”“{”名称“:”Jose“}”“”“).Andexpect(状态().iscreated)assertthat(jdbctestutils.countrowstable(jdbctemplate,“用户”)).isone()}

在这个特殊的例子中,我们违反了测试边界,因为我们将我们的应用程序视为一个HTTP黑匣子以发送用户,但后来我们使用实现详细说明,即我们的用户已坚持在某些数据库中。

如果我们通过HTTP锻炼我们的应用程序,我们也可以通过HTTP断言结果吗?

@test有趣的链接(){mvc.perform(post(“/用户”).contenttype(mediatype.application_json).Content(“”“{”名称“:”Jose“}”“”“).Andexpect(状态().iscreated)mvc.perform(get(“/用户/ jose”)).Andexpect(status()。isok)}

如果我们遵循最后一个方法,有一些优势:

  • 我们的测试将更快地开始(可以说,它可能需要更长的时间来执行,但它应该回报)
  • 此外,我们的测试不知道与HTTP边界(即db)无关的副作用
  • 最后,我们的测试清楚地表达了系统的目的:如果您POST,您将能够GET Users

当然,由于各种原因,这可能并不总是可能:

  • 我们可能没有“副作用”端点:这里的选项是考虑创建“测试端点”
  • 复杂性太高而无法击中整个应用程序:这里的选项是考虑切片(我们稍后会谈论它们)金宝搏官网188be

4.4。仔细思考金宝搏官网188be@dirtiescontext.

有时,我们可能需要修改ApplicationContext.在我们的测试中。对于这种情况,@dirtiescontext.准确地提供了该功能。

出于上面暴露的原因,@dirtiescontext.在执行时间时是一个非常昂贵的资源,因此,我们应该小心。

一些滥用@dirtiescontext.包括应用程序缓存重置或内存数据库重置。在集成测试中有更好的方法来处理这些场景,我们将在后面的章节中介绍一些方法。

4.5。使用测试片

测试切片是1.4中引入的弹簧引导功能。该想法是相当简单的,Spring将为您的应用程序的特定切片创建一个简单的应用程序上下文。

此外,该框架将负责最小限度的配置。

在春天启动中有一个可用的切片数量,我们也可以创建自己:

  • @jsontest:注册JSON相关组件
  • @DataJpaTest:注册JPA Bean,包括可用的ORM
  • @jdbctest.:对原始JDBC测试有用,请小心数据源以及内存DBS而无需ORM Frills
  • @Datamongotest.:尝试提供内存中的mongo测试设置
  • @webmvctest.:模拟MVC测试切片,没有其余的应用程序
  • ......(我们可以检查找到他们全部)

如果使用得当,这个特性可以帮助我们构建更小范围的测试,而不会对中小型应用的性能造成太大的损失。

但是,如果我们的申请不断增长,它也会堆积,因为它会产生一个(小)申请上下文。

4.6。使用类继承

使用单身AbstractspringIntegrationTest.作为我们所有集成测试的父母的课程是一种简单,强大而务实的方式,可以快速保持构建。

如果我们提供稳固的设置,我们的团队将简单地扩展它,了解一切'只是有效'。这样,我们可以少担心管理州或配置框架并专注于手头的问题金宝搏官网188be。

我们可以在那里设置所有测试要求:

  • 春流赛 - 或最好是规则,以防我们稍后需要其他跑步者
  • 个人资料 - 理想情况下我们的总体测试轮廓
  • 初始配置 - 设置应用程序状态

让我们来看看一个简单的基类,负责前一点:

@springboottest @activeprofiles(“test”)抽象类AbstractspringStegrationTest {@rule @jvmfield val spressmethodrule = springmethodrule()伴随对象{@classrule @jvmfield val spring_class_rule = springclassrule()}}

4.7。国家管理层

重要的是要记住单位测试中的“单位”来自。简单地说,这意味着我们可以在任何一致的结果中运行单个测试(或子集)。

因此,在每次测试开始之前,状态应该是干净的和已知的。

换句话说,无论是否以隔离或与其他测试一起执行,测试的结果都应该是一致的。

这个想法适用于集成测试。我们需要确保在开始新测试之前拥有已知(和可重复的)状态。我们重用速度的组件越多(应用上下文,DB,队列,文件......),越来越多地获得州污染。

假设我们现在与班级继承一起,我们有一个管理状态的中央地。

让我们增强我们的抽象类,以确保在运行测试之前我们的应用程序处于已知状态。

在我们的示例中,我们假设有几个存储库(来自各种数据源),以及丝袜服务器:

@SpringBootTest @ActiveProfiles("test") @AutoConfigureWireMock(port = 8666) @AutoConfigureMockMvc抽象类AbstractSpringIntegrationTest{//…repos: Set> @Autowired lateinit var cacheManager:cacheemanager @Before fun resetState() {cleanAllDatabases() cleanAllCaches() resetWiremockStatus()} fun cleanAllDatabases() {JdbcTestUtils.deleteFromTables(jdbcTemplate, "table1", "table2") jdbcTemplate。update("ALTER TABLE table1 ALTER COLUMN id RESTART WITH 1")forEach {it.deleteAll()}} fun cleanAllCaches(){缓存管理器。cacheNames .map {cacheManager.getCache(it)} .filterNotNull() .forEach {it.clear()}} fun resetWiremockStatus() {wireMockServer.resetAll() //设置默认请求

4.8。重构进入单元测试

这可能是最重要的一点之一。我们会在一些实际上锻炼应用程序的一些高级政策的集成测试中遍布自己一遍又一遍地。

每当我们找到一些集成测试测试一堆核心业务逻辑的案例时,它是时候重新思考我们的方法并将其分解为单位测试。

这里可能的模式成功完成这一点:

  • 确定测试核心业务逻辑的多个场景的集成测试
  • 复制套件,并将其重构到单元测试中——在这个阶段,我们可能需要分解产品代码以使其具有可测试性
  • 得到所有测试绿色
  • 在集成套件中留出令人瞩目的快乐路径样本 - 我们可能需要重构或加入并重塑一些
  • 删除剩余的集成测试

迈克尔羽毛涵盖了许多技术,以实现这一目标,更有效地与遗留码合作。

5.总结

在本文中,我们介绍了集成测试与春天的重点。

首先,我们讨论了集成测试的重要性以金宝搏官网188be及它们在春季应用中特别相关。

之后,我们总结了一些工具,可以派上Web应用程序中某些类型的集成测试。

最后,我们经历了一个潜在问题的列表,减慢了我们的测试执行时间,以及改进它的技巧。

春天底

使用Spring 5和Spring Boot 2开始,通过学习春天课程:

> >这门课程
对这篇文章的评论关闭!