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.

How do I test null and non-null values in JUnit?

To test null and non-null values in JUnit, use these assertions:

  • assertNull(value) — passes if the value is null
  • assertNotNull(value) — passes if the value is not null

In JUnit 5, these methods are available from org.junit.jupiter.api.Assertions.

Basic Example

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class NullCheckTest {

    @Test
    void valueShouldBeNull() {
        String name = null;

        assertNull(name);
    }

    @Test
    void valueShouldNotBeNull() {
        String name = "John";

        assertNotNull(name);
    }
}

Using Assertion Messages

You can add a message to make test failures easier to understand.

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertNotNull;

class NullCheckTest {

    @Test
    void valueShouldBeNull() {
        String result = null;

        assertNull(result, "The result should be null");
    }

    @Test
    void valueShouldNotBeNull() {
        String result = "Hello JUnit";

        assertNotNull(result, "The result should not be null");
    }
}

Testing a Method That May Return Null

Suppose you have a method that returns a username:

class UserService {

    String findUsernameById(int id) {
        if (id == 1) {
            return "Alice";
        }
        return null;
    }
}

You can test both cases like this:

import org.junit.jupiter.api.Test;

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

class UserServiceTest {

    private final UserService userService = new UserService();

    @Test
    void findUsernameByIdReturnsNameWhenUserExists() {
        String username = userService.findUsernameById(1);

        assertNotNull(username);
        assertEquals("Alice", username);
    }

    @Test
    void findUsernameByIdReturnsNullWhenUserDoesNotExist() {
        String username = userService.findUsernameById(99);

        assertNull(username);
    }
}

Testing Null Arguments

If your code should reject null values, use assertThrows() to check that an exception is thrown.

import org.junit.jupiter.api.Test;

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

class PersonTest {

    @Test
    void constructorThrowsExceptionWhenNameIsNull() {
        NullPointerException exception = assertThrows(
                NullPointerException.class,
                () -> new Person(null)
        );

        assertEquals("Name cannot be null", exception.getMessage());
    }
}

class Person {

    private final String name;

    Person(String name) {
        if (name == null) {
            throw new NullPointerException("Name cannot be null");
        }

        this.name = name;
    }
}

Summary

Use:

assertNull(value);
assertNotNull(value);

For null-related exceptions, use:

assertThrows(NullPointerException.class, () -> {
    // code that should throw NullPointerException
});

These assertions are the standard way to test null and non-null values in JUnit 5.

How do I test boolean conditions with assertTrue() and assertFalse()?

Use assertTrue() when you expect a boolean condition to be true, and assertFalse() when you expect it to be false.

They are JUnit assertions, most commonly used in JUnit 5 like this:

import org.junit.jupiter.api.Test;

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

class BooleanConditionTest {

    @Test
    void shouldCheckBooleanConditions() {
        String message = "Hello JUnit";

        assertTrue(message.contains("JUnit"));
        assertFalse(message.isEmpty());
    }
}

assertTrue()

assertTrue(condition) passes if the condition evaluates to true.

assertTrue(5 > 3);
assertTrue("JUnit".startsWith("J"));

If the condition is false, the test fails.

assertFalse()

assertFalse(condition) passes if the condition evaluates to false.

assertFalse(5 < 3);
assertFalse("JUnit".isBlank());

If the condition is true, the test fails.

Example with a custom method

Suppose you have a method that checks whether a user is active:

class User {
    private boolean active;

    User(boolean active) {
        this.active = active;
    }

    boolean isActive() {
        return active;
    }
}

You can test it like this:

import org.junit.jupiter.api.Test;

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

class UserTest {

    @Test
    void activeUserShouldReturnTrue() {
        User user = new User(true);

        assertTrue(user.isActive());
    }

    @Test
    void inactiveUserShouldReturnFalse() {
        User user = new User(false);

        assertFalse(user.isActive());
    }
}

Add failure messages

You can also provide a message that appears when the assertion fails:

assertTrue(user.isActive(), "User should be active");
assertFalse(message.isEmpty(), "Message should not be empty");

Summary

Assertion Use when you expect
assertTrue(condition) The condition should be true
assertFalse(condition) The condition should be false

In short:

assertTrue(value > 0);
assertFalse(name.isBlank());