我目前正在代码库上编写单元测试,内部使用了很多ActionEvent
,而且由于ActionEvent
没有覆盖equals()
,我正在创建一个自定义ArgumentMatcher
以匹配ActionEvent
的。
我的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());
}
}
我想知道是否可以更改我的ArgumentMatcher
,以便它接受从其他匹配器创建的参数。例如,如果我有一个名为actionEvent()
的方法返回匹配器,我希望能够执行以下操作:
verify(mock).fireEvent(argThat(actionEvent(same(source), anyInt(), eq("actionCommand"))));
有没有办法让自定义ArgumentMatcher
以这种方式接受来自其他匹配器的参数?
答案 0 :(得分:3)
你可以为Hamcrest或Hamcrest风格的匹配器做到这一点,但不能通过org.mockito.Matchers
上的静态方法获得的Mockito匹配器。
简而言之,Mockito中的same
,anyInt
和eq
等方法都设计为适合when
和verify
中的方法调用,因此他们通过副作用违反直觉。这使得消费它们非常困难,并且在Mockito内部之外与它们一起工作。相比之下,如果您将自己限制为使用Matcher
(Hamcrest)或ArgumentMatcher
(Mockito)个实例,则可以根据自己的内容操纵这些实例,而使用Hamcrest,您已经拥有large library of matchers to start with。有关上下文,请参阅my other Q&A here。
简而言之,您的匹配器可能看起来像这样。
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());
}
}
作为奖励,您可以使用describeMismatch
in Hamcrest 1.3+汇总不匹配的字段,这可能更容易确定ActionEvent的哪些方面失败。 (但是,如果您不使用ArgumentCaptor,这对verify
次呼叫没有帮助,因为Mockito将不匹配的呼叫视为“缺少A而是接收B”,而不是“收到B但是匹配器A失败”出于这些原因“。您必须捕获事件并使用assertEquals
从错配描述中受益。)