Service Layer Unit Testing
Relevant source files
The following files were used as context for generating this wiki page:
- Part1/API/src/test/java/com/example/api/DepartmentServiceTest.java
- Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java
- Part1/API/src/main/java/com/example/api/service/DepartmentService.java
- Part1/API/src/main/java/com/example/api/service/EmployeeService.java
- Part1/API/src/test/java/com/example/api/EmployeeControllerTest.java
Service Layer Unit Testing in this project ensures the integrity of business logic governing employee management, department administration, and promotion eligibility. These tests are isolated from external dependencies like databases by utilizing Mockito to mock repository layers, focusing strictly on the functional correctness of service methods.
The testing suite validates critical constraints, such as ensuring department budgets are positive and verifying that employees meet specific tenure requirements before being eligible for salary increases and role upgrades.
Sources: Part1/API/src/test/java/com/example/api/DepartmentServiceTest.java, Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java
Testing Architecture and Configuration
The project utilizes JUnit 5 and Mockito for unit testing. The @ExtendWith(MockitoExtension.class) annotation is employed to enable mock injections. Services are tested as "SUT" (System Under Test) while their corresponding JPA repositories are mocked to simulate database interactions without requiring a running environment.
Key Components
| Component | Responsibility in Testing |
|---|---|
@Mock | Creates a simulated instance of a Repository (e.g., EmployeeRepository). |
@InjectMocks | Injects the mocked repositories into the Service instance being tested. |
when(...).thenReturn(...) | Configures behavior for mock objects to return specific data. |
assertThrows | Validates that business logic correctly rejects invalid inputs with exceptions. |
Sources: Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java:15-25, Part1/API/src/test/java/com/example/api/DepartmentServiceTest.java:15-22
Dependency Injection Flow
The following diagram illustrates how mocks are injected into the service layer during a test execution.
This diagram shows the relationship between the test class, mocks, and the service being tested.
Sources: Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java:18-24
Employee Business Logic Testing
The EmployeeServiceTest focuses heavily on the promoteEmployee logic. This logic includes complex conditions regarding start dates and salary calculations.
Promotion Eligibility Rules
- Existence Check: The system must verify the employee exists in the database.
- Tenure Requirement: Employees must have started more than 6 months ago to be eligible.
- Salary Missing: Tests ensure the system handles cases where salary data might be null.
Sources: Part1/API/src/main/java/com/example/api/service/EmployeeService.java:51-64
Promotion Flow Analysis
The sequence diagram demonstrates the conditional logic and repository interactions verified by unit tests.
Sources: Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java:42-69, Part1/API/src/main/java/com/example/api/service/EmployeeService.java:51-71
Department Validation Testing
Testing for DepartmentService ensures that organizational constraints are enforced during the creation of new departments. Specifically, it validates the budget field.
Validation Logic
The service layer enforces that a budget cannot be null or less than or equal to zero. If these conditions are met, the test verifies that an IllegalArgumentException is thrown with the message "Budget must be positive".
Sources: Part1/API/src/main/java/com/example/api/service/DepartmentService.java:25-28, Part1/API/src/test/java/com/example/api/DepartmentServiceTest.java:25-35
Department Creation Test Scenarios
| Scenario | Input | Expected Outcome |
|---|---|---|
| Negative Budget | -1000 | RuntimeException ("Budget must be positive") |
| Valid Budget | 10000 | Department object saved and returned |
Sources: Part1/API/src/test/java/com/example/api/DepartmentServiceTest.java:25-48
Implementation Details
Mocking Example: Employee Promotion
The following snippet shows how the service layer logic is exercised in a test to ensure a 10% salary increase is correctly calculated and applied.
@Test
void promoteEmployee_shouldIncreaseSalary_ifEligible() {
Employee employee = new Employee();
employee.setId(1L);
employee.setStartDate(LocalDate.now().minusMonths(8)); // Eligible (>6 months)
employee.setSalary(30000);
when(employeeRepository.findById(1L)).thenReturn(Optional.of(employee));
when(employeeRepository.save(employee)).thenReturn(employee);
Employee updatedEmployee = employeeService.promoteEmployee(1L);
assertEquals(33000, updatedEmployee.getSalary()); // 30000 * 1.10
}
Sources: Part1/API/src/test/java/com/example/api/EmployeeServiceTest.java:56-70
Conclusion
Service Layer Unit Testing serves as the primary verification mechanism for the core business rules of the SafeDispatch API. By mocking the repository layer, the tests provide fast, reliable feedback on the correctness of salary calculations, role updates, and budget validations, ensuring that data integrity is maintained before any persistence occurs.