Wednesday, 11 June 2025

Mockito in JUnit with relational database (Or) NoSQL

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.

@Mock
private 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

  1. when(...).thenReturn(...) → Mock method behavior.
    when(departmentService.fetchDepartmentById(1L)).thenReturn(department);
  2. any(Class.class) → Match any argument of that class.
    when(departmentService.saveDepartment(any(Department.class))).thenReturn(department);
  3. verify(..., times(n)) → Ensure a method was called n times.
    verify(departmentService, times(1)).deleteDepartmentById(1L);
  4. doThrow(...).when(...).method() → Simulate exceptions.
    doThrow(new DepartmentNotFoundException("Not Found")).when(departmentService).fetchDepartmentById(2L);

Mockito vs. Real Objects

FeatureReal ObjectMockito 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

๐Ÿ“ฆ 1. User.java (Entity)
@Entity
@Table(name = "users")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String email;
    // Constructors, Getters, Setters
}

๐Ÿ“ฆ 2. UserRepository.java

public interface UserRepository extends JpaRepository<User, Long> { }

๐Ÿ“ฆ 3. UserService.java

@Service
public 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

LayerTool UsedNotes
Controller@WebMvcTestTests only controller, not service/repo
Service@MockBeanService is mocked to isolate controller
DBMS SQLNot 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.

3)Can you test private methods with JUnit + Mockito?

๐Ÿ”ด Directly — ❌ NOT recommended

Mockito does NOT support mocking or verifying private methods directly. It follows the best practice: test public behavior, not internal implementation.

๐ŸŸก Indirectly — ✅ YES

Private methods can be tested indirectly by calling public methods that use them.

๐Ÿ›  If you still need to test a private method:

Use Reflection (not recommended for unit tests). Use PowerMock (now outdated and not compatible with JUnit 5). Use JUnit 5 + ReflectionTestUtils or similar only for legacy systems.

✍️ Example: Testing private method indirectly

java
public class MyService { public String process(String input) { return format(input.toUpperCase()); } private String format(String value) { return "[" + value + "]"; } }
java
@Test public void testProcess() { MyService service = new MyService(); String result = service.process("hello"); assertEquals("[HELLO]", result); // indirectly tests private format() }

๐Ÿ“š Common JUnit & Mockito Annotations

AnnotationLibraryDescription
@TestJUnitMarks a test method
@BeforeEach / @BeforeJUnitRuns before each test (JUnit 5 / JUnit 4)
@AfterEach / @AfterJUnitRuns after each test
@BeforeAll / @BeforeClassJUnitRuns once before all tests
@AfterAll / @AfterClassJUnitRuns once after all tests
@DisplayNameJUnit 5Custom name for test method
@NestedJUnit 5For grouping related test cases
@MockMockitoCreates a mock object
@InjectMocksMockitoInjects mocks into the tested object
@SpyMockitoSpy on real object (partial mocking)
@CaptorMockitoCaptures arguments passed to mocks
@ExtendWith(MockitoExtension.class)JUnit 5 + MockitoEnables Mockito annotations in JUnit 5

๐Ÿงช Example: Mockito with Annotations

java
@ExtendWith(MockitoExtension.class) public class UserServiceTest { @Mock private UserRepository userRepository; @InjectMocks private UserService userService; @Test public void testFindById() { User user = new User("1", "Swamy"); when(userRepository.findById("1")).thenReturn(Optional.of(user)); Optional<User> result = userService.findById("1"); assertTrue(result.isPresent()); assertEquals("Swamy", result.get().getName()); } }

๐Ÿ›‘ Summary

QuestionAnswer
Can you test private methods in Mockito?Not directly, only via public methods.
Can you mock private methods in Mockito?No, use PowerMock (not recommended).
Best practice?Test only public behavior; private methods are implementation details.