英文:
Mapstruct mapper using mockito returning null object inspite being mocked
问题
I have a mapper which converts one type to another type. I am writing a unit test for the business (service layer) where I am autowiring the mapper. In the corresponding Junit of the service class, I am mocking the mapper using the Mock annotation. While debugging, I could see that the mapper is getting mocked, but after debugging goes to the service layer, the mocked mapper method is returning a 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;
// Rest of the service class code...
}
JUnit class using Mockito:
@ExtendWith(MockitoExtension.class)
class HolidaymanagementApplicationTests {
@Mock
HolidayRepo holidayRepo;
@Mock
EmployeeHolidayRepo employeeHolidayRepo;
@Mock
EmployeeHolidayMapper employeeHolidayMapper;
@InjectMocks
EmployeeHolidayService employeeHolidayService;
// Rest of the JUnit test code...
}
In the above code, while debugging, I could see that the mapper is mocked. Now when the implementation goes to the service class from the assertEquals statement, the EmployeeHolidayEntity
object fetched through the mapper is returning null.
When running the code as a Spring Boot application, the mapper is working fine and 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;
}
英文:
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;
}
答案1
得分: 1
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 actual execution is a few milliseconds 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 don't need mocking. You then don't have to call when(
on mappers in your tests.
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论