如何创建接受来自其他匹配器的参数的自定义 ArgumentMatcher?

Cha*_*cer 6 java mockito

我目前正在在ActionEvent内部使用大量's的代码库上编写单元测试,并且由于ActionEvent没有覆盖equals(),我正在创建一个自定义ArgumentMatcher来匹配ActionEvent's。

我ArgumentMatcher目前看起来像这样:

public class ActionEventMatcher extends ArgumentMatcher<ActionEvent> {
    private Object source;
    private int id;
    private String actionCommand;

    public ActionEventMatcher(Object source, int id, String actionCommand) {
        this.source = source;
        this.id = id;
        this.actionCommand = actionCommand;
    }

    @Override
    public boolean matches(Object argument) {
        if (!(argument instanceof ActionEvent))
            return false;
        ActionEvent e = (ActionEvent)argument;

        return source.equals(e.getSource()) &&
            id == e.getId() && actionCommand.equals(e.getActionCommand());
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否可以更改我的ArgumentMatcher以便它接受从其他匹配器创建的参数。例如,如果我调用了actionEvent()一个返回匹配器的方法,我希望能够执行以下操作:

verify(mock).fireEvent(argThat(actionEvent(same(source), anyInt(), eq("actionCommand"))));
Run Code Online (Sandbox Code Playgroud)

有没有办法让自定义ArgumentMatcher以这种方式接受来自其他匹配器的参数?

Jef*_*ica 6

您将能够为 Hamcrest 或 Hamcrest 样式的匹配器执行此操作,但不能为从org.mockito.Matchers.

总之,方法一样same,anyInt和eq在被的Mockito都设计成适合在方法调用when和verify,使他们通过副作用违反直觉的工作。这使得在 Mockito 内部结构之外使用它们并与它们一起工作变得非常困难。相比之下,如果您限制自己使用Matcher(Hamcrest)或ArgumentMatcher(Mockito)实例,您可以根据自己的喜好操作它们,而使用 Hamcrest,您将已经拥有一个庞大的匹配器库。有关上下文,请参阅我的其他问答。

简而言之,您的匹配器可能看起来像这样。

public class ActionEventMatcher extends ArgumentMatcher<ActionEvent> {
    /* fields here */

    public ActionEventMatcher(
            Matcher<Object> sourceMatcher,
            Matcher<Integer> idMatcher,
            Matcher<String> actionCommandMatcher) { /* save fields here */ }

    @Override
    public boolean matches(Object argument) {
        if (!(argument instanceof ActionEvent))
            return false;
        ActionEvent e = (ActionEvent)argument;

        return this.sourceMatcher.matches(e.getSource())
            && this.idMatcher.matches(e.getId())
            && this.actionCommandMatcher.matches(e.getActionCommand());
    }
}
Run Code Online (Sandbox Code Playgroud)

作为奖励,您可以describeMismatch在 Hamcrest 1.3+ 中使用来汇总不匹配的字段,这可能更容易确定 ActionEvent 的哪些方面失败。(verify不过,如果您不使用 ArgumentCaptor,这对呼叫没有帮助,因为 Mockito 将不匹配的呼叫视为“缺少 A 但收到 B”,而不是“收到 B 但由于这些原因匹配器 A 失败”。您必须捕获事件并用于assertEquals从不匹配的描述中受益。)