In JUnit 5, how to run code before all tests
This is now possible in JUnit5 by creating a custom Extension, from which you can register a shutdown hook on the root test-context.
Your extension would look like this;
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 }}
Then, any tests classes where you need this executed at least once, can be annotated with:
@ExtendWith({YourExtension.class})
When you use this extension on multiple classes, the startup and shutdown logic will only be invoked once.
The already provided answer from @Philipp Gayret has some problems when testing JUnit in parallel (i.e. junit.jupiter.execution.parallel.enabled = true
).
Therefore I adapted the solution to:
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 { private static boolean started = false; // Gate keeper to prevent multiple Threads within the same routine final static Lock lock = new ReentrantLock(); @Override public void beforeAll(final ExtensionContext context) throws Exception { // lock the access so only one Thread has access to it lock.lock(); 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 } // free the access lock.unlock(); } @Override public void close() { // Your "after all tests" logic goes here }}
As mentioned below JUnit5 provides an automatic Extension Registration. To do so add a in src/test/resources/
a directory called /META-INF/services
and add a file named org.junit.jupiter.api.extension.Extension
. Add into this file the fully classified name of your class, e.g.
at.myPackage.BeforeAllTestsExtension
Next enable in the same Junit config file
junit.jupiter.extensions.autodetection.enabled=true
With this the extension is attached automatically to all of your tests.
Extending on suggestion from @Philipp, here's a more complete code snippet:
import static org.junit.jupiter.api.extension.ExtensionContext.Namespace.GLOBAL; import org.junit.jupiter.api.extension.BeforeAllCallback;import org.junit.jupiter.api.extension.ExtensionContext;public abstract class BaseSetupExtension implements BeforeAllCallback, ExtensionContext.Store.CloseableResource { @Override public void beforeAll(ExtensionContext context) throws Exception { // We need to use a unique key here, across all usages of this particular extension. String uniqueKey = this.getClass().getName(); Object value = context.getRoot().getStore(GLOBAL).get(uniqueKey); if (value == null) { // First test container invocation. context.getRoot().getStore(GLOBAL).put(uniqueKey, this); setup(); } } // Callback that is invoked <em>exactly once</em> // before the start of <em>all</em> test containers. abstract void setup(); // Callback that is invoked <em>exactly once</em> // after the end of <em>all</em> test containers. // Inherited from {@code CloseableResource} public abstract void close() throws Throwable;}
How to use:
public class DemoSetupExtension extends BaseSetupExtension { @Override void setup() {} @Override public void close() throws Throwable {}} @ExtendWith(DemoSetupExtension.class)public class TestOne { @BeforeAll public void beforeAllTestOne { ... } @Test public void testOne { ... }}@ExtendWith(DemoSetupExtension.class)public class TestTwo { @BeforeAll public void beforeAllTestTwo { ... } @Test public void testTwo { ... }}
Test execution order will be:
DemoSetupExtension.setup (*) TestOne.beforeAllTestOne TestOne.testOne TestOne.afterAllTestOne TestTwo.beforeAllTestTwo TestTwo.testTwo TestTwo.afterAllTestTwo DemoSetupExtension.close (*)
...this will be true regardless if you choose to run a single @Test (e.g.TestOne.testOne), or an entire test class (TestOne), or multiple / all tests.