Published: November 3, 2024
Testing is a cornerstone of professional software development, ensuring your Spring Boot application works correctly, stays maintainable, and evolves confidently. In this post, we’ll explore how to leverage JUnit 5 and Mockito for effective unit and integration testing of Spring Boot applications.
Why JUnit 5 and Mockito?
- JUnit 5 is the modern testing framework with modular architecture and improved features over JUnit 4.
- Mockito is the leading mocking framework to simulate dependencies and isolate units for testing.
- Spring Boot’s test starter integrates well with both, making testing straightforward.
Getting Started: Setup Dependencies
In your pom.xml
for Maven or build.gradle
for Gradle, add:
Maven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
This includes JUnit 5, Mockito, and Spring Test libraries.
Writing Unit Tests with JUnit 5 and Mockito
Example 1: Testing a Service with Mocked Repository
Assume a simple service layer:
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User findUserById(Long id) {
return userRepository.findById(id).orElse(null);
}
}
Create a test class:
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testFindUserById_UserExists() {
User user = new User(1L, "Alice");
Mockito.when(userRepository.findById(1L)).thenReturn(Optional.of(user));
User result = userService.findUserById(1L);
Assertions.assertNotNull(result);
Assertions.assertEquals("Alice", result.getName());
}
@Test
void testFindUserById_UserNotFound() {
Mockito.when(userRepository.findById(2L)).thenReturn(Optional.empty());
User result = userService.findUserById(2L);
Assertions.assertNull(result);
}
}
Explanation:
@Mock
creates a mock of the repository.@InjectMocks
injects the mock into the service.- Mockito’s
when(...).thenReturn(...)
configures mock behavior. - Assertions verify outcomes.
Integration Testing with Spring Boot Test
Sometimes, you want to test components together with the Spring context.
Example 2: Testing Controller with Spring Boot
@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void testGetUser() throws Exception {
mockMvc.perform(get("/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Alice"));
}
}
Here:
@SpringBootTest
boots the entire Spring context.MockMvc
performs HTTP request simulations without a real server.jsonPath
verifies JSON response structure.
Mocking Beans in Spring Context
If you want to mock certain beans in an integration test, use:
@MockBean
private UserRepository userRepository;
This will replace the real bean with a mock in the Spring context.
Advanced Tips
- Use parameterized tests (
@ParameterizedTest
) in JUnit 5 to run the same test with different inputs. - Leverage ArgumentCaptor in Mockito to verify method arguments.
- Use @Nested tests in JUnit 5 to organize test cases.
- Consider Testcontainers for integration tests with real databases or message brokers.
Summary
JUnit 5 and Mockito provide a powerful combo to test Spring Boot applications, from isolated units to full integration tests. Proper use of mocks, assertions, and Spring testing support ensures robust, maintainable tests.