@SpringBootTest + @BeforeAll

2022-09-04 04:50:07

我有一个小型的弹簧启动应用程序,其中包含数据库和rabbymq用法。所以我想用集成测试(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();
}

问题是我的 Web 应用在 @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 应用在后进程测试实例阶段启动,并在“全部”之前@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 点。有“准备”的执行,然后是“之前”。

我不确定是 junit,SpringExtension 还是我做错了什么。有什么建议吗?

朱尼特-木星: 5.0.1

弹簧测试: 5.0.0.发布

弹簧启动测试:1.5.8.发布


答案 1

Checkout https://www.testcontainers.org/ 它提供了与JUnit的集成,以启动RabbitMQ和docker容器中的数据库,作为JUnit测试的一部分。这使得集成测试非常逼真,因为您使用的数据库和消息队列版本与生产中使用的数据库和消息队列版本相同。


答案 2

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


推荐