I have a mapper which converts one type to another type. I am writing a unit test forbusiness (service layer) where I am autowiring mapper. In the corresponding Junit of service class I am mocking mapper using Mock annotation. While debugging I could see that mapper is getting mocked but after debugging goes to service layer the mocked mapper method is returning null object
Mapper class
@Mapper(componentModel = "spring")
public interface EmployeeHolidayMapper {
@Mapping(target = "employeeEntity.empId",source = "employeeHolidayDto.empId")
@Mapping(target = "leaveStartDate",expression = "java(LocalDate.parse(employeeHolidayDto"
+ ".getEmpLeaveStartDate().toString(),dateTimeFormatter))")
@Mapping(target = "leaveEndDate",expression = "java(LocalDate.parse(employeeHolidayDto"
+ ".getEmpLeaveEndDate().toString(),dateTimeFormatter))")
public EmployeeHolidayEntity employeeHoliDayDtoToEmployeeHolidayEntity(EmployeeHolidayDto
employeeHolidayDto,LocalDate localDate,DateTimeFormatter dateTimeFormatter);
Service class
@Service
@RequiredArgsConstructor
public class EmployeeHolidayService {
private final HolidayRepo holidayRepo;
private final EmployeeHolidayRepo employeeHolidayRepo;
private final EmployeeHolidayMapper employeeHolidayMapper;
public Mono<Integer> saveEmployeeHolidayData(EmployeeHolidayDto employeeHolidayDto){
return Optional.ofNullable(employeeHolidayDto)
.filter(dto->dto.getEmpLeaveEndDate()!=null && dto.getEmpLeaveStartDate() != null
&& dto.getEmpLeaveStartDate() > 0 && dto.getEmpLeaveEndDate() > 0 && dto.getEmpLeaveEndDate()
.compareTo(dto.getEmpLeaveStartDate()) >=0)
.map(dto->{
EmployeeHolidayEntity employeeHolidayEntity = employeeHolidayMapper
.employeeHoliDayDtoToEmployeeHolidayEntity(dto, LocalDate.now(),
DateTimeFormatter.BASIC_ISO_DATE);
int diffOfDays = employeeHolidayEntity.getLeaveEndDate().getDayOfYear()
- employeeHolidayEntity.getLeaveStartDate().getDayOfYear();
int noOfLeavesLeft = holidayRepo.getNoofLeavesLeft(dto.getEmpId()) - (diffOfDays);
if (noOfLeavesLeft > 0) {
int updatedRows = holidayRepo.updateNoLeaveDays(dto.getEmpId(), noOfLeavesLeft);
if (updatedRows > 0) {
EmployeeHolidayEntity employeeHolidayEntitySaved = employeeHolidayRepo
.saveAndFlush(employeeHolidayEntity);
if (employeeHolidayEntitySaved.getEmployeeHolidayId() > 0) {
return Mono.just(updatedRows);
} else {
return Mono.just(0);
}
} else {
return Mono.just(0);
}
}
else {
return Mono.just(0);
}
})
.orElse(null);
}
Junit class using mockito
@ExtendWith(MockitoExtension.class)
class HolidaymanagementApplicationTests {
@Mock
HolidayRepo holidayRepo;
@Mock
EmployeeHolidayRepo employeeHolidayRepo;
@Mock
EmployeeHolidayMapper employeeHolidayMapper;
@InjectMocks
EmployeeHolidayService employeeHolidayService;
@Test
void testPostrequest() {
String startDate = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
String endDate = LocalDate.now().plusDays(2).format(DateTimeFormatter.BASIC_ISO_DATE);
EmployeeHolidayDto employeeHolidayDto = new EmployeeHolidayDto(1, Integer.parseInt(startDate),
Integer.parseInt(endDate));
EmployeeEntity employeeEntity = new EmployeeEntity(1, null, null, null, null);
EmployeeHolidayEntity employeeHolidayEntity = new EmployeeHolidayEntity(1,
LocalDate.parse(startDate, DateTimeFormatter.BASIC_ISO_DATE),
LocalDate.parse(endDate, DateTimeFormatter.BASIC_ISO_DATE), employeeEntity);
when(employeeHolidayMapper.employeeHoliDayDtoToEmployeeHolidayEntity(employeeHolidayDto, LocalDate.now(),
DateTimeFormatter.BASIC_ISO_DATE)).thenReturn(employeeHolidayEntity);
HolidayEntity holidayEntity = new HolidayEntity(1, 10, employeeEntity);
when(holidayRepo.getNoofLeavesLeft(1)).thenReturn(10);
when(holidayRepo.updateNoLeaveDays(1, 8)).thenReturn(1);
EmployeeHolidayEntity employeeHolidayDbEntity = new EmployeeHolidayEntity(1,
employeeHolidayEntity.getLeaveStartDate(), employeeHolidayEntity.getLeaveEndDate(), employeeEntity);
when(employeeHolidayRepo.saveAndFlush(employeeHolidayEntity)).thenReturn(employeeHolidayDbEntity);
assertEquals(employeeHolidayService.saveEmployeeHolidayData(employeeHolidayDto).block(),
1);
In the above code while debugging I could see that mapper is mocked. Now when implementation goes to service class from asserEquals statement. The EmployeeHolidayEntity object fetched through mapper is returning null.
When running code a spring boot application mapper is working fine and is returning the object.
Below is my entity class.
@Entity
@Table(name = "empl_holiday_tbl")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@EqualsAndHashCode
public class EmployeeHolidayEntity implements Serializable{
/**
*
*/
private static final long serialVersionUID = 2429371741034836686L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", columnDefinition = "INT UNSIGNED AUTO_INCREMENT")
private Integer employeeHolidayId;
@Column(name = "startDate", columnDefinition = "DATE NOT NULL")
private LocalDate leaveStartDate;
@Column(name = "endDate", columnDefinition = "DATE NOT NULL")
private LocalDate leaveEndDate;
@ManyToOne
@JoinColumn(name = "empId",nullable = false,columnDefinition = "INT UNSIGNED")
private EmployeeEntity employeeEntity;
}
Your problem is that your mock when(
never matches the execution.
when(employeeHolidayMapper.employeeHoliDayDtoToEmployeeHolidayEntity(employeeHolidayDto, LocalDate.now(),
DateTimeFormatter.BASIC_ISO_DATE)).thenReturn(employeeHolidayEntity);
contains a "LocalDate.now()" your actuall execution is a few milisenconds later. It will therefore be different and the when(
never is used. The fallback of a mocked class is to return null which is your result.
To verify my suspicion you could try to change your code to
when(employeeHolidayMapper.employeeHoliDayDtoToEmployeeHolidayEntity(any(), any(),
any())).thenReturn(employeeHolidayEntity);
your return value should now be correct.
Furthermore i would suggest changing your test setup. For Mockito tests with Mapstruct I usually use
@Spy
EmployeeHolidayMapper employeeHolidayMapper = Mappers.get(EmployeeHolidayMapper .class);
@InjectMocks
EmployeeHolidayService employeeHolidayService;
this way you get the real mapper since mapping is something that usually dont need mocking. You then don´t have to call when(
on mappers in your tests.