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