【问题标题】:Spring Integration Tests - idiomatic way of overriding beansSpring 集成测试 - 覆盖 bean 的惯用方式
【发布时间】:2018-04-04 02:14:14
【问题描述】:

如何以惯用的方式覆盖 Spring(Boot)集成测试中的 bean?

到目前为止,我的源配置是这样的:

@Configuration
class ApplicationConfiguration {
  @Bean
  CarsRepository carsRepository() {
    // return some real sql db
  }
}

还有这样的测试:

@SpringBootTest
class ApplicationISpec extends Specification {
  @Configuration
  @Import(Application.class)
  static class TestConfig {
    @Bean
    @Primary
    CarsRepository testsCarsRepository() {
      // return some in-memory repository
    }
  }

  def "it can do stuff with cars"() {
    // do some REST requests to application and verify it works
    // there is no need to make real calls to real DB
  }
}

第一件事是测试 bean testsCarsRepository 方法必须不同于原始方法(这并不明显,并且没有警告/错误)。 但最后一个问题是:在集成测试中用 Spring 覆盖 bean 的惯用方式是什么?

当我在 Twitter - Stephane Nicoll 上发布有关方法名称的 WTF 时,说 @Primary 不打算用于在测试中覆盖 bean。

那么首选的方法是什么?

【问题讨论】:

  • @MockBean 看起来不错。
  • @StephaneNic​​oll 我已经编辑了帖子,所以它更多地说明了用例。我不想嘲笑我的豆子。而不是我只想用其他一些测试实现替换它。想象一下,我想运行 Spring 集成测试(因此所有 bean 图都已加载),但我想用内存中的实现替换一些边界 bean(如 DB、外部服务等)
  • 您所指的是我们创建MockBean 的原因。如果您想使用内存数据库运行,我们也支持 (@AutoconfigureTestDatabase)。在不使用配置文件的情况下覆盖 bean 需要订购和使用相同的 bean 名称,因此它有点脆弱。所以我会在拒绝之前先看看这些选项。
  • @StephaneNic​​oll 感谢您的意见。所以可能@Profile@Primary 是我要走的路。我想用测试 bean 替换应用程序 bean。它不必与数据库相关。它可以有一些配置选项,或者类似的东西。我不想嘲笑它。我只想使用不同的实现进行测试。感谢贡献!
  • 你不需要@Primary。接受的答案对我来说似乎有点好

标签: spring spring-boot spring-boot-test


【解决方案1】:

您可以使用@Profile@ActiveProfile 注释来分隔您的测试和生产配置。例如,将您的测试配置更改为:

@SpringBootTest
@ActiveProfiles("test")
class CarsISpec extends Specification {
    @Configuration
    @Import(Application.class)
    @Profile("test")
    static class TestConfig {
       @Bean
       CarsRepository testsCarsRepository() {
       // return some in-memory repository
       }
  }
}

别忘了用@Profile("!test") 标记你的生产配置ApplicationConfiguration

Spring Boot 还提供了许多测试工具(例如,@DataJpaTest 带有嵌入式数据库,@MockBean 用于在上下文中模拟 bean 等)Link to doc

【讨论】:

  • 谢谢,我知道这种方法,但对我的推文上的 Stepahne Nicoll 回答感到困惑,所以这就是我问的原因。不过感谢您的意见!
  • 顺便说一句,您不需要所有代码。如果您的TestConfig 只有@TestConfiguration,它将起作用。 ActiveProfiles 将禁用“生产”服务,并且额外的配置将应用在默认行为之上(基本上检测Application 类)。如果您同意,您可以编辑您的答案吗?
  • 感谢您的回复!老实说,我不明白如何将@TestConfiguration 正确应用于这段代码。我可以请您用您的方法发布自己的答案吗?包括为什么@ActiveProfiles 不是最佳选择的原因。我相信这对我和问题的作者都会有所帮助。提前致谢!
  • 这种方法的主要弱点是需要将@Profile("!test") 添加到应用程序bean。我希望我的测试能够有选择地一个接一个地替换任何应用程序 bean,而不是在同一个测试中同时替换所有应用程序 bean……用这种方法这是不可能的,因为只要我将 @Profile("!test") 添加到我的 bean 中,我所有的测试都需要另一个“模拟 bean”而不是这个 bean,并且应用程序上下文在我提供 bean 的一些实现之前不会启动(因为其他应用程序的 bean 可以依赖它)。
猜你喜欢
  • 1970-01-01
  • 2016-06-15
  • 2018-11-09
  • 2019-01-31
  • 2023-04-04
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多