在 JUnit 5 中,如何在所有测试之前运行代码

2022-08-31 10:06:35

该批注将方法标记为在中的所有测试之前运行。@BeforeAll

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

但是,有没有办法在所有类中的所有测试之前运行一些代码?

我想确保测试使用一组特定的数据库连接,并且在运行任何测试之前必须对这些连接进行全局一次性设置。


答案 1

现在,通过创建自定义扩展,可以在 JUnit5 中实现这一点,从中可以在根测试上下文中注册关闭挂钩。

您的扩展将如下所示;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;

public class YourExtension implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {

    private static boolean started = false;

    @Override
    public void beforeAll(ExtensionContext context) {
        if (!started) {
            started = true;
            // Your "before all tests" startup logic goes here
            // The following line registers a callback hook when the root test context is shut down
            context.getRoot().getStore(GLOBAL).put("any unique name", this);
        }
    }

    @Override
    public void close() {
        // Your "after all tests" logic goes here
    }
}

然后,任何需要至少执行一次的测试类都可以使用以下内容进行注释:

@ExtendWith({YourExtension.class})

在多个类上使用此扩展时,启动和关闭逻辑将仅调用一次。


答案 2

来自@Philipp Gayret已经提供的答案在并行测试JUnit时存在一些问题(即)。junit.jupiter.execution.parallel.enabled = true

因此,我将解决方案调整为:

import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.ExtensionContext;

public class BeforeAllTestsExtension extends BasicTestClass
        implements BeforeAllCallback, ExtensionContext.Store.CloseableResource {

    /** Gate keeper to prevent multiple Threads within the same routine */
    private static final Lock LOCK = new ReentrantLock();
    /** volatile boolean to tell other threads, when unblocked, whether they should try attempt start-up.  Alternatively, could use AtomicBoolean. */
    private static volatile boolean started = false;
    
    @Override
    public void beforeAll(final ExtensionContext context) throws Exception {
        // lock the access so only one Thread has access to it
        LOCK.lock();
        try {
            if (!started) {
                started = true;
                // Your "before all tests" startup logic goes here
                // The following line registers a callback hook when the root test context is
                // shut down
                context.getRoot().getStore(GLOBAL).put("any unique name", this);

                // do your work - which might take some time - 
                // or just uses more time than the simple check of a boolean
            }
        finally {
            // free the access
            LOCK.unlock();
        }
    }

    @Override
    public void close() {
        // Your "after all tests" logic goes here
    }
}

如下所述,JUnit5 提供了自动扩展注册。为此,请在名为 的目录中添加一个,并添加一个名为 的文件。将类的完全分类名称添加到此文件中,例如src/test/resources//META-INF/servicesorg.junit.jupiter.api.extension.Extension

at.myPackage.BeforeAllTestsExtension

接下来在同一 Junit 配置文件中启用

junit.jupiter.extensions.autodetection.enabled=true

这样,扩展将自动附加到所有测试中。


推荐