Unit Testing with JUnit 5 & Mockito
Unit testing is the foundation of software quality. A unit test checks a single Java class in complete isolation. If your <code>UserService</code> talks to a <code>Database</code>, a unit test fakes the database so you only test the logic inside <code>UserService</code>. We use <strong>JUnit 5</strong> and <strong>Mockito</strong> for this.
The Chef Tasting the Sauce Analogy:
Before a Hyderabadi chef serves Biryani to 1000 people at a wedding, they don't cook 1000 plates to see if the recipe is right. They cook a small sample of the masala in a test kitchen (Unit Test). They use fake, cheap ingredients (Mocks) instead of the real expensive saffron, just to check if the recipe logic is correct.
In Java, Mockito creates fake objects (Mocks) of your repositories. You tell the mock exactly what to return, so you can test your Service's logic without needing a real database.
- JUnit 5 (
org.junit.jupiter): The modern testing framework. Uses@Testand@BeforeEach. - @ExtendWith(MockitoExtension.class): Tells JUnit to enable Mockito for this test class.
- @Mock: Creates a fake, empty object of a dependency (e.g., a fake Repository).
- @InjectMocks: Creates a real instance of the class you are testing (e.g., Service) and automatically injects the
@Mockobjects into it. - when().thenReturn(): Trains the mock. "When someone calls
findById(1), return a fake Book."
package com.devinhyderabad;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
// 1. Enable Mockito
@ExtendWith(MockitoExtension.class)
public class BookServiceTest {
// 2. Create a fake BookRepository (It won't touch a real DB)
@Mock
private BookRepository bookRepository;
// 3. Create a real BookService and inject the fake repo into it
@InjectMocks
private BookService bookService;
@Test
public void testGetBookTitle_ReturnsUpperCase() {
// 4. Arrange: Train the mock
Book fakeBook = new Book(1L, "spring boot", "Deva");
when(bookRepository.findById(1L)).thenReturn(Optional.of(fakeBook));
// 5. Act: Call the real service method
String result = bookService.getBookTitleUpperCase(1L);
// 6. Assert: Check if the logic worked
assertEquals("SPRING BOOT", result);
}
}Note: We assume BookService has a method getBookTitleUpperCase that fetches the book and uppercases the title.
Interview Question: "What is the difference between a Unit Test and an Integration Test in Spring Boot?"
Answer: A unit test (using @ExtendWith(MockitoExtension.class)) tests a single class in isolation. It does not start the Spring Application Context and uses mocked dependencies. It is extremely fast. An integration test (using @SpringBootTest) starts the real Spring context, connects to a real (or test) database, and tests how multiple components work together.
Enterprise Note: Follow the Test Pyramid. 80% of your tests should be fast Unit Tests (Mockito). Only 20% should be slow Integration Tests. If you write only integration tests, your CI/CD pipeline will take an hour to run.
Key Takeaways
- ✅ @ExtendWith(MockitoExtension.class) enables Mockito in JUnit 5
- ✅ @Mock creates fake objects; @InjectMocks injects them into the class under test
- ✅ when().thenReturn() trains the mock to return specific values
- ✅ Follow the Test Pyramid: 80% unit tests, 20% integration tests
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login