intellij-idea 如何在Intellij Idea中保持测试运行之间加载Spring上下文?

mf98qq94  于 2022-11-01  发布在  IntelliJ IDEA
关注(0)|答案(2)|浏览(155)

Spring-test提供了在测试运行期间加载Spring上下文的注解。例如,有一个org.springframework.test.context.junit4.SpringJUnit4ClassRunner junit runner类和org.springframework.test.context.ContextConfiguration注解用于指定上下文加载。对于集成测试,上下文加载可能会很长,在调试期间,需要运行相同的测试十几次,直到“丢失”所有错误。有没有方法在不多次加载上下文的情况下做到这一点?例如,我完成了上下文加载的调试,然后运行该上下文并开始在Intellij Idea中运行测试?这在Intellij Idea中是可能的吗?

1bqhqjot

1bqhqjot1#

很久以前没有答案,这是奇怪的,这是非常重要的知道,因为它可以保存大量的资源和时间。
如果您有一个带有注解的类

@SpringBootTest
public class IntegrationTest

并且你将它扩展到你所有的Test类上下文将只被加载一次

public class ServiceIntegationTest extends IntegrationTest

此类中所有测试将使用相同上下文扩展此类所有类也将重用相同上下文

ssm49v7z

ssm49v7z2#

可能不是最干净的解决方案,但这个效果很好。
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)
        }
    }
}

1.创建另一个 thin Sping 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 {}
        }
    }
}

1.最后,添加正常的Sping 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"
        }
    }
}

使用此方法时,有几点需要注意/改进:
1.它要求团队在代码库维护方面有良好的纪律;在哪里放置集成测试、Spring配置、bean等。您很容易得到一个包含不需要的bean的混乱的上下文。
1.如何处理环境、配置文件和属性并不简单。
1.访问在主应用程序上下文中创建的bean是一个挑战。(例如,访问JDBC数据源bean。)
1.如何处理共享资源(例如端口)是一个(不太难)的问题。
1.对Gradle Continues Build的支持需要在构建脚本中进行一些配置。
我已经创建了一个示例项目here作为概念验证。
(The事实上,没有人处理这个问题,这是令人难以置信的。期待官方和/或更好的解决方案)

相关问题