当我为服务层类运行单元测试时,我收到了一个烦人的NPE。 此类使用MapStruct自动生成的映射器,该映射器内部使用另一个映射器(请参见Mapper批注中的“ uses”属性):
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;
}
}
我的UnitTest是:
@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
...
}
NPE通过此行引发:
candidateDTO.setUser( userMapper.toDto( candidate.getUser() ) );
在CandidateMapperImpl中,因为候选人MapperImpl中的userMapperImpl实例(变量名称userMapper)为空。
当我使用spring-boot:run启动应用程序但仅使用UnitTest启动应用程序时不会发生
任何想法或建议将不胜感激。让我知道您是否需要更多信息或详细信息,或者我错过了重要事项。
谢谢
编辑:
我修复了使用@Autowired并使用此类注释来注释Mapper的问题:
@SpringBootTest(classes = {CandidateMapperImpl.class, UserMapperImpl.class, UserRolesMapperImpl.class,
CandidateMapper.class, UserMapper.class, UserRolesMapper.class})
概括:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {SubMapperImpl.class, SubMapper.class,
OtherSubMapper.class, OtherSubMapperImpl.class...})
public class ServiceTest {
@Autowired
Mapper mapper;
...
}
答案 0 :(得分:0)
基于带有when 'C' then
注释的测试(这是为了在测试中添加spring上下文),您似乎真的不想嘲笑嵌套的映射器,对吗?如果您希望使用Spring上下文,只需将其映射器及其所有嵌套的映射器自动布线。参见:https://stackoverflow.com/a/48503708/1098564
下面(使用了Mockito ...对MockBean还不熟悉),将为您提供一个“夹具”(即CandidateService),并注入所有嵌套的映射器(通过@Autowired),其余的依赖项都被模拟掉了。 MockBean可能有一种更干净的方法,但是目前没有时间对其进行全面测试。
cg$rec_its.ite_id := 63;