即使所有论点都是“匹配器”类型,也会从调用 verify() 中获取 InvalidUseOfMatchersException

Mat*_*son 5 java mockito

我在使用 Mockito 框架的测试中有以下代码来验证是否drawTextOnCanvas()使用正确的参数调用了该方法。

    // The two objects below are mocks.  The rest of the objects used in
    // the call to verify() are plain old java objects I've instantiated elsewhere.
    BufferedImage testImage = Mockito.mock(BufferedImage.class);
    Mockito.when(testImage.getHeight()).thenReturn(10);

    Graphics mockGraphics = Mockito.mock(Graphics.class);
    Mockito.when(mockGraphics.getFontMetrics(Matchers.any(Font.class)))
            .thenReturn(Mockito.mock(FontMetrics.class));


    Mockito.verify(drawingUtil).drawTextOnCanvas(
            Matchers.eq(imageCategory.getWidth()), 
            Matchers.eq(mockGraphics),
            Matchers.any(Font.class), 
            Matchers.eq(Arrays.asList("Test text")),
            Matchers.eq(testImage.getHeight() + 10),
            Matchers.any(FontMetrics.class), 
            Matchers.eq(10));
Run Code Online (Sandbox Code Playgroud)

但是它抛出以下异常:

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 4 recorded:
-> at com.test.package(ExampleTest.java:66)
-> at com.test.package(ExampleTest.java:67)
-> at com.test.package(ExampleTest.java:67)
-> at com.test.package(ExampleTest.java:68)

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"));

For more info see javadoc for Matchers class........
Run Code Online (Sandbox Code Playgroud)

然而,我发现如果我更换线路

 Matchers.eq(testImage.getHeight() + 10), 
Run Code Online (Sandbox Code Playgroud)

 Matchers.eq(someInteger),
Run Code Online (Sandbox Code Playgroud)

测试无一例外地运行,这让我感到困惑。

我已经查看了 Matchers 的 JavaDoc,据我所知,我所写的应该可以工作,除非有一些规则关于将模拟对象的调用放在eq()我错过的调用中。

Jef*_*ica 3

你已经搞定了:你已经模拟了testImage,并且在存根时调用模拟方法是不允许的。文档并不清楚该限制。

我之前写过关于 Mockito 匹配器的详尽答案(请参阅“实现细节”),但简短的版本是Mockito 将其参数匹配器保留在堆栈上,并且每次调用模拟的n参数方法都会检查堆栈是否包含 0 或n 个匹配器。

Mockito.verify(drawingUtil).drawTextOnCanvas(
        Matchers.eq(imageCategory.getWidth()),      // A1
        Matchers.eq(mockGraphics),                  // A2
        Matchers.any(Font.class),                   // A3
        Matchers.eq(Arrays.asList("Test text")),    // A4
        Matchers.eq(testImage.getHeight() + 10),    // B
        Matchers.any(FontMetrics.class),            // C1
        Matchers.eq(10));                           // C2
Run Code Online (Sandbox Code Playgroud)

调用顺序是这样的: 之后verify(drawingUtil),Java 按顺序准备参数drawTextOnCanvas,调用 A1 到 A4。突然,对 B 的呼叫发生了,Mockito 做好了准备,就好像textImage.getHeight()嵌入了when(...)呼叫中一样。堆栈上有 4 个匹配器,Mockito 期望通过相等(零匹配器)或参数数量getHeight()(也是零匹配器)进行匹配。在到达 C1、C2 或 之前,Mockito 会抛出该异常并显示“4 个匹配器已记录”消息drawTextOnCanvas

作为一个好的实践,将所有Matchers.eq值(包含方法调用)提取到局部变量,特别强调对模拟对象的调用。