当看起来没问题时,Mockito会给出UnfinishedVerificationException

时间:2013-04-09 14:23:47

标签: unit-testing junit mockito

当我认为我已经正确完成所有事情时,Mockito似乎正在抛出一个UnfinishedVerificationException。这是我的部分测试用例:

HttpServletRequest req = mock(HttpServletRequest.class);
when(req.getHeader("Authorization")).thenReturn("foo");

HttpServletResponse res = mock(HttpServletResponse.class);

classUnderTest.doMethod(req, res); // Use the mock

verify(res, never());
verify(req).setAttribute(anyString(), anyObject());

这是部分类和方法:

class ClassUnderTest extends AnotherClass {
    @Override
    public String doMethod(ServletRequest req, ServletRequest res) {
        // etc.
        return "someString";
    }
}

忽略你不应该模仿你不拥有的接口这一事实,为什么Mockito会给我以下信息?

org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-> at (redacted)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.

at [test method name and class redacted]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37)
at org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
... etc

17 个答案:

答案 0 :(得分:50)

我只是碰到了我的自我,这给我带来了很多困惑。

正如David上面提到的,Mockito报告了下一个 Mockito方法调用中的错误,这可能不是同一个测试方法。虽然异常消息确实包含对错误发生的实际位置的引用,但我发现错误的测试无法对测试过程产生反作用。而且测试越简单,错误就越有可能出现在下一次测试中!

这是一个简单的解决方案,可确保错误出现在正确的测试方法中:

@After
public void validate() {
    validateMockitoUsage();
}

来自Mockito文档here

  如果你滥用它,Mockito会抛出异常,以便你知道你的   测试写得正确。 问题是,Mockito做了   下次使用框架验证(例如,下次验证时,   存根,调用模拟等)。但即使异常可能被抛出   在下一个测试中,异常消息包含一个可导航的堆栈   具有缺陷位置的痕量元素。因此你可以点击和   找到Mockito被滥用的地方。

     

有时候,你可能会   想明确验证框架用法。例如,其中之一   用户希望将validateMockitoUsage()放在他的@After方法中   当他误用Mockito时他立即知道。没有它,他   我会知道它不会比他下次使用它更早   框架。 在@After中使用validateMockitoUsage()的另一个好处   是jUnit运行器将始终在缺陷的测试方法中失败   而普通的下一次'验证可能在下一次测试中失败   方法。但即使JUnit可能会将下一次测试报告为红色,也不要   担心它,只需单击中的可导航堆栈跟踪元素   异常消息,可以立即找到您滥用的地方   的Mockito。

答案 1 :(得分:37)

如果您尝试 {"name":"name"} Exception in thread"main"com.bluelinelabs.logansquare.NoSuchMapperException:Class me.codeboy.lyd.test.Bean could not be mapped to a JSON object.Perhaps it hasn't been annotated with @JsonObject? at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:165) at com.bluelinelabs.logansquare.LoganSquare.parse(LoganSquare.java:44) at me.codeboy.lyd.test.Test1.test(Test1.java:26) at me.codeboy.lyd.test.Test1.main(Test1.java:13) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140) Caused by:java.lang.ClassNotFoundException:me.codeboy.lyd.test.Bean$$JsonObjectMapper at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:425) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:358) at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:191) at com.bluelinelabs.logansquare.LoganSquare.mapperFor(LoganSquare.java:161) ...8more Process finished with exit code 1 一个需要verify原始参数的方法,也可能会导致这种情况:

例如,如果我们的方法有这个签名:

any()

你试图像这样验证它,它将失败,上面的消息:

method(long l, String s);

将其更改为verify(service).method(any(), anyString()); ,它会起作用:

anyLong()

答案 2 :(得分:3)

由于any()boolean参数一起使用时,我也遇到了同样的错误。显然,它需要为anyBoolean()

答案 3 :(得分:2)

在我的情况下,使用 kotlin 是因为未将要测试的功能声明为open

该异常注意到不能使用final / private / equals / hash方法。

fun increment(){
        i++
    }

open fun increment(){
        i++
    }

答案 4 :(得分:1)

对我来说,问题结果是测试上下文xml中缺少bean声明。它是由另一个类使用的自定义方面类,其实例是类的构造函数的参数,该参数是验证verify()调用失败的参数。所以我将bean声明添加到上下文xml中,之后它运行良好。

答案 5 :(得分:0)

如果您尝试使用Mockito.verify验证私有方法或程序包私有方法,则会收到此错误。

如果您不想使用PowerMockito,可以将方法设置为保护状态,我建议您添加@VisibleForTesting标记:

之前:

void doSomething() {
   //Some behaviour
}

之后:

@VisibleForTesting
protected void doSomething() {
   //Some behaviour
}

答案 6 :(得分:0)

这是我的一粒盐! 我发现 MockitoHibernate Validation 之间存在冲突。 我的解决方案是将我的合同检查(@NotNull、@NotEmpty 等)与模拟测试分开。我还开始使用 validateMockitoUsage() 来确保一切正常运行。

答案 7 :(得分:0)

测试可以单独良好地运行,但是在运行集成测试套件时,它将失败,并显示UnfinishedVerificationException。当我们使用来自模仿者的verify()并具有@EnableRetry时,就会出现问题。 解决方法是使用

public static <T> T unwrapAndVerify(T mock, VerificationMode mode) { return ((T) Mockito.verify(AopTestUtils.getTargetObject(mock), mode)); }

如本https://html.developreference.com/article/15741255/Mocked+Spring+%23Service+that+has+%23Retryable+annotations+on+methods+fails+with+UnfinishedVerificationException中所述。

答案 8 :(得分:0)

在以下堆栈上,我也遇到了同样的问题:

  • 科特琳
  • Junit 4.13
  • Mockito 2.28.2 + Mockito-Inline 2.13.0
  • 机器人4.3.1

我尝试验证lambda调用:

@RunWith(RobolectricTestRunner::class)
class MainViewTest {

    @get:Rule
    val mockitoRule: MockitoRule = MockitoJUnit.rule()

    @Mock private lateinit var mockClickCallback: () -> Unit

    @Test
    fun `should call clickCallback on the button click`() {
        val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
        val viewUnderTest = MainView(activity)
        viewUnderTest.setClickCallback(mockClickCallback)

        viewUnderTest.button.performClick()

        verify(mockClickCallback).invoke() // UnfinishedVerificationException
    }
}

然后我在Github上发现了the issue,看来问题出在Robolectric。我使用以下解决方法:

@RunWith(RobolectricTestRunner::class)
class MainViewTest {

    private interface UnitFunction: () -> Unit

    @Test
    fun `should call clickCallback on the button click`() {
        val activity = Robolectric.buildActivity(MainActivity::class.java).create().get()
        val viewUnderTest = MainView(activity)
        val mockClickCallback = mock(UnitFunction::class.java) as () -> Unit
        viewUnderTest.setClickCallback(mockClickCallback)

        viewUnderTest.button.performClick()

        verify(mockClickCallback).invoke() // OK
    }
}

答案 9 :(得分:0)

更改为@RunWith(PowerMockRunner.class),问题消失了。 之前使用的是@RunWith(MockitoJUnitRunner.class)

希望对某人有帮助。

答案 10 :(得分:0)

上面的两个答案建议在每次测试后使用validateMockitoUsage()方法。 尽管这是正确的,但我发现使用@ExtendWith(MockitoExtension.class)来注释您的班级 在Junit 5中,当添加一些不错的Mockito功能时,效果相同。

对我来说看起来也更干净。

我猜Junit 4 @RunWith(MockitoJUnitRunner.class)会产生类似的影响,但我没有测试。

答案 11 :(得分:0)

我遇到了相同的错误

org.mockito.exceptions.misusing.UnfinishedVerificationException: 
Missing method call for verify(mock) here:
-at com.xxx.MyTest.testRun_Should_xxx_When_yyy(MyTest.java:127)

Example of correct verification:
    verify(mock).doSomething()

Also, this error might show up because you verify either of: final/private/equals()/hashCode() methods.
Those methods *cannot* be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.


    at com.xxx.MyTest.validate(MyTest.java:132)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.internal.runners.MethodRoadie.runAfters(MethodRoadie.java:145)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:99)
...

在我的情况下,由于我在调用 Mockito.verify(...)之前使用了 PowerMockito.verifyStatic(),因此产生了错误,将 PowerMockito.verifyStatic()移至最后一行(或将其删除)。

发件人:

PowerMockito.verifyStatic();
Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class));

收件人:

Mockito.verify(myMock, Mockito.times(1)).myMockedMethod(anyString(), anyString(), anyString(), any(XXX.class), any(YYY.class), any(ZZZ.class)); 
PowerMockito.verifyStatic();

答案 12 :(得分:0)

使用Junit 5,您可以添加以下内容以在控制台中显示更有意义的Mockito异常

@AfterEach
public void validate() {
    validateMockitoUsage()
}

也请参见以下答案:https://stackoverflow.com/a/22550055/8073652

答案 13 :(得分:0)

我有类似的问题,我找到了解决这个问题的方法。您要验证的模拟对象已被重置,因此您应该重置它。您可以在测试用例函数之前重置(模拟),这可能会有所帮助。

答案 14 :(得分:0)

我的类MyRepository

有类似的例外
  

org.mockito.exceptions.misusing.UnfinishedVerificationException:   缺少方法调用验证(模拟):    - &GT; at MyRepository $$ FastClassBySpringCGLIB $$ de8d8358.invoke()

     

正确验证的示例:

verify(mock).doSomething()

当我为MyRepository和mock接口创建接口但未实现时,问题得到了解决。 似乎spring创建了一些CGLIB代理,它导致了UnfinishedVerificationException异常。

答案 15 :(得分:-1)

我不知道你的&#34; classUnderTest&#34;来自,但请确保它嘲笑不是真正的。 我在下面的测试用例中遇到了同样的问题:

MyAgent rpc = new MyAgent("myNodeName");
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

但它在以下测试用例中消失了:

MyAgent rpc = PowerMockito.spy(new MyAgent("myNodeName"));
...
rpc.doSomething();
...
PowerMockito.verifyPrivate(rpc).invoke("initPowerSwitch");
PowerMockito.verifyPrivate(rpc).invoke("init", "192.168.0.23", "b2", 3);

注意,对象rpc应该被 PowerMockito.spy(...)嘲笑。

答案 16 :(得分:-1)

在使用 mockStatic 方法并多次调用 Mockito.verify 时遇到同样的异常,但传递的是接口而不是实现类。

错误代码:

try (MockedStatic<Service> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
  staticMock.verify(() -> ServiceImpl.method()); // passed without errors
  staticMock.verify(() -> ServiceImpl.method()); // throws UnfinishedVerificationException 
}

固定代码:

try (MockedStatic<ServiceImpl> staticMock = Mockito.mockStatic(Service.class, Mockito.CALLS_REAL_METHODS)) {
  staticMock.verify(() -> ServiceImpl.method());
  staticMock.verify(() -> ServiceImpl.method());
}

这显然是我的错误,但 UnfinishedVerificationException 消息没有帮助