靓嘟嘟

当前位置: 首页 >> 娱乐八卦

spock(Spock单元测试框架系列(七):异常测试)

2024年01月11日 靓嘟嘟

在业务开发中,我们经常会遇到各种抛出异常的情况,

  • 主动抛出异常,比如参数校验中校验不能为null,列表不能为空,不符合某种类型等,我们可能会在校验不通过时主动抛出异常。
  • 主动捕获异常,比如在调用某个明确抛出异常的方法时,我们会主动捕获异常,以便打印相关异常信息,方便问题的排查。

本篇文章主要介绍一下Spock是如何测试代码中抛异常的场景,以及如何Mock一个方法抛出异常。

测试异常

以下业务代码用于校验一个用户是否合法:

/** * 校验用户是否合法 * * @param user 用户 */public void validateUser(UserDO user) {    if (user == null) {        throw new BizException("10001", "user is null");    }    if (user.getUserId() == null || user.getUserId() <= 0) {        throw new BizException("10002", "user id is invalid");    }    if (StringUtils.isEmpty(user.getUserNick())) {        throw new BizException("10003", "user nick is empty");    }}

在Spock中,我们可以then块中通过 thrown() 方法来验证异常,甚至可以验证异常的errorCode和errorMessage是否符合预期。

@Unrolldef "test validate user"() {    when:    itemService.validateUser(user)    then:    def exception = thrown(expectedException)    exception.errorCode == expectedErrCode    where:    user           || expectedException || expectedErrCode    getUser(10001) || BizException      || "10001"    getUser(10002) || BizException      || "10002"    getUser(10003) || BizException      || "10003"}def getUser(int code) {    def user = new UserDO()    switch (code) {        case 10001:            user = null            break        case 10002:            user.setUserId(0)            break        case 10003:            user.setUserId(123L)            user.setUserNick(null)            break    }    return user}

在Spock中,我们还可以通过 notThrown()方法测试某个方法未抛出异常。当您测试一个Void方法并且想要测试它是否在不抛出异常的情况下执行时非常有用。

还是上面的业务代码,我们增加了一种不抛出异常的验证。

@Unrolldef "test valid user"() {    given:    def user = new UserDO(            userId: 123L,            userNick: "user"    )    when:    itemService.validateUser(user)    then:    notThrown(BizException)}

模拟异常

业务中我们在调用下游的方法时,会经常通过try-catch来捕获下游主动抛出的一些异常,就像我们上面所写的校验逻辑。在这种情况下,我们除了验证正常的链路,还希望能够主动模拟下游方法抛出异常以便于验证catch中的逻辑。

在Spock中,模拟方法抛出的异常非常简单,就像模拟方法的返回值一样。以下这段代码是我们业务中的一段真实逻辑(仅用于演示,去掉了一些包含业务语义的部分)。

@Component@Slf4jpublic class OutputExt extends BlankOutputExt {    @Resource    private strategyManager StrategyManager;    @Override    public ErrorMessage process(final Context context) {        try {            strategyManager.parse(context.getResponse());        } catch (BizException e) {            log.error("策略解析异常:", e.getErrorCode(), e.getErrorMsg());            return ErrorMessageUtils.fail(e);        }        return ErrorMessageUtils.success();    }}

我们来看看Spock是如何测试这段代码中catch分支的。

class OutputExtTest extends Specification {    def strategyManager = Mock(StrategyManager)    def outputExt = new OutputExt(            strategyManager: strategyManager    )    def "test process"() {        given:        def context = new Context(                response: new ResponseDTO()        )        when:        strategyManager.parse(_ as ResponseDTO) >> { throw new BizException("10010", "parse error") }        def errorMessage = outputExt.process(context)        then:        with(errorMessage) {            errorCode == "10010"        }    }}

可以看到,通过 strategyManager.parse(_ as ResponseDTO) >> { throw new BizException("10010", "parse error") } 即可以很轻松的模拟Mock对象的方法调用抛出异常。

以上,就是本篇文章的所有内容,谢谢大家!

  • 友情链接
  • 合作媒体