JUnit5 Annotations

Core Test Annotations

import org.junit.jupiter.api.*; class CalculatorTest { private Calculator calc; @BeforeAll static void initAll() { // Runs once before all tests in this class System.out.println("Suite starting"); } @BeforeEach void setUp() { // Runs before each test method calc = new Calculator(); } @Test @DisplayName("Addition: 2 + 3 = 5") void testAdd() { assertEquals(5, calc.add(2, 3)); } @Test void testDivide() { assertEquals(2.0, calc.divide(10, 5)); } @AfterEach void tearDown() { // Runs after each test calc = null; } @AfterAll static void tearDownAll() { // Runs once after all tests System.out.println("Suite finished"); } }

@Nested โ€” Hierarchical Tests

@DisplayName("UserService Tests") class UserServiceTest { @Nested @DisplayName("when user exists") class WhenUserExists { private User user; @BeforeEach void setUp() { user = userRepo.save(new User("alice@example.com")); } @Test void findById_returnsUser() { assertNotNull(service.findById(user.getId())); } @Test void delete_removesUser() { service.delete(user.getId()); assertFalse(userRepo.existsById(user.getId())); } } @Nested @DisplayName("when user does not exist") class WhenUserNotFound { @Test void findById_throwsException() { assertThrows(UserNotFoundException.class, () -> service.findById(999L)); } } }

@Tag, @Disabled, @Timeout

import org.junit.jupiter.api.*; import java.time.Duration; // Tags for test selection @Tag("integration") @Tag("database") class DatabaseIntegrationTest { @Test @Tag("slow") void largeDatasetQuery() { /* ... */ } @Test @Disabled("Temporarily disabled โ€” see JIRA-1234") void brokenFeatureTest() { /* ... */ } @Test @Timeout(5) // Fails if test takes longer than 5 seconds void apiCallShouldBeQuick() throws Exception { // ... } @Test void withAssertTimeout() { assertTimeout(Duration.ofSeconds(2), () -> { performSlowOperation(); }); } } // Run only tagged tests with Maven: // mvn test -Dgroups="integration" // mvn test -DexcludedGroups="slow"

@ExtendWith โ€” Extensions

import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.context.junit.jupiter.SpringExtension; // Mockito integration @ExtendWith(MockitoExtension.class) class PaymentServiceTest { @Mock private PaymentGateway gateway; @InjectMocks private PaymentService service; @Test void chargeCard_callsGateway() { when(gateway.charge(any())).thenReturn(new ChargeResult("ch_1")); service.processPayment(new Order(100.0)); verify(gateway, times(1)).charge(any()); } } // Spring Boot test @ExtendWith(SpringExtension.class) @SpringBootTest class ApplicationTest { @Autowired private MyService service; // ... } // Custom extension @ExtendWith(CustomDbExtension.class) class CustomExtTest { /* ... */ }

@TestMethodOrder & Lifecycle

import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.TestInstance; // Control test execution order @TestMethodOrder(MethodOrderer.OrderAnnotation.class) class OrderedTest { @Test @Order(1) void firstTest() { /* ... */ } @Test @Order(2) void secondTest() { /* ... */ } @Test @Order(3) void thirdTest() { /* ... */ } } // Shared instance โ€” one instance for all tests @TestInstance(TestInstance.Lifecycle.PER_CLASS) class SharedInstanceTest { private final List<String> log = new ArrayList<>(); @BeforeAll void init() { log.add("start"); } // No static needed @Test void test1() { log.add("t1"); } @Test void test2() { log.add("t2"); } @AfterAll void printLog() { System.out.println(log); } }

Annotation Quick Reference

AnnotationLifecycleNotes
@TestPer testMarks a method as a test
@BeforeEachBefore each testSetup / reset state
@AfterEachAfter each testCleanup / teardown
@BeforeAllOnce before allMust be static (unless PER_CLASS)
@AfterAllOnce after allMust be static (unless PER_CLASS)
@NestedClass levelGroups related tests
@TagClass/methodFilter by tag at runtime
@DisabledClass/methodSkip test(s)
@DisplayNameClass/methodHuman-readable name
@ExtendWithClass levelRegister extensions
@TimeoutClass/methodFail if duration exceeded