In this quick guide, we discuss Junit 5 @TestInstance annotation and examples on how to change test instance lifecycle behaviour using @TestInstance.
1. Junit 5 test instance lifecycle
JUnit creates a new instance of each test class before executing each test method. The default behaviour of Junit 5 test instance lifecycle is “per-method”. This can be changed using @TestInstance annotation. Junit 5 supports two instance lifecycle modes.
- Lifecycle per-method.
- Lifecycle per-class.
You can set the instance lifecycle mode for the tests by annotating with @TestInstance
annotation to the test class.
2. Lifecycle per-method mode
This is default behavior for all versions of Junit. When using this mode, a new test instance will be created for each test method, test factory method, or test template method. Example using @TestInstance(Lifecycle.PER_METHOD)
@TestInstance(Lifecycle.PER_METHOD) public class MathUtilTest { private int result = 5; @Test void test_Add() { result = MathUtil.add(result, 5); System.out.println("test_Add(5,5) => "+result); assertEquals(10, result); } @Test void test_Multiply() { result = MathUtil.multiple(result, 5); System.out.println("test_Multiply(5,5) => "+result); assertEquals(25, result); } @Test void test_Devide() { result = MathUtil.devide(result, 5); System.out.println("test_Devide(5,5) => "+result); assertEquals(1, result); } }
Output :
test_Devide(5,5) => 1 test_Add(5,5) => 10 test_Multiply(5,5) => 25
3. Lifecycle per-class mode
3.1. When using this mode, a new test instance will be created once per test class. In this mode shared test instance state between test methods in a given test class as well as between non-static @BeforeAll
and @AfterAll
Example using @TestInstance(Lifecycle.PER_CLASS)
@TestInstance(Lifecycle.PER_CLASS) public class MathUtilTest { private int result = 5; @Test void test_Add() { result = MathUtil.add(result, 5); System.out.println("test_Add(5,5) => "+result); assertEquals(10, result); } @Test void test_Multiply() { result = MathUtil.multiple(result, 5); System.out.println("test_Multiply(5,5) => "+result); assertEquals(25, result); } @Test void test_Devide() { result = MathUtil.devide(result, 5); System.out.println("test_Devide(5,5) => "+result); assertEquals(1, result); } }
Output :
test_Devide(5,5) => 1 test_Add(5,5) => 6 test_Multiply(5,5) => 30
3.2. The Default mode of test instance lifecycle is PER_METHOD
, if you are not set test instance lifecycle mode as Lifecycle.PER_CLASS
, @BeforeAll
and @AfterAll
call back methods should be static, otherwise you will get compile time error. If your lifecycle mode is Lifecycle.PER_CLASS
you can make @BeforeAll
and @AfterAll
methods as non-static.
Test @BeforeAll
and @AfterAll
methods must be static unless the test class is annotated with @Testinstance(Lifecycle.PER_CLASS)
@TestInstance(Lifecycle.PER_CLASS) public class Junit5_TestInstance_Lifecycle_Test { @BeforeAll void beforeAll() { // here common setup for all tests System.out.println("--- Before starting tests --- "); } @BeforeEach void beforeEach(TestInfo testInfo) { // here initialize setup for each test System.out.println("Before Strat test >>>> "+testInfo.getTestMethod().get().getName()); } @Test void test_Add() { System.out.println("MathUtil.add(5, 5) => "+MathUtil.add(5, 5)); assertEquals(10, MathUtil.add(5, 5)); } @Test void test_Multiply() { System.out.println("MathUtil.multiple(5, 5) => "+MathUtil.multiple(5, 5)); assertEquals(25, MathUtil.multiple(5, 5)); } @AfterEach void afetrEach(TestInfo testInfo) { // here cleanup setup after each test completes System.out.println("After complete test >>>> "+testInfo.getTestMethod().get().getName()); } @AfterAll void afetrAll() { // here cleanup setup after all tests completes System.out.println("--- After tests completed ---"); } }
Output :
--- Before starting tests --- Before Strat test >>>> test_Add MathUtil.add(5, 5) => 10 After complete test >>>> test_Add Before Strat test >>>> test_Multiply MathUtil.multiple(5, 5) => 25 After complete test >>>> test_Multiply --- After tests completed ---
3.3. By default Junit 5 nested test classes not allow to write @BeforeAll
and @AfterAll
methods, you can write them in nested classes only if test lifecycle mode is Lifecycle.PER_CLASS
and they should be non-static.
public class Junit5_NestedTests_Test { @Test void test1() { System.out.println("=> test1()"); } @Nested @TestInstance(Lifecycle.PER_CLASS) class TestA { @BeforeAll void testA_BeforeAll() { System.out.println("=> testA_BeforeAll()"); } @Test void testA_test1() { System.out.println("=> testA_test1()"); } } }
Output :
=> test1() => testA_BeforeAll() => testA_test1()
3.4. You can declare @BeforeAll
and @AfterAll
on interface methods.
@TestInstance(Lifecycle.PER_CLASS) public interface IBaseTest { @BeforeAll default void beforeAll() { // here common setup for all tests System.out.println("--- Before starting tests --- "); } @AfterAll default void afetrAll() { // here cleanup setup after all tests completes System.out.println("--- After tests completed ---"); } }
public class IntsanceLifecycleTest implements IBaseTest { private int result = 5; @Test void test_Add() { result = MathUtil.add(result, 5); System.out.println("test_Add(5,5) => "+result); assertEquals(10, result); } @Test void test_Multiply() { result = MathUtil.multiple(result, 5); System.out.println("test_Multiply(5,5) => "+result); assertEquals(25, result); } @Test void test_Devide() { result = MathUtil.devide(result, 5); System.out.println("test_Devide(5,5) => "+result); assertEquals(1, result); } }
Output :
--- Before starting tests --- test_Devide(5,5) => 1 test_Add(5,5) => 6 test_Multiply(5,5) => 30 --- After tests completed ---
4. Globally change Default Test Instance Lifecycle
To change the default test instance lifecycle mode, set the junit.jupiter.testinstance.lifecycle.default
configuration parameter to the name of an enum constant defined in TestInstance.Lifecycle
, ignoring case.
Create a file named junit-platform.properties
in the root of the class path in src/test/resources
.
-
-Djunit.jupiter.testinstance.lifecycle.default=per_class
– to set test instance lifecycle mode to per_class -
-Djunit.jupiter.testinstance.lifecycle.default=per_method
– to set test instance lifecycle mode to per_method (actually no need to set this, because it’s default behavior)
5. Conclusion
In this article we have covered Junit 5 test instance lifecycle and instance lifecycle modes with several examples.
You also might be interested in following examples:
- Junit 5 Dynamic Tests
- Junit 5 tags and filter tests
- Junit 5 Timeout tests
- Junit 5 ConsoleLauncher examples
- Junit 5 maven example
- Junit 5 Disable tests
- Junit 5 nested tests
- Junit 5 parallel execution