Spring集成测试-重写bean的惯用方法

Spring集成测试-重写bean的惯用方法,spring,spring-boot,spring-boot-test,Spring,Spring Boot,Spring Boot Test,如何以惯用的方式覆盖Spring(Boot)集成测试中的bean 到目前为止,我的源代码配置如下: @Configuration class ApplicationConfiguration { @Bean CarsRepository carsRepository() { // return some real sql db } } @SpringBootTest class ApplicationISpec extends Specification { @Conf

如何以惯用的方式覆盖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
  }
}
还有这样的测试:

@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
  }
}
首先,testbean
testscarsepository
方法必须不同于原始方法(这并不明显,也没有警告/错误)。 但最后一个问题是:在集成测试中用Spring覆盖bean的惯用方法是什么

当我在上发布关于方法名的WTF时,我说
@Primary
不打算用于在测试中重写bean


那么,首选的方法是什么呢?

您可以使用
@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”)
标记生产配置
应用程序配置


此外,Spring Boot还提供了大量的测试工具(例如带有嵌入式数据库的
@DataJpaTest
,用于在上下文中模拟bean的
@MockBean
),等等)

@MockBean
看起来是一个不错的选择。@StephaneNicoll我编辑了这篇文章,所以它介绍了更多的用例。我不想嘲笑我的豆子。与此相反,我只想用其他一些只用于测试的实现来替换它。假设我想运行Spring集成测试(这样所有的bean图都被加载),但我想用内存实现替换一些边界bean(如DB、外部服务或其他),这就是为什么我们创建了
MockBean
。如果您想使用内存数据库运行,我们也支持它(
@AutoconfigureTestDatabase
)。在不使用概要文件的情况下重写bean需要排序并使用相同的bean名称,因此有点脆弱。所以在拒绝之前我会先看看这些选项。@StephaneNicoll谢谢你的意见。所以对我来说,
@Profile
&
@Primary
可能是一条出路。我想用测试bean替换应用程序bean。它不必与数据库相关。它可以有一些配置选项,或者类似的东西。我不想嘲笑它。我只想对测试使用不同的实现。谢谢你的贡献!您不需要
@Primary
。被接受的答案在我看来有点好,我知道这种方法,但在我的推特上与Stepahne Nicoll的答案相混淆,所以这就是我问的原因。尽管如此,还是要感谢您的投入!顺便说一句,你不需要所有的代码。如果你的
TestConfig
只有
@TestConfiguration
,它就可以工作了。ActiveProfiles将禁用“生产”服务,并在默认行为的顶部应用额外的配置(基本上检测
应用程序
类)。如果您同意,您可以编辑您的答案吗?谢谢您的回复!老实说,我不明白如何正确地将
@TestConfiguration
应用于这段代码。我能请你把你自己的答案和你的方法贴在一起吗?包括
@ActiveProfiles
不是最佳选择的原因。我相信这会对我和问题的作者有所帮助。提前谢谢!这种方法的关键弱点是需要将
@Profile(“!test”)
添加到应用程序bean中。我希望我的测试有选择地逐个替换任何应用程序bean,而不是在同一测试中同时替换所有应用程序bean。。。使用这种方法是不可能的,因为只要我将
@Profile(“!test”)
添加到我的bean中,我的所有测试都将需要另一个“mock bean”而不是这个bean,并且在我提供bean的一些实现之前应用程序上下文将不会启动(因为其他应用程序的bean可以依赖它)。