How do I use @BeforeAll and @AfterAll in JUnit?

In JUnit 5, @BeforeAll and @AfterAll are lifecycle annotations used to run setup and cleanup code once per test class.

They are useful when you need to initialize or clean up expensive shared resources, such as:

  • database connections
  • test containers
  • temporary directories
  • mock servers
  • shared test data
  • application-wide configuration

Basic Rule

By default, methods annotated with @BeforeAll and @AfterAll must be static.

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

class ExampleTest {

    @BeforeAll
    static void setUpBeforeAllTests() {
        System.out.println("Runs once before all tests");
    }

    @AfterAll
    static void cleanUpAfterAllTests() {
        System.out.println("Runs once after all tests");
    }

    @Test
    void firstTest() {
        System.out.println("First test");
    }

    @Test
    void secondTest() {
        System.out.println("Second test");
    }
}

Execution order:

Runs once before all tests
First test
Second test
Runs once after all tests

Compared with @BeforeEach and @AfterEach

@BeforeAll and @AfterAll run once for the whole test class.

@BeforeEach and @AfterEach run before and after every test method.

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;

class LifecycleTest {

    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all tests");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("Before each test");
    }

    @Test
    void testOne() {
        System.out.println("Test one");
    }

    @Test
    void testTwo() {
        System.out.println("Test two");
    }

    @AfterEach
    void afterEach() {
        System.out.println("After each test");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("After all tests");
    }
}

Output will be similar to:

Before all tests
Before each test
Test one
After each test
Before each test
Test two
After each test
After all tests

Practical Example

Suppose several tests need the same expensive resource.

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

class DatabaseConnectionTest {

    private static FakeDatabaseConnection connection;

    @BeforeAll
    static void openConnection() {
        connection = new FakeDatabaseConnection();
        connection.open();
    }

    @AfterAll
    static void closeConnection() {
        connection.close();
    }

    @Test
    void connectionShouldBeOpen() {
        assertTrue(connection.isOpen());
    }

    @Test
    void canExecuteQuery() {
        assertTrue(connection.execute("SELECT 1"));
    }
}

Here:

  • openConnection() runs once before all tests.
  • The same connection is reused by all test methods.
  • closeConnection() runs once after all tests finish.

Using Non-Static @BeforeAll and @AfterAll

If you do not want these methods to be static, annotate the test class with:

@TestInstance(TestInstance.Lifecycle.PER_CLASS)

Example:

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class NonStaticLifecycleTest {

    private String sharedValue;

    @BeforeAll
    void beforeAll() {
        sharedValue = "ready";
    }

    @AfterAll
    void afterAll() {
        sharedValue = null;
    }

    @Test
    void testSharedValue() {
        assert sharedValue.equals("ready");
    }
}

With PER_CLASS, JUnit creates one instance of the test class and reuses it for all test methods. Because of that, @BeforeAll and @AfterAll can be instance methods.

When Should You Use Them?

Use @BeforeAll for setup that should happen once, such as:

@BeforeAll
static void startServer() {
    // start shared server
}

Use @AfterAll for cleanup that should happen once, such as:

@AfterAll
static void stopServer() {
    // stop shared server
}

Avoid using them for the per-test state. For that, prefer @BeforeEach.

Important Best Practices

  • Use @BeforeAll only for shared setup.
  • Use @AfterAll to release resources created in @BeforeAll.
  • Avoid modifying the shared state between tests unless you reset it properly.
  • Prefer @BeforeEach when each test needs a fresh object.
  • By default, make @BeforeAll and @AfterAll methods static.
  • Use @TestInstance(TestInstance.Lifecycle.PER_CLASS) only when you specifically want non-static lifecycle methods.

In short:

Annotation Runs When? Usually Static?
@BeforeAll Once before all tests Yes
@AfterAll Once after all tests Yes
@BeforeEach Before each test method No
@AfterEach After each test method No

How do I use @BeforeEach and @AfterEach in JUnit?

In JUnit 5, @BeforeEach and @AfterEach are lifecycle annotations.

They let you run code before and after every test method.

Annotation When it runs Common use
@BeforeEach Before each @Test method Create objects, initialize test data, reset state
@AfterEach After each @Test method Clean up resources, close files/connections, reset temporary state

Basic Example

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.assertEquals;

class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @AfterEach
    void tearDown() {
        calculator = null;
    }

    @Test
    void addReturnsSumOfTwoNumbers() {
        int result = calculator.add(2, 3);

        assertEquals(5, result);
    }

    @Test
    void subtractReturnsDifferenceOfTwoNumbers() {
        int result = calculator.subtract(10, 4);

        assertEquals(6, result);
    }
}

Here is the execution order:

setUp()
addReturnsSumOfTwoNumbers()
tearDown()

setUp()
subtractReturnsDifferenceOfTwoNumbers()
tearDown()

So each test gets a fresh setup.


What @BeforeEach Is For

Use @BeforeEach when several tests need the same preparation.

For example:

@BeforeEach
void setUp() {
    calculator = new Calculator();
}

This avoids repeating the same setup code in every test:

@Test
void addReturnsSumOfTwoNumbers() {
    calculator = new Calculator();

    assertEquals(5, calculator.add(2, 3));
}

Instead, the test can focus only on the behavior being tested:

@Test
void addReturnsSumOfTwoNumbers() {
    assertEquals(5, calculator.add(2, 3));
}

What @AfterEach Is For

Use @AfterEach when you need cleanup after every test.

Common examples include:

  • Closing files
  • Closing database connections
  • Deleting temporary files
  • Clearing test data
  • Resetting shared state

Example:

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

class ShoppingCartTest {

    private List<String> cart;

    @BeforeEach
    void setUp() {
        cart = new ArrayList<>();
    }

    @AfterEach
    void tearDown() {
        cart.clear();
    }

    @Test
    void cartStartsEmpty() {
        assertEquals(0, cart.size());
    }

    @Test
    void itemCanBeAddedToCart() {
        cart.add("Book");

        assertEquals(1, cart.size());
    }
}

Method Names Are Flexible

The method names do not have to be setUp() and tearDown().

These are common names, but any valid method name works:

@BeforeEach
void createTestObjects() {
    // setup code
}

@AfterEach
void cleanUpTestObjects() {
    // cleanup code
}

JUnit cares about the annotations, not the method names.


Important Rules

In JUnit 5:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.AfterEach;

The lifecycle methods should usually be:

@BeforeEach
void setUp() {
}

and:

@AfterEach
void tearDown() {
}

They are typically:

  • Not static
  • Package-private or public
  • Return void
  • No parameters, unless using advanced JUnit features such as dependency injection

@BeforeEach vs @BeforeAll

Do not confuse @BeforeEach with @BeforeAll.

Annotation Runs
@BeforeEach Before every test method
@BeforeAll Once before all tests in the class

Example:

@BeforeAll
@BeforeEach
@Test
@AfterEach
@BeforeEach
@Test
@AfterEach
@AfterAll

Use @BeforeEach when each test should start with a clean, fresh setup.

Use @BeforeAll for expensive setup that only needs to happen once.


Complete Example

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.assertEquals;

class BankAccountTest {

    private BankAccount account;

    @BeforeEach
    void setUp() {
        account = new BankAccount(100);
    }

    @AfterEach
    void tearDown() {
        account = null;
    }

    @Test
    void depositIncreasesBalance() {
        account.deposit(50);

        assertEquals(150, account.getBalance());
    }

    @Test
    void withdrawDecreasesBalance() {
        account.withdraw(30);

        assertEquals(70, account.getBalance());
    }
}

Each test starts with a new account balance of 100.

That means depositIncreasesBalance() does not affect withdrawDecreasesBalance().


Summary

Use:

@BeforeEach

to prepare a fresh test environment before every test.

Use:

@AfterEach

to clean up after every test.

A typical pattern is:

@BeforeEach
void setUp() {
    // create test objects
}

@Test
void someTest() {
    // run test
}

@AfterEach
void tearDown() {
    // clean up
}

How do I understand test naming conventions in JUnit?

JUnit itself does not require one specific naming convention for test methods, especially in JUnit 5. A test method is recognized because it is annotated with @Test, not because of its name.

That said, good test names are crucial because they explain what behavior is being tested.


1. Test Class Naming

A common convention is to name the test class after the class being tested, followed by Test.

class CalculatorTest {
}

Examples:

Production Class Test Class
Calculator CalculatorTest
UserService UserServiceTest
OrderRepository OrderRepositoryTest
PasswordValidator PasswordValidatorTest

This makes it easy to find the tests for a given class.


2. Test Method Naming

Test method names should describe the expected behavior.

A good test name usually answers:

What should happen, and under what conditions?

Example:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

class CalculatorTest {

    @Test
    void shouldAddTwoNumbers() {
        int result = 2 + 3;

        assertEquals(5, result);
    }
}

The method name shouldAddTwoNumbers clearly says what behavior is expected.


3. Common Naming Styles

Style 1: shouldDoSomething

This is one of the most common modern styles.

@Test
void shouldReturnSumWhenAddingTwoNumbers() {
}

Examples:

@Test
void shouldCreateUser() {
}

@Test
void shouldRejectInvalidPassword() {
}

@Test
void shouldThrowExceptionWhenEmailIsMissing() {
}

This style is readable and works well for most tests.


Style 2: methodName_shouldExpectedBehavior_whenCondition

This style includes the method being tested, the expected result, and the condition.

@Test
void calculateTotal_shouldReturnDiscountedPrice_whenUserIsPremium() {
}

Pattern:

methodName_shouldExpectedResult_whenCondition

Examples:

@Test
void login_shouldReturnToken_whenCredentialsAreValid() {
}

@Test
void findById_shouldReturnEmpty_whenUserDoesNotExist() {
}

@Test
void register_shouldThrowException_whenEmailAlreadyExists() {
}

This is useful in larger codebases because it makes test reports very descriptive.


Style 3: given_when_then

This style follows behavior-driven development naming.

@Test
void givenValidCredentials_whenLogin_thenReturnsToken() {
}

Pattern:

givenCondition_whenAction_thenExpectedResult

Examples:

@Test
void givenEmptyCart_whenCheckout_thenThrowsException() {
}

@Test
void givenPremiumUser_whenCalculatingPrice_thenAppliesDiscount() {
}

@Test
void givenMissingEmail_whenRegisteringUser_thenValidationFails() {
}

This style is very explicit, though names can become long.


Style 4: Plain Descriptive Name

Sometimes a short descriptive name is enough.

@Test
void returnsTrueForValidPassword() {
}

@Test
void throwsExceptionForInvalidEmail() {
}

@Test
void calculatesTotalPrice() {
}

This is straightforward and readable when the test case is obvious.


4. JUnit 5 Allows Readable Display Names

JUnit 5 supports @DisplayName, which lets you use spaces and natural language in test reports.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertTrue;

class PasswordValidatorTest {

    @Test
    @DisplayName("Valid password should be accepted")
    void shouldAcceptValidPassword() {
        assertTrue(true);
    }
}

The method still needs a valid Java method name, but the test output can show:

Valid password should be accepted

This is useful when you want very readable test reports.


5. Older JUnit Naming Convention

Older JUnit versions, especially JUnit 3, used method names beginning with test.

public void testAddition() {
}

In modern JUnit 5, this is not required.

This still works only if the method is properly annotated with @Test:

@Test
void testAddition() {
}

But modern naming usually prefers more descriptive names like:

@Test
void shouldAddTwoNumbers() {
}

6. Good vs. Weak Test Names

Weak names

@Test
void test1() {
}

@Test
void testUser() {
}

@Test
void checkSomething() {
}

These names do not clearly explain what is being tested.

Better names

@Test
void shouldCreateUserWhenInputIsValid() {
}

@Test
void shouldRejectUserWhenEmailIsMissing() {
}

@Test
void shouldReturnEmptyListWhenNoOrdersExist() {
}

These names explain the expected behavior.


7. Naming Tests for Exceptions

When testing exceptions, include the failure condition in the name.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

class CalculatorTest {

    @Test
    void shouldThrowExceptionWhenDividingByZero() {
        assertThrows(ArithmeticException.class, () -> {
            int result = 10 / 0;
        });
    }
}

Other examples:

@Test
void shouldThrowExceptionWhenEmailIsInvalid() {
}

@Test
void shouldThrowExceptionWhenUserDoesNotExist() {
}

@Test
void shouldThrowExceptionWhenPasswordIsTooShort() {
}

8. Recommended Convention

For most projects, a good default is:

shouldExpectedBehaviorWhenCondition

Example:

@Test
void shouldReturnUserWhenIdExists() {
}

@Test
void shouldReturnEmptyWhenIdDoesNotExist() {
}

@Test
void shouldThrowExceptionWhenInputIsNull() {
}

This style is:

  • Easy to read
  • Easy to search
  • Clear in test reports
  • Not tied to implementation details

Summary

In JUnit 5:

  • Test classes are commonly named ClassNameTest.
  • Test methods do not need to start with test.
  • Test methods should describe behavior clearly.
  • Common styles include:
    • shouldDoSomething
    • shouldExpectedBehaviorWhenCondition
    • methodName_shouldExpectedBehavior_whenCondition
    • givenCondition_whenAction_thenExpectedResult
  • Use @DisplayName when you want more readable test output.

A good test name tells you what failed before you even open the test code.

How do I test exceptions with assertThrows()?

Testing Exceptions with assertThrows() in JUnit 5

Use assertThrows() when you expect a piece of code to throw a specific exception.

Basic Syntax

ExceptionType exception = assertThrows(
        ExceptionType.class,
        () -> {
            // code that should throw the exception
        }
);

For JUnit 5, import it like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

Simple Example

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertThrows;

class DivisionTest {

    @Test
    void divideByZeroThrowsArithmeticException() {
        assertThrows(ArithmeticException.class, () -> {
            int result = 10 / 0;
        });
    }
}

If 10 / 0 throws an ArithmeticException, the test passes.

If no exception is thrown, or a different exception is thrown, the test fails.


Checking the Exception Message

assertThrows() returns the thrown exception, so you can inspect it.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class UserServiceTest {

    @Test
    void rejectsInvalidUserId() {
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> validateUserId(-1)
        );

        assertEquals("User ID must be positive", exception.getMessage());
    }

    private void validateUserId(int userId) {
        if (userId <= 0) {
            throw new IllegalArgumentException("User ID must be positive");
        }
    }
}

Testing a Method That Throws an Exception

Suppose you have this method:

public int divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Divider cannot be zero");
    }

    return a / b;
}

You can test it like this:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

class CalculatorTest {

    private final Calculator calculator = new Calculator();

    @Test
    void divideThrowsExceptionWhenDividerIsZero() {
        IllegalArgumentException exception = assertThrows(
                IllegalArgumentException.class,
                () -> calculator.divide(10, 0)
        );

        assertEquals("Divider cannot be zero", exception.getMessage());
    }
}

Short Form

If you only care that the exception is thrown, you do not need to store it:

@Test
void invalidInputThrowsException() {
    assertThrows(
            IllegalArgumentException.class,
            () -> someMethod("invalid")
    );
}

Important Notes

  • The code that should throw the exception goes inside the lambda: () -> ...
  • The expected exception type goes first: IllegalArgumentException.class
  • The test passes only if that exception type, or a subclass of it, is thrown.
  • If you want an exact exception type match, use assertThrowsExactly().

Example:

@Test
void throwsExactlyIllegalArgumentException() {
    assertThrowsExactly(
            IllegalArgumentException.class,
            () -> someMethod("invalid")
    );
}

You would need this import:

import static org.junit.jupiter.api.Assertions.assertThrowsExactly;

Common Mistake

Do not call the method before assertThrows():

// Wrong
someMethod("invalid");
assertThrows(IllegalArgumentException.class, () -> {});

Instead, call the method inside the lambda:

// Correct
assertThrows(
        IllegalArgumentException.class,
        () -> someMethod("invalid")
);

Summary

Use assertThrows() like this:

@Test
void methodThrowsExpectedException() {
    Exception exception = assertThrows(
            Exception.class,
            () -> methodThatShouldThrow()
    );

    assertEquals("Expected message", exception.getMessage());
}

It verifies that the code throws the expected exception and optionally lets you check details such as the exception message.

How do I group multiple assertions with assertAll()?

In JUnit 5, you can group multiple assertions using assertAll(). This lets JUnit run all assertions in the group, even if one fails, and then report all failures together.

Basic Syntax

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class UserTest {

    @Test
    void testUserDetails() {
        User user = new User("Alice", 25, "[email protected]");

        assertAll("User details",
                () -> assertEquals("Alice", user.getName()),
                () -> assertEquals(25, user.getAge()),
                () -> assertEquals("[email protected]", user.getEmail())
        );
    }
}

Each assertion is written as a lambda expression:

() -> assertEquals(expected, actual)

Why Use assertAll()?

Without assertAll(), JUnit stops at the first failed assertion:

assertEquals("Alice", user.getName());
assertEquals(25, user.getAge());
assertEquals("[email protected]", user.getEmail());

If the first assertion fails, the remaining assertions are not executed.

With assertAll(), JUnit executes every assertion inside the group and reports all failures at once.

Example with Multiple Failures

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class CalculatorTest {

    @Test
    void testCalculatorResults() {
        int result = 10;

        assertAll("Calculator checks",
                () -> assertEquals(10, result),
                () -> assertTrue(result > 0),
                () -> assertFalse(result < 0),
                () -> assertNotEquals(5, result)
        );
    }
}

Nested assertAll()

You can also group assertions into nested sections:

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class PersonTest {

    @Test
    void testPerson() {
        Person person = new Person("John", "Doe", 30);

        assertAll("Person",
                () -> assertAll("Name",
                        () -> assertEquals("John", person.getFirstName()),
                        () -> assertEquals("Doe", person.getLastName())
                ),
                () -> assertAll("Age",
                        () -> assertEquals(30, person.getAge()),
                        () -> assertTrue(person.getAge() >= 18)
                )
        );
    }
}

Using assertAll() with a List

You can use assertAll() when checking multiple objects too:

import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

class ProductTest {

    @Test
    void testProducts() {
        List<String> products = List.of("Book", "Pen", "Notebook");

        assertAll("Product list",
                () -> assertEquals(3, products.size()),
                () -> assertTrue(products.contains("Book")),
                () -> assertTrue(products.contains("Pen")),
                () -> assertTrue(products.contains("Notebook"))
        );
    }
}

Important Note

assertAll() is best used when assertions are independent of each other.

Good:

assertAll("User",
        () -> assertEquals("Alice", user.getName()),
        () -> assertEquals(25, user.getAge()),
        () -> assertEquals("[email protected]", user.getEmail())
);

Avoid placing dependent logic inside it:

assertAll("User",
        () -> assertNotNull(user),
        () -> assertEquals("Alice", user.getName())
);

If user is null, the second assertion may throw a NullPointerException. In that case, check assertNotNull(user) before assertAll():

assertNotNull(user);

assertAll("User",
        () -> assertEquals("Alice", user.getName()),
        () -> assertEquals(25, user.getAge()),
        () -> assertEquals("[email protected]", user.getEmail())
);

Summary

Use assertAll() like this:

assertAll("group name",
        () -> assertEquals(expectedValue, actualValue),
        () -> assertTrue(condition),
        () -> assertNotNull(object)
);

It helps make your tests more informative by showing all assertion failures in one run instead of stopping at the first failure.