今天在别人写了一半的单元测试基础上准备完成剩余的,于是写了如下测试代码:
@Mock
private FcoCertMapper fcoCertMapper;
PowerMockito.when(fcoCertMapper.selectCertInfoList(Mockito.any(CertQueryDto.class))).thenReturn(infoVos);
certManageServiceImpl.selectCertInfoList(dto);
执行后报错:
打断点发现fcoCertMapper报了空指针
fcoCertMapper已经使用@Mock了,没问题,问题原来是certManageServiceImpl没有使用@InjectMocks,这样fcoCertMapper就为null了。
仔细看了下,原来这个单元测试类有特殊性,该类在方法前面有静态类调用了静态方法。如果使用@InjectMocks,那么运行测试后,实例化certManageServiceImpl,首先就执行到静态类调用静态方法,然而这里还没有Mock,所以肯定会报错。
@Component
public class CertManageServiceImpl implements CertManageService {
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CertManageServiceImpl.class);
@Autowired
RsfServiceCommonClient rsfServiceCommonClient;
ServiceAgent certManageServiceRSF = ServiceLocator.getServiceAgent(RsfAgentEnum.CERT_MANAGE_AGENT.getContract(),
RsfAgentEnum.CERT_MANAGE_AGENT.getImplCode(),false);
}
综上所述,这里不使用@InjectMocks,而是先mock静态类和静态方法。然后再使用Whitebox.setInternalState帮助设置fcoCertMapper实例,这样整个单元测试就运行通过了。
@Before
public void setUp() throws Exception {
ConsumerContext consumerContext = mock(ConsumerContext.class);
mockStatic(ConsumerContextFactory.class);
when(ConsumerContextFactory.getConsumerContext(any(String.class))).thenReturn(consumerContext);
mockStatic(ServiceLocator.class);
when(ServiceLocator.getServiceAgent(any(String.class), any(String.class))).thenReturn(serviceAgent);
certManageServiceImpl = new CertManageServiceImpl();
Whitebox.setInternalState(certManageServiceImpl, "rsfServiceCommonClient", rsfServiceCommonClient);
Whitebox.setInternalState(certManageServiceImpl, "fcoCertRecordMapper", fcoCertRecordMapper);
Whitebox.setInternalState(certManageServiceImpl, "fcoCertMapper", fcoCertMapper);
}
附完整单元测试代码:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ConsumerContextFactory.class, ServiceLocator.class})
@SuppressStaticInitializationFor({"com.suning.rsf.consumer.ServiceAgent","com.suning.rsf.consumer.ServiceLocator"})
public class CertManageServiceImplTest {
CertManageServiceImpl certManageServiceImpl;
@Mock
RsfServiceCommonClient rsfServiceCommonClient;
@Mock
ServiceAgent serviceAgent;
@Mock
FcoCertRecordMapper fcoCertRecordMapper;
@Mock
private FcoCertMapper fcoCertMapper;
@Before
public void setUp() throws Exception {
ConsumerContext consumerContext = mock(ConsumerContext.class);
mockStatic(ConsumerContextFactory.class);
when(ConsumerContextFactory.getConsumerContext(any(String.class))).thenReturn(consumerContext);
mockStatic(ServiceLocator.class);
when(ServiceLocator.getServiceAgent(any(String.class), any(String.class))).thenReturn(serviceAgent);
certManageServiceImpl = new CertManageServiceImpl();
Whitebox.setInternalState(certManageServiceImpl, "rsfServiceCommonClient", rsfServiceCommonClient);
Whitebox.setInternalState(certManageServiceImpl, "fcoCertRecordMapper", fcoCertRecordMapper);
Whitebox.setInternalState(certManageServiceImpl, "fcoCertMapper", fcoCertMapper);
}
@After
public void tearDown() throws Exception {
}
@Test(expected = AppException.class)
public void certApply() throws Exception {
CertRecordDto dto = new CertRecordDto();
PowerMockito.when(rsfServiceCommonClient.rsfInvoke(Mockito.any(ServiceAgent.class),Mockito.anyString(),Mockito.anyMap())).thenThrow(new TimeoutException());
certManageServiceImpl.certApply(dto);
}
@Test
public void selectCertInfoListTest(){
CertQueryDto dto = new CertQueryDto();
dto.setSerialNoStr("1");
dto.setCertStatus("01");
dto.setEndTime("2019-02-02");
List<CertInfoVo> infoVos = new ArrayList<>();
CertInfoVo certInfoVo = new CertInfoVo();
certInfoVo.setId(1L);
certInfoVo.setCertStatus("01");
infoVos.add(certInfoVo);
PowerMockito.when(fcoCertMapper.selectCertInfoList(Mockito.any(CertQueryDto.class))).thenReturn(infoVos);
certManageServiceImpl.selectCertInfoList(dto);
}
}
逻辑代码:
@Component
public class CertManageServiceImpl implements CertManageService {
/**
* 日志
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CertManageServiceImpl.class);
@Autowired
RsfServiceCommonClient rsfServiceCommonClient;
ServiceAgent certManageServiceRSF = ServiceLocator.getServiceAgent(RsfAgentEnum.CERT_MANAGE_AGENT.getContract(),
RsfAgentEnum.CERT_MANAGE_AGENT.getImplCode(),false);
@Autowired
FcoCertRecordMapper fcoCertRecordMapper;
@Autowired
private FcoCertMapper fcoCertMapper;
@Override
public List<CertInfoVo> selectCertInfoList(CertQueryDto dto) {
if (StringUtils.isNotEmpty(dto.getSerialNoStr())) {
dto.setSerialNo(Integer.parseInt(dto.getSerialNoStr()));
}
String endtime = dto.getEndTime();
if (StringUtils.isNotEmpty(endtime)) {
DateTimeFormatter df = DateTimeFormat.forPattern(DateConstant.DATEFORMATE_YYYY_MM_DD);
Date dateTime = df.parseDateTime(endtime).toDate();
String et = DateUtils.formatDate(DateUtils.addDate(dateTime, 1), DateConstant.DATEFORMATE_YYYY_MM_DD);
dto.setEndTime(et);
}
List<CertInfoVo> certDtos = fcoCertMapper.selectCertInfoList(dto);
for (CertInfoVo certDto:certDtos
) {
certDto.setCertStatus(CertStatusEnum.getDescriptionFromCode(certDto.getCertStatus()));
}
return certDtos;
}
@Override
public CertResult certApply(CertRecordDto certRecordDto) {
SdcReqDto sdcReqDto = buildSdcReqDto(certRecordDto);
LOGGER.info("cert apply.start, request:{}", sdcReqDto);
Map<String, Object> result;
try {
result = (Map<String, Object>) rsfServiceCommonClient.rsfInvoke(certManageServiceRSF,
RsfMethodEnum.CERT_MANAGE_AGENT_certApply.getMethod(), BeanToMapUtils.bean2Map(sdcReqDto));
} catch (TimeoutException ex) {
LOGGER.error("certApply调用{}时超时异常,ex:{}", ex);
throw new AppException(CoreErrorCode.RSF_TIME_OUT_FAILURE, CoreErrorCode.RSF_TIME_OUT_FAILURE_CN);
} catch (RSFException ex) {
LOGGER.error("certApply调用{}时RSF异常,ex:{}", ex);
throw new AppException(CoreErrorCode.RSF_EXCEPTION_FAILURE, CoreErrorCode.RSF_EXCEPTION_FAILURE_CN);
} catch (Exception exc) {
LOGGER.error("certApply调用{}时异常,ex:{}", exc);
throw new AppException(CoreErrorCode.OTHER_EXCEPTION_FAILURE, CoreErrorCode.OTHER_EXCEPTION_FAILURE_CN);
}
checkSuccess(result, ReturnCode.HANDLE_SUCCESS);
LOGGER.info("cert apply.end, response:{}", result);
SdcResDto sdcResDto = JSON.parseObject(JSON.toJSONString(result), SdcResDto.class);
CertResult certResult = new CertResult();
certResult.setUserNo(sdcReqDto.getUserNo());
BeanUtils.copyProperties(sdcResDto, certResult);
CertRecordDto recordDto = new CertRecordDto();
recordDto.setUserNo(sdcReqDto.getUserNo());
recordDto.setTelNo(sdcReqDto.getTelNo());
recordDto.setSn(certResult.getSn());
recordDto.setDn(certResult.getDn());
/**
* 删除并重新保存新记录
*/
deleteCertRecord(sdcReqDto.getUserNo());
saveCertRecord(recordDto);
return certResult;
}
}