I have a method which I would like to create some unit test (this method warping
applicationContext.getEnvironment().getProperty(key, class)
for consul integration)
Long story short:
public class DynamicProperties {
public <T> T getEnvironmentProperty(String key, Class<T> cls) {
return cls.cast(applicationContext.getEnvironment().getProperty(key,cls));
}
}
when testing some other class which using the DynamicProperties class, as the following:
@Test
void testA() {
//before
when(dynamicProperties.getEnvironmentProperty(eq(KEY_A), Boolean.class)).thenReturn(true);
when(dynamicProperties.getEnvironmentProperty(eq(KEY_B), Long.class)).thenReturn(0l);
//when
archivedSensorsService.testMethod();
//than
verify(...)
}
KEY_A KEY_B are public static final strings I'm getting the following error:
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
When trying the following:
@Test
void testA() {
//before
when(dynamicProperties.getEnvironmentProperty(eq(KEY_A), anyObject())).thenReturn(true);
when(dynamicProperties.getEnvironmentProperty(eq(KEY_B), anyObject())).thenReturn(0l);
//when
archivedSensorsService.testMethod();
//than
verify(...)
}
Getting the following error:
org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:
- this invocation of 'getEnvironmentProperty' method:
dynamicProperties.getEnvironmentProperty(
null,
null
);
-> at com.xxx.xxx ionNotBeenTriggered(..)
- has following stubbing(s) with different arguments:
1. dynamicProperties.getEnvironmentProperty(
null,
null
);
Any suggestions?
The problem is caused by mixing mocking with and without argument matchers. If you use an argument matcher to one of the mocked method arguments, you have to use a matcher for all of them. You can read more here.
I've created a simple project on GitHub with a solution - you can check it if you like, but here's the snippet:
@Test
void withoutEq() {
DynamicProperties dynamicProperties = mock(DynamicProperties.class);
when(dynamicProperties.getEnvironmentProperty(KEY_A, Boolean.class))
.thenReturn(true);
when(dynamicProperties.getEnvironmentProperty(KEY_B, Long.class))
.thenReturn(1L);
assertAll(
() -> assertTrue(dynamicProperties.getEnvironmentProperty(KEY_A, Boolean.class)),
() -> assertEquals(1, dynamicProperties.getEnvironmentProperty(KEY_B, Long.class))
);
}
@Test
void withEq() {
DynamicProperties dynamicProperties = mock(DynamicProperties.class);
when(dynamicProperties.getEnvironmentProperty(eq(KEY_A), eq(Boolean.class)))
.thenReturn(true);
when(dynamicProperties.getEnvironmentProperty(eq(KEY_B), eq(Long.class)))
.thenReturn(1L);
assertAll(
() -> assertTrue(dynamicProperties.getEnvironmentProperty(KEY_A, Boolean.class)),
() -> assertEquals(1, dynamicProperties.getEnvironmentProperty(KEY_B, Long.class))
);
}
As you can see - one of the methods uses eq
matcher for both of the method's arguments and the other one uses none. Both tests pass.
In your case
when(dynamicProperties.getEnvironmentProperty(eq(KEY_A), anyObject())).thenReturn(true);
this mock did not cause "matcher combined with raw values" error, because eq
and anyObject
are both argument matchers, but
when(dynamicProperties.getEnvironmentProperty(eq(KEY_A), Boolean.class)).thenReturn(true);
has a matcher (eq
) and a simple object (Boolean.class
without eq
).