junit+mockito-PowerMock完成单测
Mockito简介
什么是Mockito
Mockito是一个开源的Mock框架,旨在为Java单元测试提供简单、可读的Mock对象。它可以模拟类的行为,使测试代码能够在不依赖真实对象的情况下运行。
为什么使用Mockito
- 隔离外部依赖:可以模拟外部系统(如数据库、网络服务等),使测试更加独立。
- 提高测试覆盖率:即使没有实现具体逻辑,也可以编写测试,确保接口和交互逻辑正确。
- 便于测试边界条件:可以轻松模拟异常情况和边界条件,确保代码在各种情况下的稳定性。
中文文档
https://gitcode.com/bboyfeiyu/mockito-doc-zh/overview?utm_source=artical_gitcode
https://github.com/kuaile-zc/mockito-doc-zh/tree/master
单测mock
监测变量
// Run the test final List<String> result = coldChainShipmentOrderDomainServiceImplUnderTest.createShipmentOrder(command, OperateContextUtil.getSystemOperator()); //监测此变量 ArgumentCaptor<List<ColdChainShipmentOrderAggregate>> captor = ArgumentCaptor.forClass( List.class); //内部调用此mock方法时监测 verify(mockColdChainShipmentOrderRepository).doSave(captor.capture()); // 获取捕获的参数值 List<ColdChainShipmentOrderAggregate> capturedValue = captor.getValue(); //mock的数据未经过习惯没有domainEvents assertThat(CollectionUtils.isNotEmpty(capturedValue) && capturedValue.size() == 1 && capturedValue.get(0).getDomainEvents().get(0) instanceof CreateShipmentOrderDomainEvent).isTrue();
状态清除
Mockito.reset(mockRedissonLockUtil);
Mockito.reset(mockColdChainAlarmOrderRepository);
Mockito.reset(mockNotifyApplicationService);
Mockito.reset(mockNotifyApplicationService);
mock void方法抛出异常
doThrow(new YxtRuntimeException(ResponseCodeType.BIZ_EXCEPTION)).when(mockAuthApplicationService).checkAuthByStoreCode(command.getShipperOrgCode(), any(OperateContext.class));
捕获
变量捕获
//------------------------------------------------------根据发货单号进行发货---------------------------------- // Run the test final List<String> result = coldChainShipmentOrderDomainServiceImplUnderTest.batchShipOrder(batchShipCommand, operateContext); ArgumentCaptor<List<ColdChainShipmentOrderAggregate>> captor = ArgumentCaptor.forClass( List.class); verify(mockColdChainShipmentOrderRepository).doSave(captor.capture()); // 获取捕获的参数值 List<ColdChainShipmentOrderAggregate> capturedValue = captor.getValue(); assertThat(capturedValue.get(0).getShipmentInfo() != null).isTrue();
常用断言
断言方法被调用
verify(mockRedissonLockUtil).unlock(lockKey);
断言方法未被调用
verify(mockNotifyApplicationService, never()).sendPersonMessage(any(SendPersonMessageDTO.class), any(OperateContext.class));
断言抛出异常
assertThatThrownBy( () -> coldChainAlarmOrderDomainServiceImplUnderTest.createAlarmOrder(command)) .isInstanceOf(YxtRuntimeException.class).hasMessage("系统繁忙,请稍后重试!");
模拟事务
// 发送领域事件 TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCommit() { } });
@Before public void startTransaction() { if (!TransactionSynchronizationManager.isActualTransactionActive()) { TransactionSynchronizationManager.setActualTransactionActive(true); TransactionSynchronizationManager.initSynchronization(); } }
PowerMock
mock私有方法
// Mock 模拟私有方法 PowerMockito.doReturn(hasAuth) .when(spyService, "setAuthErpOrgCodes", Mockito.any(PageAlarmOrderReqDTO.class), Mockito.any(PageAuthAlarmOrderCommand.class), Mockito.any( OperateContext.class));
初始化私有变量
Whitebox.setInternalState(coldChainAlarmOrderRepresentationServiceImplUnderTest, "chainBusinessOrgCode",
chainBusinessOrgCodeValue);
私有方法单测
@InjectMocks private ReceiveApplicationServiceImpl receiveApplicationServiceImplUnderTest; @Test public void test_checkReceiveTime() { ReceiveApplicationServiceImpl spyService = PowerMockito.spy( receiveApplicationServiceImplUnderTest); ReceiveCommand command = ReceiveCommand.builder().receiverTime(DateHelper.getDayNow(DateHelper.now(), 1)) .build(); //发货信息为空场景 ColdChainShipmentInfoEntity coldChainShipmentInfoEntity = null; assertThatThrownBy( () -> Whitebox.invokeMethod(spyService, "checkReceiveTime", command, coldChainShipmentInfoEntity)) .isInstanceOf(YxtRuntimeException.class).hasMessage("发货信息不能为空"); //收货时间早于发货时间场景 ColdChainShipmentInfoEntity coldChainShipmentInfoEntityA = new ColdChainShipmentInfoEntity(); coldChainShipmentInfoEntityA.setDepartureTime(DateHelper.getDayNow(DateHelper.now(), 2)); assertThatThrownBy( () -> Whitebox.invokeMethod(spyService, "checkReceiveTime", command, coldChainShipmentInfoEntityA)) .isInstanceOf(YxtRuntimeException.class).hasMessage("收货时间早于发货时间,不能收货"); //收货时间大于当前时间场景 ReceiveCommand commandB = ReceiveCommand.builder().receiverTime(DateHelper.getDayNow(DateHelper.now(), 1)) .build(); ColdChainShipmentInfoEntity coldChainShipmentInfoEntityB = new ColdChainShipmentInfoEntity(); coldChainShipmentInfoEntityB.setDepartureTime(DateHelper.getDayNow(DateHelper.now(), -2)); assertThatThrownBy( () -> Whitebox.invokeMethod(spyService, "checkReceiveTime", commandB, coldChainShipmentInfoEntityB)) .isInstanceOf(YxtRuntimeException.class).hasMessage("收货时间晚于当前时间,不能收货"); }