【问题标题】:Mockito Invalid use of matchers Mock(Object.class) & anyString()Mockito 无效使用匹配器 Mock(Object.class) & anyString()
【发布时间】:2016-12-06 10:15:37
【问题描述】:

奥拉,

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

 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 调用中的“级别”参数填充了正确的值。

【问题讨论】:

  • 目标到底是什么?你想测试什么?
  • 显示方法severe
  • @NicolasFilotto 方法严重看起来像 public void Serious(MonitorEventType type, String message) { write(type, MonitorEventLevel.SEVERE, message, null);这里是完整的测试 public void testSevere() { monitor.severe(mock(MonitorEventType.class), eq(anyString())); ArgumentCaptor captor = ArgumentCaptor.forClass(DefaultMonitoringEventImpl.class);验证(事件).fire(captor.capture()); DefaultMonitoringEventImpl 输入 = captor.getValue(); assertThat(fetchMonitorLevel(input), equalTo(MonitorEventLevel.SEVERE.getDescription())); }
  • 抱歉,您仍然没有回答我所有的问题:您到底想做什么? write的方法是什么? MonitorEventLevel 是什么班级?没有所有答案就不可能回答
  • 如果你想测试一个随机字符串,那么发送一个随机字符串而不是一个空字符串。在单元测试中使用随机值的 BTY 不是一个好主意...

标签: java junit mockito matcher hamcrest


【解决方案1】:

首先,一些基础知识:

  • mock 是真实对象的替代品,您可以使用模拟框架创建该对象。它会记录其交互并进行验证以供日后使用。
  • anyanyStringeq 这样的匹配器 告诉你的模拟框架(不是你的测试框架或你的测试系统)什么样的调用与相关stubbing(告诉你的 mock 在调用它的方法时如何表现)或 verifying(询问你的 mock 框架是否调用了某个方法)。

最重要的是,JUnit 和 Mockito 不允许像“测试任何输入”这样的语句:像 any 这样的语句只存在所以你可以说“当我收到任何参数时,采取这个动作”或“检查一个方法被任何参数调用”。

现在你的例子:

/* 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% 的时间,具体取决于选择的输入。这最多会使您的测试变得嘈杂/不稳定,甚至可能导致您的团队总体上忽视测试的价值。

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

【讨论】:

  • 谢谢!昨天我已经发现这是我的问题,但是你的帖子更清楚了!还有其他方法可以实现我想要的吗? perheps mock(string.class) with Powermockito or just use "",虽然这不同但我不关心实际的字符串输入?
  • 即使可以模拟字符串,也没有从不的充分理由。替代方案在最后一段中:手动选择边缘案例,或详尽地运行所有案例。我建议使用你可以在野外找到的真实字符串,以及null
猜你喜欢
  • 2013-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-19
  • 1970-01-01
  • 2020-03-23
  • 2016-02-02
  • 1970-01-01
相关资源
最近更新 更多