Ola,
I'm busy writing a unit test like
monitor.severe(mock(MonitorEventType.class), anyString());
When I execute this I get:
Invalid use of argument matchers.
0 matchers expected, 1 recorded.
So I tried:
monitor.severe(mock(MonitorEventType.class), eq(anyString()));
But this gave
Invalid use of argument matchers.
0 matchers expected, 2 recorded.
I also tried to use
monitor.severe(any(MonitorEventType.class), anyString());
but this gives a null pointer.
What works is
monitor.severe(mock(MonitorEventType.class), "");
But thats not what I want.
My testMethod is :
@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);
}
And the method under test is:
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));
}
What I want is that When I call monitor.severe with a random MonitorEventType and a random String that the "level" parameter in teh event.fire call is filled with the right value.
First, some basics:
any
, anyString
, or eq
tells your mock framework (not your test framework or your system under test) what kind of calls are relevant for stubbing (telling your mock how to behave when its method is called) or verifying (asking your mock framework whether or not a certain method was called).Most importantly, JUnit and Mockito do not allow for statements like "test this for any input": Statements like any
only exist so you can say "when I receive any parameter, take this action" or "check that a method was called with any parameter".
So now your examples:
/* BAD */ monitor.severe(mock(MonitorEventType.class), anyString());
This doesn't work because monitor
is real, so anyString
is out of place. Your mock is fine there, though, because you're supplying a mock implementation to test a real implementation.
/* BAD */ monitor.severe(mock(MonitorEventType.class), eq(anyString()));
This is the same problem as above, but doubly so: eq
should take a real value, never a matcher like anyString
.
/* BAD */ monitor.severe(any(MonitorEventType.class), anyString());
Here you've supplied two matchers into a real method call. The matchers are just a signal to Mockito, and a real implementation is processing this, not Mockito.
/* OK */ monitor.severe(mock(MonitorEventType.class), "");
You're supplying a mocked implementation and a real string to your real system-under-test, so this is a proper use of Mockito, even if it doesn't express what you want to test.
Besides the use of Mockito, the real issue here is that you want to introduce randomness into your test. Even if Mockito were the right tool for the job—it definitely isn't—then your test might pass 90% of the time and fail 10% of the time depending on which input is picked. This will make your tests noisy/flaky at best, and may even lead your team to dismiss the value of testing in general.
Instead, pick representative use cases or edge cases; if you have an enum-type parameter, you can also iterate across all values and run the test once per value. You probably don't need Mockito for this, unless you can't easily create a MonitorEventType instance for some reason; then you might use Mockito to create a fake MonitorEventType for interacting with your real Monitor under test.