JUnit 5 provides lifecycle annotation, allowing us to define setup and teardown methods for the tests. These methods are executed at specific points during the test execution process.
Followings are the primary lifecycle annotations in JUnit 5:
@BeforeAll
- This declares the annotated method should be executed before all tests in the current test class.
- These methods must have a void return type, must not be private, and must be static.
- These methods serve the purpose of executing a specific setup logic only once before all test methods in a given test class are executed.
- These methods are useful for initializing static resources which would, otherwise, be expensive to create during each test invocation
- In JUnit 4, the equivalent of
@BeforeAll is @BeforeClass.
@AfterAll
- Similar to @BeforeClass but is called at the very end of all test/other lifecycle methods.
- @AfterAll methods must have a void return type, must not be private, and must be static
- It is called only once
- Useful for static resource clean up.
- In JUnit 4, the equivalent of
@AfterAll is @AfterClass .
@BeforeEach
- This method runs before each @Test annotated method.
- This method must have a void return type, must not be private, and must not be static.
- Used to setup instance variables/resources which can be used during a test method execution. Useful to avoid code duplication.
- In JUnit 4, the equivalent of
@BeforeEach is @Before.
@AfterEach
- This method runs after each @Test annotated method.
- This method must have a void return type, must not be private, and must not be static.
- Useful for cleaning up instance resources.
- In JUnit 4, the equivalent of
@AfterEach is @After.
Example
pom.xml
pom.xml<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>6.0.1</version>
</dependency>
A class to be tested
package com.logicbig.example;
public class Calc {
public Calc() {
System.out.println("Initializing Calc "+this);
}
public int multiply(int a, int b) {
return a * b;
}
public int divide(int a, int b) {
return a / b;
}
public int add(int a, int b) {
return a + b;
}
public void dispose() {
System.out.println("disposing Calc "+this);
}
}
A test helper
We are creating this class to be initialized in @BeforeAll and dispose in @AfterAll methods. A single instance of it will live during execution of all tests.
package com.logicbig.util;
public class TestPrinter {
public TestPrinter() {
System.out.println("Initializing TestPrinter "+this);
}
public static void print(String msg) {
System.out.println(msg);
}
public void dispose() {
System.out.println("disposing TestPrinter "+this);
}
}
CalcTest
Test class which has some @Test and life cycle methods.
package com.logicbig.example;
import com.logicbig.util.TestPrinter;
import org.junit.jupiter.api.*;
class CalcTest {
private Calc calc;
private static TestPrinter testPrinter;
@BeforeAll
static void initForAll() {
testPrinter.print("-- running @BeforeAll --");
testPrinter = new TestPrinter();
testPrinter.print("------------");
}
@BeforeEach
void init() {
testPrinter.print("-- running @BeforeEach --");
calc = new Calc();
}
@Test
public void testMultiply() {
testPrinter.print("-- running @Test multiply --");
testPrinter.print("calc instance: " + calc);
int i = calc.multiply(3, 5);
Assertions.assertEquals(15, i);
}
@Test
public void testDivide() {
testPrinter.print("-- running @Test divide --");
testPrinter.print("calc instance: " + calc);
int i = calc.divide(255, 5);
Assertions.assertEquals(51, i);
}
@Test
public void testAdd() {
testPrinter.print("-- running @Test add --");
testPrinter.print("calc instance: " + calc);
int i = calc.add(6, 5);
Assertions.assertEquals(11, i);
}
@AfterEach
void afterEachTest(){
testPrinter.print("-- running @AfterEach --");
calc.dispose();
testPrinter.print("-------------");
}
@AfterAll
static void afterAll() {
testPrinter.print("-- running @AfterAll --");
testPrinter.dispose();
}
}
mvn test -Dtest=CalcTest OutputD:\example-projects\junit-5\junit-5-life-cycle-methods>mvn test -Dtest=CalcTest [INFO] Scanning for projects... [INFO] [INFO] ----------< com.logicbig.example:junit-5-life-cycle-methods >----------- [INFO] Building junit-5-life-cycle-methods 1.0-SNAPSHOT [INFO] from pom.xml [INFO] --------------------------------[ jar ]--------------------------------- [INFO] [INFO] --- resources:3.3.1:resources (default-resources) @ junit-5-life-cycle-methods --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-life-cycle-methods\src\main\resources [INFO] [INFO] --- compiler:3.3:compile (default-compile) @ junit-5-life-cycle-methods --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- resources:3.3.1:testResources (default-testResources) @ junit-5-life-cycle-methods --- [WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent! [INFO] skip non existing resourceDirectory D:\example-projects\junit-5\junit-5-life-cycle-methods\src\test\resources [INFO] [INFO] --- compiler:3.3:testCompile (default-testCompile) @ junit-5-life-cycle-methods --- [INFO] Nothing to compile - all classes are up to date [INFO] [INFO] --- surefire:3.2.5:test (default-test) @ junit-5-life-cycle-methods --- [INFO] Using auto detected provider org.apache.maven.surefire.junitplatform.JUnitPlatformProvider [INFO] [INFO] ------------------------------------------------------- [INFO] T E S T S [INFO] ------------------------------------------------------- [INFO] Running com.logicbig.example.CalcTest -- running @BeforeAll -- Initializing TestPrinter com.logicbig.util.TestPrinter@369f73a2 ------------ -- running @BeforeEach -- Initializing Calc com.logicbig.example.Calc@35d176f7 -- running @Test add -- calc instance: com.logicbig.example.Calc@35d176f7 -- running @AfterEach -- disposing Calc com.logicbig.example.Calc@35d176f7 ------------- -- running @BeforeEach -- Initializing Calc com.logicbig.example.Calc@7d0587f1 -- running @Test divide -- calc instance: com.logicbig.example.Calc@7d0587f1 -- running @AfterEach -- disposing Calc com.logicbig.example.Calc@7d0587f1 ------------- -- running @BeforeEach -- Initializing Calc com.logicbig.example.Calc@5d76b067 -- running @Test multiply -- calc instance: com.logicbig.example.Calc@5d76b067 -- running @AfterEach -- disposing Calc com.logicbig.example.Calc@5d76b067 ------------- -- running @AfterAll -- disposing TestPrinter com.logicbig.util.TestPrinter@369f73a2 [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.078 s -- in com.logicbig.example.CalcTest [INFO] [INFO] Results: [INFO] [INFO] Tests run: 3, Failures: 0, Errors: 0, Skipped: 0 [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 7.376 s [INFO] Finished at: 2025-11-29T09:05:51+08:00 [INFO] ------------------------------------------------------------------------
As seen in above output, @BeforeAll/@AfterAll methods are called only once. @BeforeEach/@AfterEach are call before/after each 3 test executions.
Example ProjectDependencies and Technologies Used: - junit-jupiter-engine 6.0.1 (Module "junit-jupiter-engine" of JUnit)
Version Compatibility: 5.0.0 - 6.0.1 Version compatibilities of junit-jupiter-engine with this example:
- 5.0.0
- 5.0.1
- 5.0.2
- 5.0.3
- 5.1.0
- 5.1.1
- 5.2.0
- 5.3.0
- 5.3.1
- 5.3.2
- 5.4.0
- 5.4.1
- 5.4.2
- 5.5.0
- 5.5.1
- 5.5.2
- 5.6.0
- 5.6.1
- 5.6.2
- 5.6.3
- 5.7.0
- 5.7.1
- 5.7.2
- 5.8.0
- 5.8.1
- 5.8.2
- 5.9.0
- 5.9.1
- 5.9.2
- 5.9.3
- 5.10.0
- 5.10.1
- 5.10.2
- 5.10.3
- 5.10.4
- 5.10.5
- 5.11.0
- 5.11.1
- 5.11.2
- 5.11.3
- 5.11.4
- 5.12.0
- 5.12.1
- 5.12.2
- 5.13.0
- 5.13.1
- 5.13.2
- 5.13.3
- 5.13.4
- 5.14.0
- 5.14.1
- 6.0.0
- 6.0.1
Versions in green have been tested.
- JDK 25
- Maven 3.9.11
|
|