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

时间:2016-06-20 16:34:51

标签: java mockito matcher hamcrest

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

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,它允许传递不同的对象简单地依赖于匹配的输出,而不是强制实际和期望的相同类型?

1 个答案:

答案 0 :(得分:1)

小心将Mockito匹配器和Hamcrest匹配器分开。 Hamcrest或Hamcrest风格的匹配器是一个对象实例,就像上面的new DetailsMatcher(expected)一样。通过拨打argThat,您的valueObjectEq似乎会返回Details个对象,但事实并非如此:它将返回null,而Mockito会保存一个对象在内部堆栈上。因此,您不应在致电argThatwhen之外致电verify

相反,将您的DetailsMatcher更改为ArgumentMatcher<Request>类型,以表明您的匹配器可以处理任何Request,而不只是Details,并将构造函数设为公共,以便您可以调用它像这样:

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

其他几点说明:

  • Matcher.matches应该永远不会抛出异常,但如果您传入非请求,它将在此处执行此操作。如果参数不是匹配器,请查看instanceof并返回false
  • Mockito 2.0使ArgumentMatcher成为自己的类,而不是扩展org.hamcrest.Matcher。如果你想继续使用Matcher来获得它的Hamcrest属性,你可能需要将它扩展为两者,或者只是将它作为Hamcrest匹配器并调整valueObjectEq来调用MockitoHamcrest.arg而不是。
  • 虽然错误消息不会很清楚,但您始终可以手动调用该方法:

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

另见: