具有不同对象的自定义匹配器

Custom matchers with different object

您好,我正在编写自定义匹配器来验证两个不同的对象,我的代码是:

public class DetailsMatcher extends ArgumentMatcher <Details> {

    private final Details expected;

    private DetailsMatcher(Details expected) {
        this.expected = expected;
    }

    @Override
    public boolean matches(Object actual) {
        return ((Request) actual).getId().equals(expected.getId());
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(expected == null ? null : expected.toString());
    }

    public static Details valueObjectEq(Details expected) {
        return argThat(new DetailsMatcher(expected));
    }
}

我想在我的测试中使用它作为:

assertThat(requestModel, DetailsMatcher.valueObjectEq(response));

但这是两个不同的对象,所以它不起作用。我不想仅仅为了测试目的而改变我的对象,所以我们有一些像 assertThat 这样的 api,它允许传递不同的对象来简单地依赖于匹配的输出,而不是强制相同的实际和预期类型?

注意将 Mockito 匹配器和 Hamcrest 匹配器分开。 Hamcrest 或 Hamcrest 风格的匹配器是一个对象实例,就像上面的 new DetailsMatcher(expected) 一样。通过调用 argThat,您的 valueObjectEq 似乎 return 一个 Details 对象,但事实并非如此:它将 return null 和 Mockito将在内部堆栈上保存一个对象。因此,你不应该在调用 whenverify.

之外调用 argThat

相反,将您的 DetailsMatcher 更改为 ArgumentMatcher<Request> 类型,以表明您的 Matcher 可以在任何 Request 上工作,而不仅仅是 Details,并使构造函数 public 所以你可以这样称呼它:

assertThat(requestModel, new DetailsMatcher(orderResponse));
// or with a static helper method you write:
assertThat(requestModel, matchesValueObject(orderResponse));

其他一些注意事项:

  • Matcher.matches 永远不应抛出异常,但如果您传入非请求,它会在此处抛出异常。如果参数不是匹配器,请检查 instanceof 和 return false
  • Mockito 2.0 使 ArgumentMatcher 成为自己的 class,而不是扩展 org.hamcrest.Matcher。如果你想继续使用 Matcher 的 Hamcrest 属性,你可能需要让它扩展两者,或者只是让它成为 Hamcrest 匹配器并调整 valueObjectEq 以调用 MockitoHamcrest.argThat。
  • 虽然错误信息不会那么清楚,但您始终可以手动调用该方法:

    assertTrue(new DetailsMatcher(orderReponse).matches(requestModel));
    

另请参阅:

  • Mockito's Matcher vs Hamcrest Matcher?
  • How do Mockito matchers work?