@SpringBootTest + @BeforeAll

时间:2017-10-27 16:26:23

标签: java spring spring-boot spring-test junit5

我有一个带有数据库和rabbitmq用法的小型春季启动应用程序。 所以我想用集成测试(H2 + apache qpid)进行测试。

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = TestSpringConfig.class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)

由于我的应用程序期望数据库和mq Im使用@BeforeAll启动它:

@BeforeAll
public void before() {
    startMessageBroker();
    startDatabase();
}

问题是我的网络应用程序在@BeforeAll中定义的database / mq之前启动。

org.springframework.test.context.junit.jupiter.SpringExtension:

public class SpringExtension implements BeforeAllCallback, AfterAllCallback, TestInstancePostProcessor,
        BeforeEachCallback, AfterEachCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback,
        ParameterResolver {
// ...
    @Override
    public void beforeAll(ExtensionContext context) throws Exception {
        getTestContextManager(context).beforeTestClass();
    }
// ...
    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception {
        getTestContextManager(context).prepareTestInstance(testInstance);
    }
// ...

Web应用程序在postProcessTestInstance阶段启动,而@BeforeAll方法在beforeAll中启动。

org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor:

private void execute(TestDescriptor testDescriptor, C parentContext, ExecutionTracker tracker) {
    Node<C> node = asNode(testDescriptor);
    tracker.markExecuted(testDescriptor);

    C preparedContext;
    try {
        preparedContext = node.prepare(parentContext); // 1 <<<
        SkipResult skipResult = node.shouldBeSkipped(preparedContext);
        if (skipResult.isSkipped()) {
            this.listener.executionSkipped(testDescriptor, skipResult.getReason().orElse("<unknown>"));
            return;
        }
    }
    catch (Throwable throwable) {
        rethrowIfBlacklisted(throwable);
        // We call executionStarted first to comply with the contract of EngineExecutionListener
        this.listener.executionStarted(testDescriptor);
        this.listener.executionFinished(testDescriptor, TestExecutionResult.failed(throwable));
        return;
    }

    this.listener.executionStarted(testDescriptor);

    TestExecutionResult result = singleTestExecutor.executeSafely(() -> {
        C context = preparedContext;
        try {
            context = node.before(context); // 2 <<<

            C contextForDynamicChildren = context;
            context = node.execute(context, dynamicTestDescriptor -> {
                this.listener.dynamicTestRegistered(dynamicTestDescriptor);
                execute(dynamicTestDescriptor, contextForDynamicChildren, tracker);
            });

            C contextForStaticChildren = context;
            // @formatter:off
            testDescriptor.getChildren().stream()
                    .filter(child -> !tracker.wasAlreadyExecuted(child))
                    .forEach(child -> execute(child, contextForStaticChildren, tracker));
            // @formatter:on
        }
        finally {
            node.after(context);
        }
    });

    this.listener.executionFinished(testDescriptor, result);
}

见第1点和第2点。执行&#39;准​​备&#39;然后在&#39;之前。

我不确定junit,SpringExtension或我做错了什么问题。 有什么建议吗?

  

junit-jupiter:5.0.1

     

spring-test:5.0.0.RELEASE

     

spring-boot-test:1.5.8.RELEASE

4 个答案:

答案 0 :(得分:1)

结帐https://www.testcontainers.org/,作为JUnit测试的一部分,它提供了与JUnit的集成以启动RabbitMQ和Docker容器中的数据库。这使集成测试变得更加现实,因为您将在生产环境中使用相同版本的数据库和消息队列。

答案 1 :(得分:0)

我认为这是设计的。尝试添加Bean后处理器/上下文初始化器来初始化/启动DB / rabbitMQ ..

答案 2 :(得分:0)

有没有理由在测试类中启动数据库和消息代理?在我看来,这是错误的设计。它们都应该与您的应用程序上下文一起启动,因为它们是您的基础结构的一部分。

  

设置基础架构不是您的测试责任!

恕我直言,更好的做事方式如下:

  • 在maven中使用H2依赖关系test范围+在应用程序上下文启动时以启动H2的方式配置启动器
  • 在应用程序启动时启动apache qpid(可预先嵌入)
  • 在@Before中,确保在运行测试用例之前清理内容

答案 3 :(得分:-1)

JUnit 5 [@BeforeAll]注释替换了JUnit 4中的@BeforeClass注释。 它用于表示在当前测试类中的所有测试之前应该执行带注释的方法。

@BeforeAll应该在静态方法中使用

更多阅读:

  1. http://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations