在测试套件结束后保持 Spring 上下文运行,IntelliJ

Man*_*nza 5 spring spring-test spring-boot

故事是这样的:每次我想运行一个或多个集成测试时,Spring 上下文都需要启动,最多需要 2 分钟。

这有点令人沮丧,因为每次最小的更改之后我都需要等待以检查测试结果。

有没有办法在测试结束后保持 Spring 上下文运行,以避免等待?类似于启动 Spring 应用程序一次然后执行测试。

更新

刚刚发现了一个非常相似的问题: 如何在 Intellij Idea 中的测试运行之间保持 spring 上下文加载?

Rad*_*Rad 0

为了完整起见,复制我在另一个问题中的答案:
可能不是最干净的解决方案,但效果很好。

  1. 在测试中创建一个 Spring-Boot 应用程序,或多或少代表主应用程序(就配置而言):
// In a different package from the main application
// The `scanBasePackages` is the same as the main application!
@SpringBootApplication(scanBasePackages = ["com.example.api"])
class TestApplication {
    companion object {
        @JvmStatic // main method to be able to run it in IDEs
        fun main(args: Array<String>) {
            runApplication<TestApplication>(*args)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 创建另一个Spring Boot 应用程序,其中将上述应用程序创建并发布为 bean:
// In a different package from to the above
// Ideally this should almost exclude every Spring configurations
// in the classpath (they should be loaded in the above application)
@SpringBootApplication
class TestApplicationLoader {

    @Value("\${test-subject.context.load:true}")
    private var loadContext = false

    @Bean
    fun testSubject(): Closeable {
        return if (loadContext) {
            val environment = StandardEnvironment()
            val sa = SpringApplication(TestApplication::class.java)
            sa.run()
        } else { // it's loaded by the IDE or Gradle!
            Closeable {}
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 最后,添加正常的 Spring Boot 测试:
// If you make TestApplicationLoader as thin as possible
// this should take around one second or two to complete!
@SpringBootTest(classes = [TestApplicationLoader::class])
class MyControllerTest : StringSpec() {
    override fun extensions() = listOf(SpringExtension)

    @Autowired
    lateinit var testRestTemplate: TestRestTemplate

    init {
        "test" {
            val res = testRestTemplate.getForObject("http://localhost:8081/hello", String::class.java)
            res shouldBe "mocked in test-application"
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这种方法有一些需要注意/改进的地方:

  1. 它需要团队在代码库维护方面有良好的纪律;在哪里放置集成测试、Spring 配置、bean 等。您很容易会因为不需要的 bean 而导致混乱的上下文。
  2. 如何处理环境、配置文件和属性并不简单。
  3. 访问在主应用程序上下文中创建的 bean 是一个挑战。(例如 JDBC 数据源 bean。)
  4. 如何处理共享资源(例如端口)是一个(不那么难的)问题。
  5. 对 Gradle Continues Build 的支持需要在构建脚本中进行一些配置。

在这里创建了一个示例项目作为概念证明。
(事实上​​,没有人处理过这个问题,这真是令人难以置信。期待官方和/或更好的解决方案)