Mockito 无效使用匹配器 Mock(Object.class) & anyString()

Mockito Invalid use of matchers Mock(Object.class) & anyString()

欧拉,

我正忙着写一个单元测试,比如

 monitor.severe(mock(MonitorEventType.class), anyString());

当我执行这个时,我得到:

 Invalid use of argument matchers.
 0 matchers expected, 1 recorded.

所以我尝试了:

monitor.severe(mock(MonitorEventType.class), eq(anyString()));

但这给了

Invalid use of argument matchers.
0 matchers expected, 2 recorded.

我也试过用

monitor.severe(any(MonitorEventType.class), anyString());

但这给出了一个空指针。

有效的是

   monitor.severe(mock(MonitorEventType.class), "");

但这不是我想要的。

我的测试方法是:

@Test
public void testSevere() {
    monitor.severe(mock(MonitorEventType.class), eq(anyString()));
    ArgumentCaptor<DefaultMonitoringEventImpl> captor = ArgumentCaptor.forClass(DefaultMonitoringEventImpl.class);
    verify(event).fire(captor.capture());
    DefaultMonitoringEventImpl input = captor.getValue();
    assertThat(fetchMonitorLevel(input), equalTo(MonitorEventLevel.SEVERE.getDescription()));
}

private String fetchMonitorLevel(DefaultMonitoringEventImpl input) {
    Map<String, String> map = input.getMonitorEventWaardes().getWaardenLijst();
    return map.get(MonitorEvent.MONITOR_EVENT_LEVEL_KEY);
}

而被测方法为:

public void severe(MonitorEventType type, String message) {
    write(type, MonitorEventLevel.SEVERE, message, null);
}

@Asynchronous
public void write(MonitorEventType type, MonitorEventLevel level, String message, MonitorEventWaardes pEventWaardes) {
    event.fire(new DefaultMonitoringEventImpl(type, level, message, pEventWaardes));
}

我想要的是,当我使用随机 MonitorEventType 和随机字符串调用 monitor.severe 时,event.fire 调用中的 "level" 参数填充了正确的值。

首先,一些基础知识:

  • mock 是真实对象的替代品,您可以使用模拟框架创建它。它记录它的交互并为以后验证它们。
  • A matcher like any, anyString, or eq 告诉你的模拟框架(不是你的测试框架或你的被测系统) 什么样的调用与 stubbing(告诉你的 mock 在其方法被调用时如何表现)或 verifying(询问你的 mock 框架是否或者没有调用某个方法)。

最重要的是,JUnit 和 Mockito 不允许像 "test this for any input" 这样的语句:像 any 这样的语句只存在所以你可以说 "when I receive any parameter, take this action" 或 "check that a method was called with any parameter"。

所以现在你的例子:

/* BAD */ monitor.severe(mock(MonitorEventType.class), anyString());

这不起作用,因为 monitor 是真实的,所以 anyString 不合适。不过,你的模拟在那里很好,因为你提供了一个模拟实现来测试真实的实现。

/* BAD */ monitor.severe(mock(MonitorEventType.class), eq(anyString()));

这与上面的问题相同,但更重要的是:eq 应该取一个真实值,而不是像 anyString.

这样的匹配器
/* BAD */ monitor.severe(any(MonitorEventType.class), anyString());

在这里,您已经将两个匹配器提供给了一个真正的方法调用。匹配器只是 Mockito 的一个信号,真正的实现正在处理这个,而不是 Mockito。

/*  OK */ monitor.severe(mock(MonitorEventType.class), "");

您正在为真实的被测系统提供模拟实现和真实字符串,因此这是对 Mockito 的正确使用,即使它没有表达您想要测试的内容。


除了使用 Mockito 之外,这里真正的问题是您想在测试中引入 随机性 。即使 Mockito 是完成这项工作的正确工具——它肯定不是——那么你的测试可能会在 90% 的时间内通过并在 10% 的时间内失败,具体取决于选择的输入。这将使您的测试充其量 noisy/flaky,甚至可能导致您的团队忽略一般测试的价值。

相反,选择 代表性用例或边缘案例;如果您有一个枚举类型的参数,您还可以遍历所有值并 运行 每个值测试一次。您可能不需要为此使用 Mockito,除非您出于某种原因无法轻松创建 MonitorEventType 实例;那么你可以使用 Mockito 创建一个假的 MonitorEventType 来与你的真实 Monitor 进行交互。