Testing Spring Applications with JUnit 5 and Mockito
Interview Preparation Hub for Backend and Cloud-Native Engineering Roles
1. Introduction
Testing is the backbone of reliable software development. In Spring applications, testing ensures that business logic, APIs, and integrations work as expected. JUnit 5 provides a modern, flexible testing framework, while Mockito enables mocking dependencies for isolated unit tests. Together, they empower developers to write clean, maintainable, and effective tests.
This guide covers everything from basics to advanced techniques: unit testing, integration testing, mocking, parameterized tests, dynamic tests, CI/CD integration, best practices, common mistakes, and interview notes. By the end, you will have mastered testing Spring applications with JUnit 5 and Mockito.
2. JUnit 5 Basics
JUnit 5 introduces annotations and features that simplify testing:
@Test– Marks a test method.@BeforeEach– Runs before each test.@AfterEach– Runs after each test.@DisplayName– Provides a readable name for tests.@Nested– Groups related tests.@ParameterizedTest– Runs tests with multiple inputs.@RepeatedTest– Runs a test multiple times.
class CalculatorTest {
private Calculator calculator;
@BeforeEach
void setUp() {
calculator = new Calculator();
}
@Test
@DisplayName("Addition should return correct sum")
void testAddition() {
assertEquals(5, calculator.add(2, 3));
}
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testPositiveNumbers(int number) {
assertTrue(calculator.isPositive(number));
}
}
Parameterized tests allow you to run the same test logic with different inputs, reducing duplication and improving coverage.
3. Mockito Basics
Mockito allows mocking dependencies to isolate units of code. This is crucial in Spring applications where services often depend on repositories or external APIs.
@Mock– Creates a mock object.@InjectMocks– Injects mocks into the tested class.when(...).thenReturn(...)– Defines mock behavior.verify(...)– Verifies interactions with mocks.ArgumentCaptor– Captures arguments passed to mocks.
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserRepository userRepository;
@InjectMocks
private UserService userService;
@Test
void testFindUser() {
User user = new User(1L, "Naresh");
when(userRepository.findById(1L)).thenReturn(Optional.of(user));
User result = userService.getUserById(1L);
assertEquals("Naresh", result.getName());
verify(userRepository).findById(1L);
}
}
4. Advanced Mockito Usage
Advanced features include spies, argument captors, and custom answers:
@Test
void testArgumentCaptor() {
ArgumentCaptor captor = ArgumentCaptor.forClass(User.class);
userService.createUser(new User(null, "Naresh"));
verify(userRepository).save(captor.capture());
assertEquals("Naresh", captor.getValue().getName());
}
Spies allow partial mocking, where real methods are called unless stubbed.
5. Integration Testing with Spring Boot
Spring Boot provides @SpringBootTest for integration testing. MockMvc allows testing controllers without starting a full server.
@SpringBootTest
@AutoConfigureMockMvc
class UserControllerIntegrationTest {
@Autowired
private MockMvc mockMvc;
@Test
void testGetUserEndpoint() throws Exception {
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("Naresh"));
}
}
6. CI/CD Integration
Tests should run automatically in CI/CD pipelines. Tools like Jenkins, GitHub Actions, and GitLab CI can execute JUnit tests and report results.
Code coverage tools like JaCoCo ensure that critical paths are tested. Integrating with SonarQube provides insights into test quality and maintainability.
7. Best Practices
- Write unit tests for business logic with Mockito.
- Use integration tests for end-to-end scenarios.
- Keep tests independent and repeatable.
- Use descriptive names and
@DisplayNamefor clarity. - Verify interactions with mocks to ensure correct behavior.
- Test edge cases and negative scenarios.
- Integrate tests into CI/CD pipelines.
- Measure coverage but focus on meaningful tests, not just numbers.
8. Common Mistakes
- Overusing mocks instead of writing integration tests.
- Not verifying interactions, leading to false positives.
- Mixing unit and integration tests in the same class.
- Ignoring edge cases and negative scenarios.
- Writing brittle tests that depend on implementation details.
9. Interview Notes
Testing is a common topic in technical interviews for backend and full‑stack roles. Interviewers want to see not only that you can write tests, but that you understand the philosophy behind them, the tools available, and the trade‑offs between different approaches.
-
Unit vs Integration Tests: Be ready to explain the difference. Unit tests isolate a single class or method, often using Mockito to mock dependencies. Integration tests verify that multiple layers (controller, service, repository) work together correctly, often using
@SpringBootTestand MockMvc. -
Mockito Usage: Discuss how mocking helps isolate business logic. Be able to show examples of
@Mock,@InjectMocks,when(...).thenReturn(...), andverify(...). -
JUnit 5 Features: Mention annotations like
@ParameterizedTest,@Nested, and@DisplayName. These demonstrate familiarity with modern testing practices. - Best Practices: Emphasize writing independent, repeatable tests, using descriptive names, and testing edge cases.
- CI/CD Integration: Explain how tests fit into pipelines, how coverage is measured, and how failures are reported.
- Common Pitfalls: Be able to identify mistakes like over‑mocking, brittle tests, or ignoring negative scenarios.
Unit Testing → Mocking → Integration Testing → Advanced JUnit 5 → CI/CD → Best Practices → Pitfalls
10. Final Mastery Summary
JUnit 5 and Mockito together form the foundation of modern testing in Spring applications. JUnit 5 provides a flexible, annotation‑driven framework for writing tests, while Mockito enables mocking and verification of dependencies. Mastery of these tools means you can confidently test business logic, APIs, and integrations.
In this guide, we explored:
- JUnit 5 basics and advanced features like parameterized and nested tests.
- Mockito basics and advanced usage with argument captors and spies.
- Integration testing with
@SpringBootTestand MockMvc. - CI/CD integration for automated testing pipelines.
- Best practices for writing clean, maintainable tests.
- Common mistakes to avoid, such as over‑mocking or brittle tests.
- Interview notes to prepare for technical discussions.
By applying these concepts, you ensure that your Spring applications are reliable, maintainable, and production‑ready. Testing is not just about catching bugs — it’s about building confidence in your codebase, enabling faster iteration, and supporting long‑term scalability.
JUnit 5 Basics → Mockito Basics → Advanced Testing → Integration Testing → CI/CD → Best Practices → Mastery