I'm receiving an annoying NPE when I run a Unit Test for a service layer class. This class use an autogenerated mapper from MapStruct, which inside use another mapper (see in the Mapper annotation the "uses" attribute):
Mapper(componentModel = "spring", uses = {UserMapper.class})
public interface CandidateMapper extends EntityMapper<CandidateDTO, Candidate> {
@Mapping(target = "createdBy", ignore = true)
@Mapping(target = "createdDate", ignore = true)
@Mapping(target = "lastModifiedBy", ignore = true)
@Mapping(target = "lastModifiedDate", ignore = true)
@Mapping(target = "applications", ignore = true)
Candidate toEntity(CandidateDTO candidateDTO);
default Candidate fromId(Long id) {
if (id == null) {
return null;
}
Candidate candidate = new Candidate();
candidate.setId(id);
return candidate;
}
}
My UnitTest is:
@RunWith(SpringRunner.class)
public class CandidateServiceTest {
private CandidateService candidateService;
@MockBean
private UserRepository userRepository;
@MockBean
CandidateRepository candidateRepository;
@MockBean
UserDetailsService userDetailsService;
CandidateMapper candidateMapper = Mappers.getMapper(CandidateMapper.class);
UserMapper userMapper = Mappers.getMapper(UserMapper.class);
@Before
public void init() {
this.candidateService = new CandidateService(candidateRepository,
candidateMapper, userDetailsService, userMapper);
}
@Test
@WithMockUser(authorities = RolesConstants.ADMIN)
public void givenUser_whenGetCandidateOrCreateForLogin_create() {
// Pre-conditions
...
// Mocking data
...
// Given
given(userRepository.findOneByLogin(eq(login)))
.willReturn(Optional.of(user));
given(candidateRepository.findOneByUserLogin(eq(login)))
.willReturn(Option.of(candidate));
// When
CandidateDTO candidateDTO = candidateService.getCandidateOrCreateForLogin(login);
// Then
...
}
The NPE is raised by this line:
candidateDTO.setUser( userMapper.toDto( candidate.getUser() ) );
in the CandidateMapperImpl because the userMapperImpl instance (variable name userMapper) inside the candidateMapperImpl is null.
This does not happen when I launch the application with spring-boot:run but only with the UnitTest
Any ideas or suggest would be appreciated. Let me know if you'd need more infos or details or if I missed something important.
Thanks
EDIT:
I fixed the issues annotating the Mapper with @Autowired and using this class annotation:
@SpringBootTest(classes = {CandidateMapperImpl.class, UserMapperImpl.class, UserRolesMapperImpl.class,
CandidateMapper.class, UserMapper.class, UserRolesMapper.class})
To generalize:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {SubMapperImpl.class, SubMapper.class,
OtherSubMapper.class, OtherSubMapperImpl.class...})
public class ServiceTest {
@Autowired
Mapper mapper;
...
}