使用 Spring Boot 进行 Kotlin 集成测试

Posted

技术标签:

【中文标题】使用 Spring Boot 进行 Kotlin 集成测试【英文标题】:Kotlin integration Tests with Spring Boot 【发布时间】:2020-07-24 10:53:52 【问题描述】:

我所拥有的:我正在开发一个微服务,使用带有 Web 和 MongoDB 作为存储的 Spring Boot。对于 CI 集成测试,我使用测试容器。我有两个带有 SpringBootTest 注释的集成测试,它们使用 TestConfig 类。 TestConfig 类提供具有固定暴露端口的设置 MongoDB 测试容器。

我的问题:当我一次运行一个测试时,它们会成功。但是当我同时运行测试时,它们失败了。

MongoContainerConfig.kt

@TestConfiguration
class MongoContainerConfig 

    var mongoContainer: GenericContainer<Nothing>

    constructor() 
        mongoContainer = FixedHostPortGenericContainer<Nothing>("mongo")
                .withFixedExposedPort(27018,27017)
        mongoContainer.start()
    

    @PreDestroy
    fun close() 
        mongoContainer.stop()
    

第一次测试

@SpringBootTest(
    classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class),
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
)
class CardControllerTest 

    @Test
    fun test() 

第二次测试

@SpringBootTest(classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class))
class PositiveTest 

    @Test
    fun test() 

错误信息

Failed to load ApplicationContext
java.lang.IllegalStateException: Failed to load ApplicationContext
    at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
...
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'mongoContainerConfig': Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.lang.card.engcard.config.MongoContainerConfig$$EnhancerBySpringCGLIB$$e58ffeee]: Constructor threw exception; nested exception is org.testcontainers.containers.ContainerLaunchException: Container startup failed
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1320)
    a

这个项目你可以在 github 上看到 CI https://github.com/GSkoba/eng-card/runs/576320155?check_suite_focus=true

这很有趣,因为如果将测试重写为 java 就可以工作

【问题讨论】:

【参考方案1】:

哈,不容易) https://docs.spring.io/spring/docs/5.2.5.RELEASE/spring-framework-reference/testing.html#testcontext-ctx-management-caching 测试有不同的上下文,这也是 MongoContainerConfig 调用两次的原因。 修复 - 在 CardControllerTest.kt 中添加 webEnv

@SpringBootTest(classes = arrayOf(MongoContainerConfig::class, AssertUtilsConfig::class),
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class PositiveTest 

证明https://github.com/GSkoba/eng-card/actions/runs/78094215

【讨论】:

以上是关于使用 Spring Boot 进行 Kotlin 集成测试的主要内容,如果未能解决你的问题,请参考以下文章

使用 spring boot、kotlin 和 junit 进行休息控制器单元测试

如何使用 Gradle Kotlin DSL 对 Spring Boot 应用程序进行 Dockerize

使用 Spring Boot 2 和 Kotlin 进行 Jackson 反序列化,无法构造 `java.time.LocalDate` 的实例

GraphQL + Kotlin & Spring Boot 上手指南

我是不是需要使用 Kotlin Junit5 和 Spring Boot 将 Spring 注释复制到内部类?

Spring Boot没有使用Jackson Kotlin插件