Java @SpringBootTest+@以前

Java @SpringBootTest+@以前,java,spring,spring-boot,spring-test,junit5,Java,Spring,Spring Boot,Spring Test,Junit5,我有一个带有数据库和rabbitmq用法的小型spring启动应用程序。 所以我想用集成测试(H2+apacheqpid)进行测试 正如我的应用程序所期望的,数据库和mq Im使用@BeforeAll启动它: @BeforeAll public void before() { startMessageBroker(); startDatabase(); } 问题是我的web应用程序在@BeforeAll中定义的database/mq之前启动 org.springframewor

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

正如我的应用程序所期望的,数据库和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应用程序在postProcessTestInstance阶段启动,在BeforeAll中启动@BeforeAll方法

org.junit.platform.engine.support.hierarchy.hierarchycalTestExecutor:

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);
}
private void execute(TestDescriptor TestDescriptor、C parentContext、ExecutionTracker跟踪程序){
Node=asNode(testDescriptor);
markExecuted(testDescriptor);
C准备上下文;
试一试{
preparedContext=node.prepare(parentContext);//1{
C context=preparedContext;
试一试{
context=node.before(context);//2!tracker.wasAlreadyExecuted(子)
.forEach(child->execute(child、contextForStaticChildren、tracker));
//@formatter:on
}
最后{
node.after(上下文);
}
});
this.listener.executionFinished(testDescriptor,result);
}
参见第1点和第2点。执行“准备”和“之前”

我不确定是junit、SpringExtension的问题还是我做错了什么。 有什么建议吗

junit jupiter:5.0.1

弹簧试验:5.0.0.0释放

弹簧启动测试:1.5.8.1释放


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

@在静态方法中应使用BeforeAll

更多阅读:


  • 我认为这是设计上的。尝试将Bean后处理器/上下文初始值设定项添加到init/start-your-DB/rabbitMQ..

    是否有任何理由在测试类中启动DB和message broker?在我看来,这是设计上的错误。它们都应该与应用程序上下文一起启动,因为它们是基础结构的一部分e

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

    IMHO,一个更好的做事方式是:

    • 在maven+中将H2依赖项与
      测试
      作用域一起使用,以在应用程序上下文启动时启动H2的方式配置启动器
    • 在应用程序启动时启动apache qpid(最好是嵌入式的)
    • 在@Before中,只需确保在运行测试用例之前清理好内容

    签出它提供了与JUnit的集成,以在docker容器中启动RabbitMQ和数据库,作为JUnit测试的一部分。这使得集成测试非常现实,因为您在生产中使用的数据库和消息队列版本相同。

    如果依赖于当SpringExtension创建应用程序上下文时,您最好实现一个Spring。是的,它应该是。很好的一点。在fast中,有静态和无静态的执行流没有任何区别:@BeforeAll方法在两种情况下都是在web应用程序启动后执行的。我也可以从他们刚刚寻找的junit源代码中看到这一点带注释的方法。请参阅:第337行。我有H2和测试范围。我有嵌入的Qpid。有什么建议如何在spring启动之前启动H2/Qpid吗?我本来应该使用BeforeAll,但看起来这种情况不起作用。使用后处理器/上下文事件不是一种方法,因为带有ConnectionFactory的Bean已经开始初始化。我尝试了o玩懒惰但没有运气。因此,如果你有一些真实的例子,请与我分享。是的,最简单的方法是添加@Order,另一种方法是使用初学者。对于qpid,你可以使用(如果你对第三方库没有任何限制).对于H2,你可以从这里开始。问题是,初学者总是在你的豆子之前开始,这就是你想要的。
    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);
    }