Jenkins 核心升级后 Mockito 参数匹配器不正确

kir*_*l-a 5 java groovy matcher mockito jenkins

我们有 Jenkins 共享库项目,其中包含一些利用 Mockito 的单元测试。将 Jenkins-core 从版本 2.325 升级到 2.326 后,测试开始在以下行失败:

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])
      }
    })
...
Run Code Online (Sandbox Code Playgroud)

有错误:


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.
Run Code Online (Sandbox Code Playgroud)

我尝试用像anyString()这样的方法替换any(),并且只是像“”这样的值,但仍然遇到同样的错误。我也尝试过不同的存根语法,例如

doAnswer(new Answer...).when(mock).invokeMethod(eq("error"), any())
Run Code Online (Sandbox Code Playgroud)

在变更日志https://www.jenkins.io/changelog-old/#v2.326中我看到 Groovy 补丁版本已升级:

  • 将 Groovy 从 2.4.12 升级到 2.4.21

我想知道这是否会导致问题。其他依赖版本不变:

<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>
Run Code Online (Sandbox Code Playgroud)

Ber*_*nie 0

似乎其他版本的 Groovy 和 Mockito 也存在类似的问题:Is Groovy 3.0.5 incomplete with Mockito 3.6.28 ? 模拟不可用

但是,即使是最新版本的 Mockito 似乎也无法解决您正在使用的 Groovy 版本的问题。与此同时,这对我有用:

@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" ])
    }
}
Run Code Online (Sandbox Code Playgroud)