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("[email protected]"));
}
@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
| Annotation | Lifecycle | Notes |
|---|---|---|
@Test | Per test | Marks a method as a test |
@BeforeEach | Before each test | Setup / reset state |
@AfterEach | After each test | Cleanup / teardown |
@BeforeAll | Once before all | Must be static (unless PER_CLASS) |
@AfterAll | Once after all | Must be static (unless PER_CLASS) |
@Nested | Class level | Groups related tests |
@Tag | Class/method | Filter by tag at runtime |
@Disabled | Class/method | Skip test(s) |
@DisplayName | Class/method | Human-readable name |
@ExtendWith | Class level | Register extensions |
@Timeout | Class/method | Fail if duration exceeded |