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

i7uq4tfw  于 2022-11-08  发布在  Jenkins
关注(0)|答案(2)|浏览(183)

bounty将在2天后过期。回答此问题可获得+100的声望奖励。kirill-a希望吸引更多人关注此问题。

我们有一个Jenkins共享库项目,其中包含一些使用Mockito的单元测试。在Jenkins核心从版本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])
      }
    })
...

发生错误:

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.

我试过用anyString()这样的方法替换any(),只替换“”这样的值,但还是出现了同样的错误。

doAnswer(new Answer...).when(mock).invokeMethod(eq("error"), any())

在changelog www.example.com中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>
mqkwyuun

mqkwyuun1#

我试图在本地重现您的错误,但在以下行遇到编译错误:throw new AbortException((String) invocationOnMock.getArguments()[1][0]) .您是否可以尝试以下操作:

when(mock.invokeMethod(eq("error"), any(String[].class))).then(new Answer<String>() {
    @Override
    public String answer(InvocationOnMock invocationOnMock) throws Throwable {
        String[] array = (String[]) invocationOnMock.getArguments()[1];
        throw new AbortException((String) array[0]);
    }
});
mepcadol

mepcadol2#

doAnswer(...).when(mock).call(...)不会触发太多mock中的任何执行,静态编译也可以关闭Groovy的动态行为,这会有所帮助,因为您要覆盖具有特殊意义的invokeMethod(String,Object)

import static org.mockito.Mockito.*
// ...
class DSLMock {
  @groovy.transform.CompileStatic
  DSLMock() {
    this.mock = mock(DSL)
    doCallRealMethod().when(this.mock).getMetaClass() // if DSL implements GroovyObject
    doAnswer({ iom ->
      throw new AbortException(iom.getArgumentAt(1, String[])[0])
    }).when(this.mock).invokeMethod(eq('error'), anyObject())
  }
  // ...
}

相关问题