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 进行交互。
欧拉,
我正忙着写一个单元测试,比如
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
, oreq
告诉你的模拟框架(不是你的测试框架或你的被测系统) 什么样的调用与 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 进行交互。