Introduction
In this chapter, we will explore the lifecycle annotations in JUnit using a Calculator example. Lifecycle annotations allow you to set up and tear down resources before and after your tests. This helps ensure that your tests run in a clean environment and that any necessary cleanup is performed automatically.
Key Lifecycle Annotations
JUnit provides several lifecycle annotations to manage setup and teardown processes for your tests. Here are the most commonly used lifecycle annotations:
@BeforeEach@AfterEach@BeforeAll@AfterAll
1. @BeforeEach
The @BeforeEach annotation is used to specify a method that should run before each test method. This is typically used to set up test data or initialize resources.
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
private Calculator calculator;
@BeforeEach
public void setup() {
calculator = new Calculator();
}
@Test
public void testAdd() {
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
assertEquals(2, result, "5 - 3 should equal 2");
}
}
2. @AfterEach
The @AfterEach annotation is used to specify a method that should run after each test method. This is typically used to clean up resources or reset states.
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
private Calculator calculator;
@BeforeEach
public void setup() {
calculator = new Calculator();
}
@AfterEach
public void teardown() {
calculator = null; // Clean up resources
}
@Test
public void testAdd() {
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
assertEquals(2, result, "5 - 3 should equal 2");
}
}
3. @BeforeAll
The @BeforeAll annotation is used to specify a method that should run once before all the test methods in the class. This method must be static. It is typically used to set up shared resources that are expensive to create.
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
private static Calculator calculator;
@BeforeAll
public static void setupAll() {
calculator = new Calculator();
}
@BeforeEach
public void setup() {
// No need to initialize calculator here as it's done in @BeforeAll
}
@Test
public void testAdd() {
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
assertEquals(2, result, "5 - 3 should equal 2");
}
}
4. @AfterAll
The @AfterAll annotation is used to specify a method that should run once after all the test methods in the class. This method must be static. It is typically used to clean up shared resources.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
private static Calculator calculator;
@BeforeAll
public static void setupAll() {
calculator = new Calculator();
}
@AfterAll
public static void teardownAll() {
calculator = null; // Clean up resources
}
@BeforeEach
public void setup() {
// No need to initialize calculator here as it's done in @BeforeAll
}
@Test
public void testAdd() {
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
public void testSubtract() {
int result = calculator.subtract(5, 3);
assertEquals(2, result, "5 - 3 should equal 2");
}
}
Demonstrating All Annotations
Here is a complete example that demonstrates the usage of all the lifecycle annotations.
Calculator Class
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int subtract(int a, int b) {
return a - b;
}
}
CalculatorTest Class
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
public class CalculatorTest {
private static Calculator calculator;
@BeforeAll
public static void setupAll() {
System.out.println("BeforeAll: Initialize resources that are shared across all tests");
calculator = new Calculator();
}
@BeforeEach
public void setup() {
System.out.println("BeforeEach: Initialize resources before each test");
// No need to initialize calculator here as it's done in @BeforeAll
}
@Test
public void testAdd() {
System.out.println("Test: testAdd");
int result = calculator.add(2, 3);
assertEquals(5, result, "2 + 3 should equal 5");
}
@Test
public void testSubtract() {
System.out.println("Test: testSubtract");
int result = calculator.subtract(5, 3);
assertEquals(2, result, "5 - 3 should equal 2");
}
@AfterEach
public void teardown() {
System.out.println("AfterEach: Clean up resources after each test");
// Clean up resources if needed
}
@AfterAll
public static void teardownAll() {
System.out.println("AfterAll: Clean up resources that are shared across all tests");
calculator = null;
}
}
Explanation
@BeforeAll: Runs once before all tests. Used to initialize resources that are shared across tests.@BeforeEach: Runs before each test. Used to initialize resources needed for each test.@Test: The actual test methods.@AfterEach: Runs after each test. Used to clean up resources after each test.@AfterAll: Runs once after all tests. Used to clean up resources that are shared across tests.
Running the Tests using IntelliJ IDEA
Now that we have used the lifecycle annotations in our test class, let’s run the tests to ensure everything is working correctly.
- Run Test: Click the green run icon next to the
testAddmethod or theCalculatorTestclass and selectRun. - View Results: The results will be displayed in the Run window. A green check mark indicates the test passed, while a red cross indicates it failed.

Conclusion
Lifecycle annotations in JUnit, such as @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll, are essential for managing setup and teardown processes in your tests. They help ensure that your tests run in a clean environment and that necessary cleanup is performed automatically. By understanding and using these annotations effectively, you can write more organized and maintainable tests for your Java applications.