在 Spring 引导中为 catch 块添加代码覆盖率

Adding Code Coverage for catch block in Spring boot

使用2.1.6.RELEASE

这是我的 serviceImpl class 和 repo.save 方法,如果数据库字段重复,我们会捕获异常并 return 响应

@Service
public class CoreVoucherServiceImpl implements CoreVoucherService {

    @Override
    @Transactional(propagation = REQUIRED)
    public VoucherDTO createVoucher(VoucherDTO voucherDTO) {
        ... /* transforming DTO to Entity */
        try {
            voucherRepository.save(voucher);
        } catch (Exception e) {
            if (e.getCause() instanceof ConstraintViolationException) {
                throw new MyException(FIELD_NOT_UNIQUE, "title");
            }
            UB_LOGGER.debug("Error in create voucher", e);
            throw e;
        }
        voucherDTO.setId(voucher.getId());
        return voucherDTO;
    }
}

我无法为 catch 块添加代码覆盖率。我的测试 class 是

@SpringBootTest
@RunWith(SpringRunner.class)
public class CoreVoucherServiceTest {

    @Autowired
    private CoreVoucherService coreVoucherService;

    @MockBean
    private VoucherRepository voucherRepository;

    @Test
    // @Test(expected = MyException.class)
    public void createVoucherTest() {
        VoucherDTO dto = prepareCreateVoucher();
        when(voucherRepository.save(any())).thenThrow(Exception.class);
        coreVoucherService.createVoucher(dto);
    }
}

用上面的方法我得到以下错误

org.mockito.exceptions.base.MockitoException: 
Checked exception is invalid for this method!
Invalid: java.lang.Exception

如何抛出 getCauseConstraintViolationException 的异常,以便所有行都包含在测试中

你应该抛出 ConstraintViolationException,因为 save 方法根据它的方法定义不会抛出任何已检查的异常 save

when(voucherRepository.save(any()))
      .thenThrow(.ConstraintViolationException.class); 

您必须在 catch 块中测试两个用例:

异常原因为ConstraintViolationException

.thenThrow(new RuntimeException(new ConstraintViolationException("Field not Unique", null, "title")));

当异常原因不是ConstraintViolationException

.thenThrow(new RuntimeException("oops"));

对于这种情况 @ExpectedException 将是 RuntimeException

您还可以在 Junit 中使用 @Rule 和 ExpectedException 来测试异常。

@SpringBootTest
@RunWith(SpringRunner.class)
public class CoreVoucherServiceTest {

    @Autowired
    private CoreVoucherService coreVoucherService;

    @MockBean
    private VoucherRepository voucherRepository;

    @Rule
    public ExpectedException exceptionRule = ExpectedException.none();

    @Test
    // @Test(expected = MyException.class)
    public void createVoucherTest() {
        exceptionRule.expect(Exception.class); // Better if you specify specific Exception class that is going to be thrown.
        VoucherDTO dto = prepareCreateVoucher();
        when(voucherRepository.save(any())).thenThrow(Exception.class);
        coreVoucherService.createVoucher(dto);
    }
}