Back to Spring Boot Course

Spring Boot Course

Unit testing is a crucial practice in modern software development that ensures individual components of your application work as expected.

Junit is a widely used framework for writing and running unit tests in Java. It provides annotations and assertions that make it easy to test code.

Junit 5 Annotations

Test Execution Annotations

  • @Test Marks a method as a test method that will be executed by the testing framework. across tests.
  • @Disabled Marks a test method to be ignored or skipped. This is useful if you need to temporarily disable a test.

Setup and Teardown Annotations

  • @BeforeEach Marks a method to be run before each test. Useful for setting up any common test data or initializing objects.
  • @BeforeAll Marks a static method to be run once before all tests in a class. This is used for expensive setup steps that should only run once.
  • @AfterEach Marks a method to be run after each test. This is useful for cleaning up any resources or resetting states after a test.
  • @AfterAll Marks a static method to be run once after all tests in a class. It's commonly used to clean up resources that are shared

Let's see an example with these annotations,

import org.junit.jupiter.api.*; import java.io.*; import static org.junit.jupiter.api.Assertions.*; class FileServiceTest { private static final String TEMP_FILE_PATH = "temp_test_file.txt"; private FileService fileService; @BeforeAll static void setupBeforeAllTests() { log.info("Setting up before all tests..."); try { File tempFile = new File(TEMP_FILE_PATH); if (!tempFile.exists()) { tempFile.createNewFile(); } } catch (IOException e) { e.printStackTrace(); fail("Failed to set up temporary file."); } } @BeforeEach void setup() { fileService = new FileService(TEMP_FILE_PATH); } @Test void testCreateFile() { boolean result = fileService.createFile(); assertTrue(result, "File should be created successfully."); File file = new File(TEMP_FILE_PATH); assertTrue(file.exists(), "File should exist after creation."); } @Disabled("Test is disabled due to an ongoing issue") @Test void testDeleteFile() { fileService.createFile(); boolean result = fileService.deleteFile(); assertTrue(result, "File should be deleted successfully."); File file = new File(TEMP_FILE_PATH); assertFalse(file.exists(), "File should not exist after deletion."); } @AfterEach void tearDown() { log.info("Test completed."); } @AfterAll static void tearDownAfterAllTests() { log.info("Cleaning up after all tests..."); try { File tempFile = new File(TEMP_FILE_PATH); if (tempFile.exists()) { tempFile.delete(); } } catch (Exception e) { e.printStackTrace(); fail("Failed to clean up temporary file."); } } }

Parameterized Test Annotations

  • @ParameterizedTest Marks a test method to be run multiple times with different arguments. Often used in combination with argument sources like @ValueSource, @CsvSource, or @MethodSource.
  • @ValueSource Provides a set of values for a parameterized test method.

For example,

@ParameterizedTest @ValueSource(strings = {"Engineering", "Marketing", "HR"}) void testGetEmployeesByDepartment(String department) { List<Employee> employees = Arrays.asList( new Employee(1, "Praveen", department), new Employee(2, "Kiran", department) ); Mockito.when(employeeRepository.findByDepartment(department)).thenReturn(employees); List<Employee> result = employeeService.getEmployeesByDepartment(department); assertEquals(2, result.size()); assertEquals(department, result.get(0).getDepartment()); }
  • @CsvSource Provides a CSV list of values to be passed to a parameterized test method.

For example,

@ParameterizedTest @CsvSource({ "Praveen Oruganti, Engineering", "Kiran Badugu, Marketing", "Praneeth Vishnubhotla, HR" }) void testCreateEmployee(String name, String department) { Employee newEmployee = new Employee(1, name, department); Mockito.when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(newEmployee); Employee result = employeeService.createEmployee(newEmployee); assertNotNull(result); assertEquals(name, result.getName()); assertEquals(department, result.getDepartment()); }
  • @CsvFileSource This is similar to @CsvSource, but instead of specifying the values inline, you read them from a CSV file.

For example,

@ParameterizedTest @CsvFileSource(resources = "/employee-data.csv", numLinesToSkip = 1) void testCreateEmployeeFromFile(String name, String department) { Employee newEmployee = new Employee(1, name, department); Mockito.when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(newEmployee); Employee result = employeeService.createEmployee(newEmployee); assertNotNull(result); assertEquals(name, result.getName()); assertEquals(department, result.getDepartment()); }
  • @MethodSource Provides the test data from a static method. The method should return a stream, collection, or array of arguments.

For example,

import org.junit.jupiter.api.*; import org.junit.jupiter.params.*; import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.*; class EmployeeServiceTest { private EmployeeService employeeService; @BeforeEach void setUp() { employeeService = new EmployeeService(); } @ParameterizedTest @MethodSource("provideSalariesForBonusTest") void testCalculateBonus(double salary, double expectedBonusPercentage) { double actualBonus = employeeService.calculateBonus(salary); assertEquals(expectedBonusPercentage, actualBonus, "Bonus calculation is incorrect for salary: " + salary); } private static Object[][] provideSalariesForBonusTest() { return new Object[][] { {25000, 5}, {30000, 10}, {40000, 10}, {50000, 10}, {60000, 15}, {100000, 15} }; } } class EmployeeService { public double calculateBonus(double salary) { if (salary < 30000) return salary * 0.05; if (salary <= 50000) return salary * 0.10; return salary * 0.15; } }

Timeout Annotations

  • @Test(timeout = <time-in-milliseconds>) Specifies that the test should fail if it takes longer than the specified time.

For example,

@Test(timeout = 1000) void testCreateEmployeePerformance() { Employee newEmployee = new Employee(1, "Praveen Oruganti", "Engineering"); Mockito.when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(newEmployee); employeeService.createEmployee(newEmployee); }

Repetition Annotations

  • @RepeatedTest(value) Runs the same test multiple times (specified by value). Useful for stress testing or ensuring consistent behavior over multiple runs.

For example,

@RepeatedTest(5) void testCreateEmployeeRepeated() { Employee newEmployee = new Employee(1, "Praveen Oruganti", "Engineering"); Mockito.when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(newEmployee); Employee result = employeeService.createEmployee(newEmployee); assertNotNull(result); assertEquals("Praveen Oruganti", result.getName()); }

Display Name Annotation

  • @DisplayName Assigns a custom name to the test method. This is particularly useful for generating more readable test reports.
@DisplayName("Test creating an employee") @Test void testCreateEmployeeWithDisplayName() { Employee newEmployee = new Employee(1, "Praveen Oruganti", "Engineering"); Mockito.when(employeeRepository.save(Mockito.any(Employee.class))).thenReturn(newEmployee); Employee result = employeeService.createEmployee(newEmployee); assertNotNull(result); assertEquals("Praveen Oruganti", result.getName()); }

Junit 5 Assertions

  • assertEquals(expected, actual) Asserts that the expected and actual values are equal.

For example,

@Test void testEmployeeSalary() { Employee employee = new Employee(1, "Praveen Oruganti", "Engineering", 5000000); double expectedSalary = 5000000; double actualSalary = employee.getSalary(); assertEquals(expectedSalary, actualSalary, "The salary should be 5000000"); }
  • assertNotEquals(expected, actual) Asserts that the expected and actual values are not equal.

For example,

@Test void testEmployeeSalaryNotEqual() { Employee employee = new Employee(1, "Praveen Oruganti", "Engineering", 5000000); double wrongSalary = 6000000; double actualSalary = employee.getSalary(); assertNotEquals(wrongSalary, actualSalary, "The salary should not be 6000000"); }
  • assertTrue(condition) Asserts that the condition is true.

For example,

@Test void testIsEmployeeEligibleForBonus() { Employee employee = new Employee(1, "Praveen Oruganti", "Engineering", 5000000); boolean isEligible = employee.isEligibleForBonus(); assertTrue(isEligible, "Employee should be eligible for a bonus."); }
  • assertFalse(condition) Asserts that the condition is false.

For example,

@Test void testIsEmployeeOnLeave() { Employee employee = new Employee(1, "Kiran Badugu", "Marketing", 4000000); boolean onLeave = employee.isOnLeave(); assertFalse(onLeave, "Employee should not be on leave."); }
  • assertNull(value) Asserts that the value is null.

For example,

@Test void testGetEmployeeByIdNotFound() { EmployeeService employeeService = new EmployeeService(); Employee employee = employeeService.getEmployeeById(999); assertNull(employee, "The employee should not exist, so it should return null."); }
  • assertNotNull(value) Asserts that the value is not null.

For example,

@Test void testCreateEmployee() { EmployeeService employeeService = new EmployeeService(); Employee employee = employeeService.createEmployee("Praveen Oruganti", "Engineering", 5000000); assertNotNull(employee, "The employee should not be null after creation."); }
  • assertSame(expected, actual) Asserts that the expected and actual values refer to the same object(reference equality).

For example,

@Test void testSameEmployeeObject() { EmployeeService employeeService = new EmployeeService(); Employee employee1 = employeeService.getEmployeeById(1); Employee employee2 = employeeService.getEmployeeById(1); assertSame(employee1, employee2, "Both should refer to the same Employee object."); }
  • assertNotSame(expected, actual) Asserts that expected and actual values do not refer to the same object (reference inequality).

For example,

@Test void testDifferentEmployeeObjects() { EmployeeService employeeService = new EmployeeService(); Employee employee1 = employeeService.getEmployeeById(1); Employee employee2 = employeeService.getEmployeeById(2); assertNotSame(employee1, employee2, "Both should refer to different Employee objects."); }
  • assertArrayEquals(expected, actual) Asserts that the expected and actual arrays are equal (compares both content and length).

For example,

@Test void testEmployeeNamesArray() { String[] expectedEmployeeNames = {"Praveen Oruganti", "Kiran Badugu", "Praneeth Vishnubhotla"}; EmployeeService employeeService = new EmployeeService(); String[] actualEmployeeNames = employeeService.getAllEmployeeNames(); assertArrayEquals(expectedEmployeeNames, actualEmployeeNames, "The employee name arrays should be equal."); }
  • assertThrows(exception, executable) Asserts that the executable (typically a code block) throws an exception of the expected type.

For example,

@Test void testGetEmployeeByIdThrowsException() { EmployeeService employeeService = new EmployeeService(); assertThrows(EmployeeNotFoundException.class, () -> { employeeService.getEmployeeById(999); }, "Should throw EmployeeNotFoundException when employee is not found."); }

Setting Up JUnit in a Spring Boot Project

Add below dependency in pom.xml

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>

Mocking in Spring Boot Tests with Mockito

Mocking is a technique used to simulate external dependencies, such as a database or third-party service, to test the behavior of the class under test.

Mockito Annotations

  • @Mock Creates a mock instance of a class or interface. This is useful when you need to simulate the behavior of dependencies in your tests.
  • @InjectMocks Injects the mocks into the class under test. It's used to automatically inject mocked dependencies into the system under test.
  • @ExtendWith(MockitoExtension.class) Enables Mockito support in JUnit 5, handling mock initialization and dependency injection automatically.

Let's write detailed JUnit tests for the Employee Management Service that we developed using Spring Data Jpa.

Controller Test Class

package com.praveen.employee.controller; import com.fasterxml.jackson.databind.ObjectMapper; import com.praveen.employee.bo.EmployeeRequest; import com.praveen.employee.bo.EmployeeResponse; import com.praveen.employee.bo.EmployeeResponseData; import com.praveen.employee.entity.Employee; import com.praveen.employee.service.EmployeeManagementService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; 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 org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.util.List; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @ExtendWith(MockitoExtension.class) @DisplayName("EmployeeManagementController Tests") class EmployeeManagementControllerTest { @Mock private EmployeeManagementService employeeManagementService; @InjectMocks private EmployeeManagementController employeeManagementController; private MockMvc mockMvc; private ObjectMapper objectMapper; @BeforeEach void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(employeeManagementController).build(); objectMapper = new ObjectMapper(); } @Test @DisplayName("Test fetching all employees") void testFetchAllEmployees() throws Exception { Employee employee1 = new Employee(1L, "Praveen", "Solution Architect", 5000000L, "Hyderabad"); Employee employee2 = new Employee(2L, "Krishna", "Devops Manager", 3000000L, "California"); List<Employee> employees = List.of(employee1, employee2); when(employeeManagementService.fetchAllEmployees()).thenReturn(employees); mockMvc.perform(get("/api/v1/employees").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(jsonPath("$.length()").value(2)).andExpect(jsonPath("$[0].name").value("Praveen")).andExpect(jsonPath("$[1].name").value("Krishna")).andExpect(jsonPath("$[0].salary").value(5000000)).andExpect(jsonPath("$[1].salary").value(3000000)); verify(employeeManagementService, times(1)).fetchAllEmployees(); } @Test @DisplayName("Test get employee by ID") void testGetEmployeeById() throws Exception { EmployeeResponse employeeResponse = new EmployeeResponse("success", "transactionId", new EmployeeResponseData(1L, "Praveen", "Solution Architect", 5000000L, "Hyderabad"), null); when(employeeManagementService.getEmployeeById(1L)).thenReturn(employeeResponse); mockMvc.perform(get("/api/v1/employees/1").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(jsonPath("$.data.name").value("Praveen")).andExpect(jsonPath("$.data.salary").value(5000000)); verify(employeeManagementService, times(1)).getEmployeeById(1L); } @Test @DisplayName("Test create employee") void testCreateEmployee() throws Exception { EmployeeRequest employeeRequest = new EmployeeRequest("txn123", "Praveen", "Solution Architect", 5000000L, "Hyderabad"); EmployeeResponse employeeResponse = new EmployeeResponse("success", "txn123", new EmployeeResponseData(1L, "Praveen", "Solution Architect", 5000000L, "Hyderabad"), null); when(employeeManagementService.createEmployee(any(EmployeeRequest.class))).thenReturn(employeeResponse); mockMvc.perform(post("/api/v1/employees").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(employeeRequest))).andExpect(status().isCreated()).andExpect(jsonPath("$.data.name").value("Praveen")).andExpect(jsonPath("$.data.salary").value(5000000)); verify(employeeManagementService, times(1)).createEmployee(any(EmployeeRequest.class)); } @Test @DisplayName("Test update employee by ID") void testUpdateEmployeeById() throws Exception { EmployeeRequest employeeRequest = new EmployeeRequest("txn123", "Praveen", "Solution Architect", 6000000L, "Hyderabad"); EmployeeResponse employeeResponse = new EmployeeResponse("success", "txn123", new EmployeeResponseData(1L, "Praveen", "Solution Architect", 6000000L, "Hyderabad"), null); when(employeeManagementService.updateEmployeeById(any(EmployeeRequest.class), anyLong())).thenReturn(employeeResponse); mockMvc.perform(put("/api/v1/employees/1").contentType(MediaType.APPLICATION_JSON).content(objectMapper.writeValueAsString(employeeRequest))).andExpect(status().isOk()).andExpect(jsonPath("$.data.name").value("Praveen")).andExpect(jsonPath("$.data.salary").value(6000000)); verify(employeeManagementService, times(1)).updateEmployeeById(any(EmployeeRequest.class), anyLong()); } @Test @DisplayName("Test delete employee by ID") void testDeleteEmployeeById() throws Exception { EmployeeResponse employeeResponse = new EmployeeResponse("success", null, new EmployeeResponseData(1L, null, null, null, null), null); when(employeeManagementService.deleteEmployeeById(1L)).thenReturn(employeeResponse); mockMvc.perform(delete("/api/v1/employees/1").contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); verify(employeeManagementService, times(1)).deleteEmployeeById(1L); } @Test @DisplayName("Test filterEmployees with filters applied") void testFilterEmployees_withValidFilters() throws Exception { Employee employee1 = new Employee(1L, "Praveen", "Solution Architect", 5000000L, "Hyderabad"); when(employeeManagementService.getFilteredEmployees("Praveen", null, null)) .thenReturn(List.of(employee1)); mockMvc.perform(get("/api/v1/employees/filter") .param("name", "Praveen")) .andExpect(status().isOk()); verify(employeeManagementService, times(1)).getFilteredEmployees("Praveen", null, null); } @Test @DisplayName("Test filterEmployees without any filters applied") void testFilterEmployees_withNoMatchingResults() throws Exception { when(employeeManagementService.getFilteredEmployees("NonExistent", null, null)) .thenReturn(List.of()); mockMvc.perform(get("/api/v1/employees/filter") .param("name", "NonExistent")) .andExpect(status().isOk()); verify(employeeManagementService, times(1)).getFilteredEmployees("NonExistent", null, null); } @Test @DisplayName("Test filterEmployees with multiple filters applied") void testFilterEmployees_withMultipleFilters() throws Exception { Employee employee1 = new Employee(1L, "Praveen", "Solution Architect", 5000000L, "Hyderabad"); when(employeeManagementService.getFilteredEmployees("Praveen", "Hyderabad", 5000000L)) .thenReturn(List.of(employee1)); mockMvc.perform(get("/api/v1/employees/filter") .param("name", "Praveen") .param("location", "Hyderabad") .param("salary", "5000000")) .andExpect(status().isOk()); verify(employeeManagementService, times(1)).getFilteredEmployees("Praveen", "Hyderabad", 5000000L); } }

Service Test Class

package com.praveen.employee.service.impl; import com.praveen.employee.bo.EmployeeRequest; import com.praveen.employee.bo.EmployeeResponse; import com.praveen.employee.common.Constants; import com.praveen.employee.entity.Employee; import com.praveen.employee.exception.EmployeeNotFoundException; import com.praveen.employee.repository.EmployeeRepository; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; 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 org.springframework.data.jpa.domain.Specification; import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) @DisplayName("EmployeeManagementServiceImpl Unit Tests") class EmployeeManagementServiceImplTest { @Mock private EmployeeRepository employeeRepository; @InjectMocks private EmployeeManagementServiceImpl employeeManagementService; private Employee employee1; private Employee employee2; @BeforeEach void setUp() { employee1 = new Employee(1L, "Praveen Oruganti", "Solution Architect", 550000L, "Hyderabad"); employee2 = new Employee(2L, "Praneeth Vishnubhotla", "Devops Manager", 450000L, "London"); } @Test @DisplayName("Test fetch all employees") void testFetchAllEmployees() { when(employeeRepository.findAll()).thenReturn(List.of(employee1, employee2)); var employees = employeeManagementService.fetchAllEmployees(); assertNotNull(employees); assertEquals(2, employees.size()); assertEquals("Praveen Oruganti", employees.get(0).getName()); assertEquals("Praneeth Vishnubhotla", employees.get(1).getName()); verify(employeeRepository, times(1)).findAll(); } @Test @DisplayName("Test get employee by name") void testGetEmployeeByName() { when(employeeRepository.findByNameContaining("Praveen")).thenReturn(List.of(employee1)); var employees = employeeManagementService.getEmployeeByName("Praveen"); assertNotNull(employees); assertEquals(1, employees.size()); assertEquals("Praveen Oruganti", employees.get(0).getName()); verify(employeeRepository, times(1)).findByNameContaining("Praveen"); } @Test @DisplayName("Test get employee by location") void testGetEmployeeByLocation() { when(employeeRepository.findByLocationContainingOrderByNameAsc("Hyderabad")).thenReturn(List.of(employee1)); var employees = employeeManagementService.getEmployeeByLocation("Hyderabad"); assertNotNull(employees); assertEquals(1, employees.size()); assertEquals("Hyderabad", employees.get(0).getLocation()); verify(employeeRepository, times(1)).findByLocationContainingOrderByNameAsc("Hyderabad"); } @Test @DisplayName("Test get employee by ID - Success") void testGetEmployeeById_Success() throws EmployeeNotFoundException { when(employeeRepository.findById(1L)).thenReturn(Optional.of(employee1)); EmployeeResponse response = employeeManagementService.getEmployeeById(1L); assertNotNull(response); assertEquals(Constants.SUCCESS, response.status()); assertEquals(employee1.getId(), response.data().id()); verify(employeeRepository, times(1)).findById(1L); } @Test @DisplayName("Test get employee by ID - Employee Not Found") void testGetEmployeeById_EmployeeNotFound() { when(employeeRepository.findById(1L)).thenReturn(Optional.empty()); assertThrows(EmployeeNotFoundException.class, () -> employeeManagementService.getEmployeeById(1L)); verify(employeeRepository, times(1)).findById(1L); } @Test @DisplayName("Test create employee") void testCreateEmployee() { EmployeeRequest employeeRequest = new EmployeeRequest("trans123", "Praveen", "Solution Architect", 100000L, "Hyderabad"); when(employeeRepository.save(any(Employee.class))).thenReturn(employee1); EmployeeResponse response = employeeManagementService.createEmployee(employeeRequest); assertNotNull(response); assertEquals(Constants.SUCCESS, response.status()); assertEquals("Praveen", response.data().name()); verify(employeeRepository, times(1)).save(any(Employee.class)); } @Test @DisplayName("Test update employee by ID - Success") void testUpdateEmployeeById_Success() throws EmployeeNotFoundException { EmployeeRequest employeeRequest = new EmployeeRequest("trans123", "Praveen", "Solution Architect", 100000L, "Hyderabad"); when(employeeRepository.findById(1L)).thenReturn(Optional.of(employee1)); when(employeeRepository.save(any(Employee.class))).thenReturn(employee1); EmployeeResponse response = employeeManagementService.updateEmployeeById(employeeRequest, 1L); assertNotNull(response); assertEquals(Constants.SUCCESS, response.status()); assertEquals("Praveen", response.data().name()); verify(employeeRepository, times(1)).findById(1L); verify(employeeRepository, times(1)).save(any(Employee.class)); } @Test @DisplayName("Test update employee by ID - Employee Not Found") void testUpdateEmployeeById_EmployeeNotFound() { EmployeeRequest employeeRequest = new EmployeeRequest("trans123", "Praveen", "Solution Architect", 100000L, "Hyderabad"); when(employeeRepository.findById(1L)).thenReturn(Optional.empty()); assertThrows(EmployeeNotFoundException.class, () -> employeeManagementService.updateEmployeeById(employeeRequest, 1L)); verify(employeeRepository, times(1)).findById(1L); } @Test @DisplayName("Test delete employee by ID") void testDeleteEmployeeById() { doNothing().when(employeeRepository).deleteById(1L); EmployeeResponse response = employeeManagementService.deleteEmployeeById(1L); assertNotNull(response); assertEquals(Constants.SUCCESS, response.status()); verify(employeeRepository, times(1)).deleteById(1L); } @Test void testGetFilteredEmployees_withNameFilter() { when(employeeRepository.findAll(any(Specification.class))) .thenReturn(List.of(employee1)); List<Employee> employees = employeeManagementService.getFilteredEmployees("Praveen", null, null); assertEquals(1, employees.size()); assertEquals("Praveen Oruganti", employees.get(0).getName()); } @Test void testGetFilteredEmployees_withLocationFilter() { when(employeeRepository.findAll(any(Specification.class))) .thenReturn(List.of(employee2)); List<Employee> employees = employeeManagementService.getFilteredEmployees(null, "London", null); assertEquals(1, employees.size()); assertEquals("London", employees.get(0).getLocation()); } @Test void testGetFilteredEmployees_withSalaryFilter() { when(employeeRepository.findAll(any(Specification.class))) .thenReturn(List.of(employee1)); List<Employee> employees = employeeManagementService.getFilteredEmployees(null, null, 550000L); assertEquals(1, employees.size()); assertEquals(550000L, employees.get(0).getSalary()); } @Test void testGetFilteredEmployees_withAllFilters() { when(employeeRepository.findAll(any(Specification.class))) .thenReturn(List.of(employee2)); List<Employee> employees = employeeManagementService.getFilteredEmployees("Praneeth", "London", 450000L); assertEquals(1, employees.size()); assertEquals("Praneeth Vishnubhotla", employees.get(0).getName()); assertEquals("London", employees.get(0).getLocation()); assertEquals(450000L, employees.get(0).getSalary()); } @Test void testGetFilteredEmployees_noMatchingCriteria() { when(employeeRepository.findAll(any(Specification.class))) .thenReturn(List.of()); List<Employee> employees = employeeManagementService.getFilteredEmployees("NonExistent", "Unknown", 100000L); assertTrue(employees.isEmpty()); } }