如何在@SpringBootTest 之前添加设置并且只运行一次?

Posted

技术标签:

【中文标题】如何在@SpringBootTest 之前添加设置并且只运行一次?【英文标题】:How add setup before @SpringBootTest and only run once? 【发布时间】:2019-05-09 13:35:58 【问题描述】:

我有一个 docker DB 设置方法,目前位于@BeforeAll。 目前,构造如下

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public DockerConstructorTest
  @BeforeAll
  public static void setup()
    ...
    CreateContainer
    ...
  

  @AfterAll
  public static void done()
    ...
    Stop & Remove Container
    ...
  

有多个测试类都扩展了这个Test超类,每个测试类将构建一个容器并在完成后将其删除。因此,maven 管理 docker 会耗费大量时间。 (创建和删除)

我的问题是whether there's better way to deal with it

我可能想要实现的理想情况是,这个容器的创建和删除只在@SpringBootTest 启动之前运行一次,它将与所有测试类共享。同时,它也不会阻止其他开发者为某些角落场景创建新的容器。

我有一些不完整的想法:

    在 SpringBoot 主类中添加 Constructor 触发器,如果​​它已启动 通过测试,运行 Docker 容器构造函数。但这也意味着我 在 Main Class 中添加一些测试相关的代码,使它们耦合。 个人讨厌这种情况发生 覆盖 SpringBootTest。压倒一切让我觉得我是否应该这样做。

请分享您的绝妙想法,如果可以的话,我将不胜感激 将解决这个问题,或这个问题的一部分。

【问题讨论】:

【参考方案1】:

您应该在静态上下文中实例化容器。比如:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public DockerConstructorTest
    static PostgreSQLContainer<?> postgreSQLContainer =
      new PostgreSQLContainer<>(DockerImageName.parse("postgres:latest"))
          .withDatabaseName("db")
          .withUsername("postgres")
          .withPassword("postgres");

    static 
      postgreSQLContainer.start();
    

这样,所有扩展此类的类都不必重新创建容器。

【讨论】:

【参考方案2】:

不确定您的具体情况,但是,我建议您将 TestContainers 与 Spring Boot 一起使用,有许多可配置的容器可以开箱即用。此外,它们解决了您的问题,您可以拥有 Singleton 容器。 https://github.com/testcontainers/testcontainers-spring-boot

这里有一些关于如何将它用于多个类(单例容器)的参考, https://www.testcontainers.org/test_framework_integration/manual_lifecycle_control/

在我们的用例中,我们使用 Spock/Groovy 和 TestContainers,我们的基类大致如下所示。

@SpringBootTest(classes = DonkeyApplication.class)
class AbstractSpringSpec extends Specification 
    @Shared
    Closure cleanupClosure
    @Shared
    boolean setupSpecDone = false

    def setup() 
        if (!setupSpecDone) 
            setupSpecWithSpring()
            setupSpecDone = true
        
        cleanupClosure = this.&cleanupSpecWithSpring
    

    def cleanupSpec() 
        cleanupClosure?.run()
    

    def setupSpecWithSpring() 
        // override this if Spring Beans are needed in setupSpec
    

    def cleanupSpecWithSpring() 
        // override this if Spring Beans are needed in cleanupSpec
    

referance

小参考一下 spock 在清理或设置方面所做的事情:

希望这个乱七八糟的答案能给你的问题一些答案!

【讨论】:

【参考方案3】:

如果使用 JUnit 5,请查看以下答案(可能使用自定义扩展,JUnit 团队稍后会提供一流的支持)

https://***.com/a/51556718/6365858 https://***.com/a/50565085/6365858

【讨论】:

以上是关于如何在@SpringBootTest 之前添加设置并且只运行一次?的主要内容,如果未能解决你的问题,请参考以下文章

在 springboottest 中从默认 applicaton.yml 设置 testcontainer 属性的更好方法

如何让 WebTestClient 注销所有请求 [重复]

SpringBootTest - 如何在测试级别断言上下文不加载和更改属性?

使用@SpringBootTest时如何在测试类中自动装配bean

Kotlin - 如何在 springBootTest 中管理 @BeforeClass 静态方法

如何在 SpringBootTest 中的 @DataJpaTest 中导入配置类?