In JUnit 5, the @BeforeAll and @AfterAll annotations allow setup and operations to be performed once before and after all test methods are executed in a test class. This is especially useful when handling expensive resources or operations that need not be repeated for each test.
Traditionally, methods annotated with @BeforeAll and @AfterAll need to be static. JUnit 5 introduced a way to use non-static methods for these annotations by using @TestInstance(Lifecycle.PER_CLASS). In this article, we will discuss the @BeforeAll and @AfterAll annotations in Non-Static Methods.
@BeforeAll Annotation
The @BeforeAll annotation marks a method to be run before any of the test methods in the test class. This method is executed only once per test class and is typically used for initializing shared resources or performing expensive setup logic that would otherwise need to be repeated for each test.
Non-Static @BeforeAll Method Example
In JUnit 5, if you use @TestInstance(TestInstance.Lifecycle.PER_CLASS), you can have non-static @BeforeAll methods. Here's how this works:
import org.junit.jupiter.api.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BeforeAllExampleTest {
private int resource;
// Non-static @BeforeAll method
@BeforeAll
void initAll() {
resource = 0; // Initializing shared resource
System.out.println("Before all tests: resource initialized to 0");
}
// Test method 1
@Test
void test1() {
resource += 5;
System.out.println("Test 1 executed, resource: " + resource);
}
// Test method 2
@Test
void test2() {
resource += 10;
System.out.println("Test 2 executed, resource: " + resource);
}
// Test method 3
@Test
void test3() {
resource += 15;
System.out.println("Test 3 executed, resource: " + resource);
}
}
Explanation:
@TestInstance(TestInstance.Lifecycle.PER_CLASS): This annotation tells JUnit to create only one instance of the test class, so all test methods can share the same instance and its state. This is crucial for using non-static@BeforeAllmethods.- Non-static
@BeforeAllmethod: TheinitAllmethod runs before any test and initializes a sharedresource. Since the test class has a single instance, this value can be used and modified across tests. - Shared resource across tests: Each test method modifies the shared
resourceinitialized in the@BeforeAllmethod.
@AfterAll Annotation
The @AfterAll annotation marks a method to be executed once after all test methods in the current test class have run. It is typically used for cleanup tasks, such as releasing resources that were initialized in @BeforeAll or resetting states.
Non-Static @AfterAll Method Example
Here is an example of using a non-static @AfterAll method:
import org.junit.jupiter.api.*;
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class AfterAllExampleTest {
private int resource;
// This method runs before all the tests
@BeforeAll
void setUp() {
resource = 0; // Initializing resource
System.out.println("Setup completed: resource initialized to 0");
}
// Test method 1
@Test
void test1() {
resource += 10;
System.out.println("Test 1 executed, resource: " + resource);
}
// Test method 2
@Test
void test2() {
resource += 20;
System.out.println("Test 2 executed, resource: " + resource);
}
// @AfterAll method that runs once after all tests
@AfterAll
void tearDown() {
System.out.println("All tests completed. Cleaning up resources...");
resource = 0; // Resetting the resource
System.out.println("Resource reset to " + resource);
}
}
Explanation:
- Non-static
@AfterAllmethod: ThetearDownmethod is run once after all the test methods have executed. It performs cleanup by resetting the sharedresource. - Shared resource cleanup: Since the resource is shared across tests, the
@AfterAllmethod can reset or clean up the resource to maintain consistency.
Difference between @BeforeAll and @AfterAll
@BeforeAll | @AfterAll |
|---|---|
@BeforeAll indicates that the annotated method should run before all tests in the current test class. | @AfterAll is the method to be invoked after the completion of all tests in the current test class. |
It can handle instance variables too. Methods can not be called directly. | Accessing methods as well as instance variables is possible here. |
An instance is created every time for a test method in JUnit | Generation of only one instance is possible for all test methods. |
An exception is thrown in BeforeAll if the method is not static (without @TestInstance). | No exception is thrown in AfterAll with @TestInstance(Lifecycle.PER_CLASS). |
Key Points:
- Static Requirement: By default,
@BeforeAlland@AfterAllmust be static because JUnit creates a new instance of the test class for each test method. Using@TestInstance(Lifecycle.PER_CLASS)allows these methods to be non-static by ensuring that a single instance of the test class is used. - Efficiency: The
@BeforeAlland@AfterAllannotations optimize test execution by reducing setup and teardown overhead. This is especially useful for resource-heavy operations that don't need to be repeated for each test.
Conclusion
In this article, we explored how to use @BeforeAll and @AfterAll in non-static methods in JUnit 5. Normally, these methods need to be static, but by using @TestInstance(Lifecycle.PER_CLASS), you can make them non-static and reuse a single instance of the test class for all test methods. This is beneficial when you need to set up and tear down resources shared across tests, improving both test performance and code maintainability.