I am looking to migrate a JUnit 4 test suite to JUnit 5. The JUnit 4 test suite currently looks something like this:
@RunWith(Suite.class)
@SuiteClasses({FirstTest.class, SecondTest.class})
public class JUnit4Suite {
@ClassRule
public static JUnit4Server MY_SERVER = new JUnit4Server();
}
where MY_SERVER
is an ExternalResource
that all the tests in the suite use, to, say publish something (JUnit4Suite.MY_SERVER.publish(...)
):
public class JUnit4Server extends ExternalResource {
@Override
protected final void before() throws Throwable {
// start the server
}
@Override
protected final void after() {
// stop the server
}
}
The server needs to be initialized only once, at the start of the suite run, before any test runs, and stopped once all tests have finished executing. This currently works fine.
Using JUnit 5, I am coming up with something like this:
@Suite
@SelectClasses({FirstTest.class, SecondTest.class})
public class JUnit5Suite {
@RegisterExtension
public static JUnit5Server MY_SERVER = new JUnit5Server();
}
where MY_SERVER
now looks like this:
public class JUnit5Server implements BeforeAllCallback, AfterAllCallback {
@Override
public void beforeAll(ExtensionContext context) throws Exception {
...
}
}
However, when I run the JUnit5Suite
, the server instance gets created fine, however the beforeAll
method in the server does not get executed. Is there something missing?
According to javadoc
@BeforeAll is used to signal that the annotated method should be executed before all tests in the current test class. In contrast to @BeforeEach methods, @BeforeAll methods are only executed once for a given test class.
Because a test suite probably contains multiple test classes, it's reasonable to change callbacks' behaviour from test class level to test suite level.
Fortunately, JUnit Platform Suite API 1.11 introduced @BeforeSuite
and @AfterSuite
annotations.
@BeforeSuite is used to signal that the annotated method should be executed before all tests in the current test suite.
and
@AfterSuite is used to signal that the annotated method should be executed after all tests in the current test suite.
With this soulion the server will start before (and will stop after) all tests in the current test suite.
@Suite
@SelectClasses({FirstTest.class, SecondTest.class})
public class SampleSuite {
static SampleServer server = new SampleServer();
@BeforeSuite
static void beforeSuite() {
System.out.println("Before Suite");
server.start();
}
@AfterSuite
static void afterSuite() {
server.shutdown();
System.out.println("After Suite");
}
}
public class SampleServer {
public void start() {
System.out.println("Starting SampleServer");
}
public void shutdown() {
System.out.println("SampleServer shutdown");
}
}
After running mvn clean test
command the output should be like this:
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running io.github.zforgo.jupiter.SampleSuite
Before Suite
Starting SampleServer
[INFO] Running io.github.zforgo.jupiter.FirstTest
FirstTest.bar
FirstTest.foo
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.050 s -- in io.github.zforgo.jupiter.FirstTest
[INFO] Running io.github.zforgo.jupiter.SecondTest
SecondTest.bar
SecondTest.foo
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.007 s -- in io.github.zforgo.jupiter.SecondTest
SampleServer shutdown
After Suite
[INFO] Tests run: 0, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.122 s -- in io.github.zforgo.jupiter.SampleSuite