Issue
We have Jenkins shared library project with some unit-tests that utilize Mockito. After an upgrade of Jenkins-core from version 2.325 to 2.326 tests start failing on the following line:
class DSLMock {
DSLMock() {
this.mock = mock(DSL.class)
-> when(mock.invokeMethod(eq("error"), any())).then(new Answer<String>() {
@Override
String answer(InvocationOnMock invocationOnMock) throws Throwable {
throw new AbortException((String) invocationOnMock.getArguments()[1][0])
}
})
...
with error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Misplaced or misused argument matcher detected here:
-> at com.devops.jenkins.testing.DSLMock.<init>(DSLMock.groovy:66)
-> at com.devops.jenkins.testing.DSLMock.<init>(DSLMock.groovy:66)
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
This message may appear after an NullPointerException if the last matcher is returning an object
like any() but the stubbed method signature expect a primitive argument, in this case,
use primitive alternatives.
when(mock.get(any())); // bad use, will raise NPE
when(mock.get(anyInt())); // correct usage use
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.
I've tried to replace any() with methods like anyString() and just value like "" but still got same error. Also I've tried different stub syntax like
doAnswer(new Answer...).when(mock).invokeMethod(eq("error"), any())
In changelog https://www.jenkins.io/changelog-old/#v2.326 I see Groovy patch version has been upgraded:
- Upgrade Groovy from 2.4.12 to 2.4.21
I wonder if that would cause the issue. Other dependencies versions are not changed:
<groovy.version>2.4.12</groovy.version>
<junit-jupiter.version>5.8.1</junit-jupiter.version>
<mockito.core.version>3.3.3</mockito.core.version>
Solution
It seems like there have been similar issues with other versions of Groovy and Mockito: Is Groovy 3.0.5 incompatible with Mockito 3.6.28 ? Mocks are not usable
However, even the latest version of Mockito doesn't seem to fix the issue with the version of Groovy that you're using. In the meantime, this worked for me:
@Test
void shouldMockObject() {
DSL mock = spy(new DSL(null) {
@Override
Object invokeMethod(String name, Object args) {
return null
}
})
when(mock.invokeMethod(eq("error"), any())).then(new Answer<String>() {
@Override
String answer(InvocationOnMock invocationOnMock) throws Throwable {
throw new AbortException((String) invocationOnMock.getArguments()[1][0])
}
})
assertThrows(AbortException.class) {
mock.invokeMethod("error", [ "message" ])
}
}
Answered By - Bernie
Answer Checked By - Robin (JavaFixing Admin)