测试无返回值void方法遇Mockito报错且无代码覆盖率的问题
测试void方法获取代码覆盖率失败的问题与修复
待测试的VaultService方法
@Service public class VaultService { private final ProductRepository repository; private final DatabaseService databaseService; public VaultService( @Autowired BuildProperties buildProperties, ProductRepository repository, DatabaseService databaseService ) { logger.info("Creating service"); this.repository = repository; this.databaseService = databaseService; } protected void checkVaultResponseErrors(VaultResponse vaultResponse) { if (vaultResponse.responseStatus != ResponseStatus.SUCCESS) { vaultResponse.errors.forEach(error -> { if (vaultResponse.responseStatus.equals(ResponseStatus.EXCEPTION)) { throw new VaultException(error.getMessage()); } if (vaultResponse.responseStatus.equals(ResponseStatus.FAILURE)) { throw new VaultFailure(error.getMessage()); } }); } } }
VaultResponse类定义
@Getter @Setter @JsonInclude(JsonInclude.Include.NON_NULL) public class VaultResponse { @JsonProperty("responseStatus") public ResponseStatus responseStatus; @JsonProperty("errors") public List<Error> errors; }
当前错误的测试代码
@Test void should_check_vaultResponse_for_errors() { VaultService spyService = Mockito.spy(vaultService); VaultResponse vaultResponse = new VaultResponse(); ResponseStatus status = ResponseStatus.SUCCESS; List<Error> error = new ArrayList<>(); vaultResponse.setResponseStatus(status); vaultResponse.setErrors(error); doThrow(IllegalArgumentException.class) .when(spyService).checkVaultResponseErrors(vaultResponse); doNothing().when(spyService).checkVaultResponseErrors(vaultResponse); verify(spyService, times(1)).checkVaultResponseErrors(vaultResponse); }
问题分析
- 未执行真实方法:测试仅设置Mock行为,未调用
spyService.checkVaultResponseErrors(vaultResponse),真实逻辑完全没运行,自然无代码覆盖率。 - Mock行为冲突:先设置
doThrow再设置doNothing,后者覆盖前者,重复设置无意义。 - Spy使用错误:Spy的作用是调用真实方法,却用
doNothing跳过逻辑,违背测试初衷。 - 测试场景单一:仅覆盖
SUCCESS状态,未覆盖EXCEPTION和FAILURE分支,无法获取完整覆盖率。
修正后的测试代码
针对不同逻辑分支编写独立测试用例,确保每个分支都被覆盖:
测试1:SUCCESS状态无异常抛出
@Test void should_not_throw_exception_when_response_status_is_success() { // 初始化被测试类,依赖用Mock替代 VaultService vaultService = new VaultService( Mockito.mock(BuildProperties.class), Mockito.mock(ProductRepository.class), Mockito.mock(DatabaseService.class) ); VaultResponse vaultResponse = new VaultResponse(); vaultResponse.setResponseStatus(ResponseStatus.SUCCESS); vaultResponse.setErrors(new ArrayList<>()); // 调用真实方法,无异常则测试通过 vaultService.checkVaultResponseErrors(vaultResponse); }
测试2:EXCEPTION状态抛出VaultException
@Test void should_throw_vault_exception_when_response_status_is_exception() { VaultService vaultService = new VaultService( Mockito.mock(BuildProperties.class), Mockito.mock(ProductRepository.class), Mockito.mock(DatabaseService.class) ); VaultResponse vaultResponse = new VaultResponse(); vaultResponse.setResponseStatus(ResponseStatus.EXCEPTION); Error testError = new Error(); testError.setMessage("Test exception error"); vaultResponse.setErrors(List.of(testError)); // 验证抛出指定异常及消息 VaultException exception = Assertions.assertThrows(VaultException.class, () -> vaultService.checkVaultResponseErrors(vaultResponse)); Assertions.assertEquals("Test exception error", exception.getMessage()); }
测试3:FAILURE状态抛出VaultFailure
@Test void should_throw_vault_failure_when_response_status_is_failure() { VaultService vaultService = new VaultService( Mockito.mock(BuildProperties.class), Mockito.mock(ProductRepository.class), Mockito.mock(DatabaseService.class) ); VaultResponse vaultResponse = new VaultResponse(); vaultResponse.setResponseStatus(ResponseStatus.FAILURE); Error testError = new Error(); testError.setMessage("Test failure error"); vaultResponse.setErrors(List.of(testError)); // 验证抛出指定异常及消息 VaultFailure failure = Assertions.assertThrows(VaultFailure.class, () -> vaultService.checkVaultResponseErrors(vaultResponse)); Assertions.assertEquals("Test failure error", failure.getMessage()); }
关键说明
- 直接实例化被测试类:无需使用Spy,直接创建
VaultService实例(依赖用Mockito Mock),调用真实方法才能覆盖代码逻辑。 - 分场景测试:每个用例仅覆盖一个分支,逻辑清晰,便于定位问题。
- 验证异常行为:针对非SUCCESS状态,通过
assertThrows验证异常类型和消息是否符合预期。
内容的提问来源于stack exchange,提问作者pussyCat
相关产品推荐
相关产品推荐

