Labs ICT
Pro Login

Test Methods and Annotations

You have seen the @Test annotation in action, but JUnit 5 has a whole bunch of annotations that let you control how your tests run. Let us go through the most important ones so you know what tools you have at your disposal.

The Core Annotations


import org.junit.jupiter.api.*;

class AnnotationsDemoTest {

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

    @BeforeEach
    void beforeEach() {
        System.out.println("Runs before EACH test");
    }

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

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

    @AfterEach
    void afterEach() {
        System.out.println("Runs after EACH test");
    }

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

Running this prints:


Runs once before ALL tests
Runs before EACH test
First test
Runs after EACH test
Runs before EACH test
Second test
Runs after EACH test
Runs once after ALL tests
    

The @Test Annotation

This is the most basic annotation. Any method annotated with @Test is a test method. That is it. No special naming conventions required (unlike JUnit 4 where methods had to start with "test").


@Test
void thisIsATest() {
    // JUnit will find and run this method
}

@Test
void thisIsAlsoATest() {
    // This one too
}

void thisIsNotATest() {
    // No @Test annotation, so JUnit ignores this
}
    

@Disabled - Skipping Tests

Sometimes you want to skip a test. Maybe the feature is not implemented yet, or there is a known bug you are not ready to fix. Use @Disabled:


@Test
@Disabled("Not implemented yet - waiting for API")
void shouldCallExternalService() {
    // This test will be skipped
}

@Test
@Disabled("Known issue: see JIRA-1234")
void shouldHandleEdgeCase() {
    // This test will also be skipped
}
    

The string argument is optional but highly recommended. It tells other developers why the test is disabled. A disabled test without a reason is like a TODO comment without context — useless.

@DisplayName - Making Tests Readable

By default, JUnit uses the method name as the display name. But method names have limitations (no spaces, no special characters). @DisplayName lets you give your tests a human-readable name:


@Test
@DisplayName("Should add two positive numbers correctly")
void shouldAddTwoPositiveNumbers() {
    Calculator calc = new Calculator();
    assertEquals(7, calc.add(3, 4));
}

@Test
@DisplayName("Should return 0 when adding zero")
void addWithZero() {
    Calculator calc = new Calculator();
    assertEquals(5, calc.add(5, 0));
}
    

This shows up in your test reports and makes it much easier to understand what is being tested at a glance.

@Nested - Grouping Tests

When you have many tests for a single class, @Nested lets you group them into logical sections using inner classes:


class CalculatorTest {

    Calculator calc = new Calculator();

    @Nested
    class AdditionTests {
        @Test
        void shouldAddPositiveNumbers() {
            assertEquals(5, calc.add(2, 3));
        }

        @Test
        void shouldHandleNegativeNumbers() {
            assertEquals(-1, calc.add(-3, 2));
        }
    }

    @Nested
    class DivisionTests {
        @Test
        void shouldDivideCorrectly() {
            assertEquals(3, calc.divide(9, 3));
        }

        @Test
        void shouldThrowWhenDividingByZero() {
            assertThrows(ArithmeticException.class,
                () -> calc.divide(1, 0));
        }
    }
}
    

Now your test report looks like a clear hierarchy instead of a flat list of 50 tests.

@Tag - Filtering Tests

Tags let you categorize tests so you can run subsets:


@Test
@Tag("fast")
void quickTest() {
    // Runs quickly
}

@Test
@Tag("slow")
void databaseTest() {
    // Takes time, maybe skip in CI
}

@Test
@Tag("integration")
void externalApiTest() {
    // Depends on external service
}
    

Run only fast tests:


# Maven
mvn test -Dgroups=fast

# Gradle
gradle test -Dgroups=fast

# Exclude slow tests
mvn test -DexcludedGroups=slow