关闭验证覆盖默认模拟

closure verification override default mocking

我有一个方法如下:

public void save(DbSession session,Wrappe wrapper,Wrappe wrappe){
      //...other logic

      //save wrapper
      wrapper=(Wrapper)session.save(wrapper)

      //set wrapper's id into wrappee
      wrappee.setWrapperId(wrapper.getId());

      //save wrappee
      session.save(wrappee);
}

测试代码如下所示:

    given:      
    session.save(_) >> wrapperWithGeneratedId

    when:
    obj.save(session,wrapper,wrappee)

    then:"wrapper got saved"
    1*session.save(_) >> {Wrapper save ->
         diffs(wrapper,saved)==null
    }
    and:"wrappee"
    1*session.save(_) >> {Wrappe saved ->
        diffs(wrappee,saved)==null
    }

这些测试代码会抛出异常:

java.lang.ClassCastException: java.lang.Boolean cannot be cast to com.company.model.Wrapper

如果在"then"段评论验证关闭,测试会通过,所以我猜这个段

1*session.save(_) >> {Wrapper save ->
         diffs(wrapper,saved)==null
}

忽略这个嘲讽:

session.save(_) >> wrapperWithGeneratedId

有什么方法可以正确地做到这两点吗?

第一。 'and' 是语法糖。这只是一种在同一块中视觉分离代码的方法。你的最后两个模拟实际上是相同的(尽管因为你是在行为上测试它仍然会验证保存被调用了两次。)

第二。假设您想验证 diffs(wrapper,saved)==null,目前不会发生,因为它不是 'base level' 评估。 then/where/closures/etc 中的任何内容都需要在前面加上 'assert ' 才能对其进行评估。

第三。 then 块的范围仅限于它的 when 块,并且可以覆盖现有的模拟;您假设您的模拟被覆盖是正确的。

第四。您有什么理由不在评估中包含您的 return 价值吗?

2 * session.save(_) >> {Wrapper save ->
     diffs(wrapper,saved)==null
     return wrapperWithGeneratedId
}

第五。您的错误是由于您的模拟 returning 一个布尔值(您的断言逻辑)然后 Groovy 尝试(但失败)解析为包装器。我对为什么会发生这种情况的假设是 .save() 有一个 return 类型的包装器。要解决这个问题,您需要为 Wrapper 创建一个布尔构造函数,或者将您的 mock 更改为 return 某些 Groovy 可以变成 Wrapper(第 4 点中的操作方法)

Official Stub/Mock/Spy documentation (quite good, worth a read)