如何使用Spring与动态数据库端口并行运行集成测试

时间:2017-06-06 14:35:56

标签: spring redis integration-testing junit4 parallel-testing

描述

我们的应用程序越来越多,其中涉及到与redis数据库连接的众多集成测试。由于数量不断增加,我们希望至少在课堂级别对它们进行并行化。 到目前为止,我们已经按顺序运行所有测试,并在静态com.github.kstyrc embedded-redis 0.6 / @BefroreClass方法(jUnit 4)中启动(停止)嵌入式redis数据库(@AfterClass)。 数据库的端口始终相同 - 9736。对于我们的jedis连接池,这也在application.properties via spring.redis.port=9736中设置。 为了使并行化工作,我们必须动态获取端口,并将其通告给连接工厂以进行连接池。 这个问题我在一段时间后通过在配置中实现BeanPostProcessor得到了解决。我剩下的问题是正确拦截bean生命周期和Web应用程序上下文。

代码片段并行测试

application.properties

...
spring.redis.port=${random.int[4000,5000]}
...

BeanPostProcessor实施配置

@Configuration
public class TestConfig implements BeanPostProcessor {

    private RedisServer redisServer;

    private int redisPort;

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (JedisConnectionFactory.class.equals(bean.getClass())) {
            redisPort = ((JedisConnectionFactory) bean).getPort();
            redisServer().start();
        }
        return bean;
    }

    @Bean(destroyMethod = "stop")
    public RedisServer redisServer() {
        redisServer = RedisServer.builder().port(redisPort).build();
        return redisServer;
    }
}

使用动态端口

进行并行测试的启动和关闭
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class OfferControllerTest {

    private MockMvc mockMvc;

    @Inject
    protected WebApplicationContext wac;
...
    @Before
    public void setup() throws Exception {
        this.mockMvc = webAppContextSetup(this.wac).apply(springSecurity()).build();
    }

    @After
    public void tearDown() throws Exception {
        offerRepository.deleteAll();
    }
...

通过maven-surefire-plugin 2.18.1

实现测试并行化
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>2.18.1</version>
    <configuration>
        <parallel>classes</parallel>
        <threadCount>4</threadCount>
    </configuration>
</plugin>

补编

在spring bean初始化阶段,我们的TestConfig挂钩到JedisConnectionFactory bean的生命周期,并在启动连接池之前通过spring.redis.port=${random.int[4000,5000]}在随机选择的端口上启动redis服务器。由于redisServer本身是一个bean,我们使用destroyMethod来停止服务器上的bean销毁,因此将其留给应用程序上下文生命周期。 从静态端口到动态端口,从顺序到并行的转换进展顺利。

问题

但是当我并行运行测试时,我会得到如下错误:
java.lang.IllegalStateException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@22b19d79 has been closed already

@Before
public void setup() throws Exception {
    this.mockMvc = webAppContextSetup(this.wac).apply(springSecurity()).build();
}


org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'spring.redis-org.springframework.boot.autoconfigure.data.redis.RedisProperties': Initialization of bean failed; nested exception is java.lang.IllegalStateException: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@22b19d79 has been closed already

@After
public void tearDown() throws Exception {
    offerRepository.deleteAll();
}

帮助

我不确定这个问题。也许我们可以省略对offerRepository.deleteAll()的tearDown调用 因为@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
但是设置webAppContextSetup(this.wac).apply(springSecurity()).build()的错误仍然存​​在。

并行运行时应用程序上下文是否被搞砸了?为什么设置中的应用程序上下文已经关闭? 我们选择了错误的方法(错误的模式)吗?如果是这样,我们应该改变什么?

0 个答案:

没有答案