JUnit 5 - Quick Reference
Deep Knowledge: Use mcp__documentation__fetch_docs with technology: junit for comprehensive documentation.
When NOT to Use This Skill
- Integration Tests with Containers - Use
testcontainers for Docker-based tests - REST API Testing - Use
rest-assured for HTTP/REST testing - E2E Web Testing - Use Selenium or Playwright
- JavaScript/TypeScript - Use
vitest or jest for JS/TS - Database Integration Tests - Combine with
spring-boot-integration skill
Essential Patterns
Basic Test
@Test
void shouldAddNumbers() {
assertEquals(5, calculator.add(2, 3));
assertThrows(ArithmeticException.class, () -> calculator.divide(10, 0));
}
Mockito + Service Test
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserServiceImpl userService;
@Test
void shouldCreateUser() {
when(userRepository.save(any())).thenReturn(user);
UserResponse result = userService.create(request);
assertNotNull(result);
verify(userRepository, times(1)).save(any());
}
}
Spring Boot Test
@SpringBootTest
@ActiveProfiles("test")
class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@MockBean
private UserRepository userRepository;
@Test
void contextLoads() {
assertNotNull(userService);
}
}
Controller Test
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
@Test
void shouldReturnUsers() throws Exception {
when(userService.findAll()).thenReturn(users);
mockMvc.perform(get("/api/v1/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("John"));
}
}
Repository Test
@DataJpaTest
class UserRepositoryTest {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository userRepository;
@Test
void shouldFindByEmail() {
entityManager.persist(user);
Optional<User> found = userRepository.findByEmail("john@email.com");
assertTrue(found.isPresent());
}
}
Common Annotations
| Annotation | Usage |
|---|
@Test | Test method |
@BeforeEach | Setup before each test |
@Mock | Creates mock |
@InjectMocks | Injects mocks |
@SpringBootTest | Integration test |
@WebMvcTest | Controller test |
@DataJpaTest | Repository test |
Anti-Patterns
| Anti-Pattern | Why It's Bad | Solution |
|---|
| Using @SpringBootTest for unit tests | Extremely slow | Use @ExtendWith(MockitoExtension.class) |
| Testing private methods | Coupled to implementation | Test through public API |
| No mock cleanup | Tests affect each other | Use @BeforeEach, Mockito.reset() |
| Hardcoded test data | Hard to maintain | Use test data builders or factories |
| Not verifying mock interactions | Silent failures | Use verify() to ensure methods called |
| Too many assertions per test | Hard to debug | One logical assertion per test |
| Ignoring @Disabled tests | Technical debt accumulates | Fix or remove disabled tests |
Quick Troubleshooting
| Problem | Likely Cause | Solution |
|---|
| "NullPointerException in test" | Mock not injected | Check @Mock and @InjectMocks annotations |
| "Wanted but not invoked" | Method not called or wrong args | Verify method call, check argument matchers |
| Test takes too long | Using @SpringBootTest unnecessarily | Use Mockito for unit tests |
| "UnnecessaryStubbingException" | Mock setup but not used | Remove unused when() statements |
| Flaky test | Shared state or timing | Isolate setup, avoid Thread.sleep |
| "No tests found" | Wrong naming convention | Use test* prefix or @Test annotation |
Reference Documentation