Mockito in JUnit
Mockito is a popular Java framework used in JUnit testing to create mock objects. These mock objects simulate real dependencies, making unit testing faster, isolated, and more reliable.
Why Use Mockito?
- Isolate dependencies: Avoid calling actual services, databases, or APIs.
- Improve test performance: No need to connect to external systems.
- Control method behavior: Define return values for methods.
- Verify interactions: Ensure methods are called with expected parameters.
Basic Mockito Annotations
1️⃣ @Mock
→ Creates a mock object.
@Mockprivate DepartmentService departmentService;
2️⃣ @InjectMocks
→ Injects mock objects into the class being tested.
@InjectMocks
private DepartmentController departmentController;
3️⃣ @BeforeEach
→ Initializes mocks before each test.
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
Example: Unit Test for DepartmentController
@ExtendWith(MockitoExtension.class) // JUnit 5 (JUnit Jupiter)
public class DepartmentControllerTest {
@Mock
private DepartmentService departmentService;
@InjectMocks
private DepartmentController departmentController;
private Department department;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
department = Department.builder()
.departmentId(1L)
.departmentName("IT")
.departmentAddress("New York")
.departmentCode("IT-001")
.build();
}
@Test
void testSaveDepartment() {
when(departmentService.saveDepartment(any(Department.class))).thenReturn(department);
Department savedDepartment = departmentController.saveDepartment(department);
assertNotNull(savedDepartment);
assertEquals("IT", savedDepartment.getDepartmentName());
}
@Test
void testFetchDepartmentById() throws DepartmentNotFoundException {
when(departmentService.fetchDepartmentById(1L)).thenReturn(department);
Department foundDepartment = departmentController.fetchDepartmentById(1L);
assertNotNull(foundDepartment);
assertEquals(1L, foundDepartment.getDepartmentId());
}
@Test
void testDeleteDepartmentById() {
String response = departmentController.deleteDepartmentById(1L);
assertEquals("Department deleted Successfully!!", response);
verify(departmentService, times(1)).deleteDepartmentById(1L);
}
}
Key Mockito Methods
when(...).thenReturn(...)
→ Mock method behavior.when(departmentService.fetchDepartmentById(1L)).thenReturn(department);
any(Class.class)
→ Match any argument of that class.when(departmentService.saveDepartment(any(Department.class))).thenReturn(department);
verify(..., times(n))
→ Ensure a method was called n
times.verify(departmentService, times(1)).deleteDepartmentById(1L);
doThrow(...).when(...).method()
→ Simulate exceptions.doThrow(new DepartmentNotFoundException("Not Found")).when(departmentService).fetchDepartmentById(2L);
Mockito vs. Real Objects
Feature Real Object Mockito Mock Calls real methods? ✅ Yes ❌ No Affects real data? ✅ Yes ❌ No Faster execution? ❌ No ✅ Yes Dependency isolation? ❌ No ✅ Yes
1) We can write JUnit tests for a Spring Boot Controller layer using @WebMvcTest
with Mockito, while the backend uses MS SQL Server(relational database).
✅ Scenario Overview for relational databases
-
Database: MS SQL Server (via Spring Data JPA)
-
Test: Controller using
@WebMvcTest
-
Mocking:
UserService
-
HTTP testing:
MockMvc
User.java
(Entity)๐ฆ 2. UserRepository.java
public interface UserRepository extends JpaRepository<User, Long> {
}
๐ฆ 3. UserService.java
@Servicepublic class UserService {
@Autowired
private UserRepository userRepository;
public User saveUser(User user) {
return userRepository.save(user);
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
public Optional<User> getUserById(Long id) {
return userRepository.findById(id);
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
๐ฆ 4. UserController.java
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
return new ResponseEntity<>(userService.saveUser(user), HttpStatus.CREATED);
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
return ResponseEntity.ok(userService.getAllUsers());
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.getUserById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.deleteUser(id);
return ResponseEntity.noContent().build();
}
}
๐ Key Point:
in @WebMvcTest
tests, the actual database (MSSQL Or MongoDB) is not involved — we mock the service layer, so it doesn't matter which database is used.
✅ 5. UserControllerTest.java
– @WebMvcTest
+ Mockito
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private UserService userService;
private User user;
@BeforeEach
void setUp() {
user = new User();
user.setId(1L);
user.setName("John");
user.setEmail("john@example.com");
}
@Test
void testCreateUser() throws Exception {
when(userService.saveUser(any(User.class))).thenReturn(user);
mockMvc.perform(post("/api/users")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"John\", \"email\":\"john@example.com\"}"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value("John"))
.andExpect(jsonPath("$.email").value("john@example.com"));
}
@Test
void testGetAllUsers() throws Exception {
when(userService.getAllUsers()).thenReturn(List.of(user));
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.length()").value(1))
.andExpect(jsonPath("$[0].name").value("John"));
}
@Test
void testGetUserById() throws Exception {
when(userService.getUserById(1L)).thenReturn(Optional.of(user));
mockMvc.perform(get("/api/users/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value("John"));
}
@Test
void testDeleteUser() throws Exception {
doNothing().when(userService).deleteUser(1L);
mockMvc.perform(delete("/api/users/1"))
.andExpect(status().isNoContent());
}
}
๐งช Dependencies Required in pom.xml
Make sure your pom.xml
includes:
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- For JSONPath in tests -->
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
✅ Summary
Layer Tool Used Notes Controller @WebMvcTest
Tests only controller, not service/repo Service @MockBean
Service is mocked to isolate controller DB MS SQL Not used in controller test
------------------------------------------------------------2)We can write a JUnit + Mockito + @WebMvcTest test class for a Spring Boot Controller that uses MongoDB.✅ Scenario Setup: MongoDB-based User CRUD๐ฆ User.java
@Document(collection = "users")
public class User {
@Id
private String id;
private String name;
private String email;
// Getters and Setters
}
๐ฆ UserRepository.java
public interface UserRepository extends MongoRepository<User, String> {
}
๐ฆ UserService.java same as above
๐ฆ UserController.java same as above
✅ UserControllerTest.java
– JUnit + Mockito + @WebMvcTest same as above
๐ฆ Maven Dependencies (If not already present)
Make sure your test scope dependencies include:
<!-- Spring Boot Starter Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Mockito Core -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
✅ Summary
@WebMvcTest
isolates only the controller.
@MockBean
is used to inject a mocked UserService
—the database (MongoDB) isn’t touched.
Use MockMvc
to simulate HTTP requests.
Since MongoDB is abstracted behind the service, you don't need to mock the repository for controller tests.
No comments:
Post a Comment