【问题标题】:Mockito exception in doThrow that looks correctdoThrow 中看起来正确的 Mockito 异常
【发布时间】:2012-08-29 22:15:04
【问题描述】:

我正在尝试模拟一个方法以查看我是否正确处理了异常。这是据我所知。

界面:

interface SampleManager {
    void deleteVariome(String specimenId, String analysisId) throws Exception;
    // ...
}

单元测试:

// ...
SampleManger sampleManager = mock(SampleManager.class);

// below is line 753
doThrow(Exception.class).when(sampleManager).deleteVariome(sample1.getId(), analysisId);

结果:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at ...server.ArchiveManagerImplUTest.deleteVariomeFails(ArchiveManagerImplUTest.java:753)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod(); <-- this looks a log like what I did!

Hints:

 1. missing thenReturn()

 2. you are trying to stub a final method, you naughty developer! <-- I have a lot of other mocks of this interface in this test that work.

【问题讨论】:

    标签: java mockito


    【解决方案1】:

    从我刚刚遇到的一个相同问题中,我怀疑 sample 是一个模拟,而你在其他地方存根 sample.getId()?无论如何,这在我的情况下导致了这个问题。

    由于某种原因,如果您以这种方式传递给与doThrow 一起使用的存根的参数之一是您也模拟的方法的结果,那么 Mockito 会感到不安。也许这是一种避免无限循环的重入检查,我不知道。

    无论如何,尝试将sample.getId() 替换为常量值,这应该可以解决问题。您可以考虑使用在测试中声明的常量来进行模拟和任何进一步的使用。然后,您还可以通过添加另一个对 verify 的调用来检查您正在测试的方法是否使用了 sample.getId()

    【讨论】:

    • 我遇到了同样的问题。通过不传递常量值而不是模拟来解决它。
    • 谢谢你!我通过在 thenReturn 方法中传递一个局部变量而不是直接来自 getter 的值来解决它。
    【解决方案2】:

    此错误通常在实际发生的地方之后报告。如果您未能正确地存根某些东西,Mockito 通常直到您下次调用其中一个 Mockito 方法时才知道。这可能是在同一个测试方法中,也可能是在同一个类中的后来的测试方法中,甚至是完全不同的测试类中。

    你引用的那句话对我来说很好。看一下它上面的行,您在其中调用了 Mockito 存根或验证方法。您的when 很可能没有关联的thenReturnthenthenThrow。或者您可能有一个 verify 缺少实际的方法调用。还有一些其他的可能性。

    如果您在引用的行上方找不到错误,请发布更多代码,我会仔细查看。

    【讨论】:

    • 此外,如果您使用 JUnit 运行器 MockitoJUnitRunner.class,Mockito 将检查您的测试方法是否没有任何未完成的存根。这将有助于将此错误与问题的根源隔离开来。
    • 致 OP:如果您想确定是否是问题所在,这很容易:只需运行特定的一种测试方法,您应该会发现它工作正常。或者您可以在实际测试逻辑之前放置一个模拟重置,您可能会发现测试运行良好。这些是大卫华莱士所描述的问题的症状
    • 但问题实际上可能出在同一个测试方法上。因此,您可能会在仅运行一种测试方法时遇到错误。在这种情况下,使用MockitoJUnitRunner 也无济于事。
    • 作为@DavidWallace 答案的扩展:不要在thenReturn 调用中调用创建模拟的函数。由于在创建函数内部的模拟时 thenReturn 尚未完成,因此 Mockito 保释。
    【解决方案3】:

    正如 Gijs 的回答中所述,这可能是由于 Mockito 中的一个错误。这是一个重现它的完整测试:

    interface Sample { String getId(); }
    interface SampleManager {
        void deleteVariome(String specimenId, String analysisId);
    }
    
    @Test
    public void probableMockitoBug() {
        Sample sample1 = mock(Sample.class);
        when(sample1.getId()).thenReturn("a");
    
        SampleManager manager = mock(SampleManager.class);
        doThrow(Exception.class).when(manager).deleteVariome(sample1.getId(), "b");
    
        manager.deleteVariome("a", "b");
    }
    

    测试产生以下输出:

    org.mockito.exceptions.misusing.UnfinishedStubbingException: 此处检测到未完成的存根: -> 在 org.mockitousage.JavadocExamplesTest.probableMockitoBug(JavadocExamplesTest.java:404) 例如。 thenReturn() 可能会丢失。 正确的存根示例: 当(模拟。isOk())。然后返回(真); when(mock.isOk()).thenThrow(异常); doThrow(exception).when(mock).someVoidMethod(); 提示: 1. 缺少 thenReturn() 2. 你正试图存根最后的方法,你这个顽皮的开发者! 在 org.mockito.exceptions.Reporter.unfinishedStubbing(Reporter.java:55) 在 org.mockito.internal.progress.MockingProgressImpl.validateState(MockingProgressImpl.java:74) 在 org.mockito.internal.progress.ThreadSafeMockingProgress.validateState(ThreadSafeMockingProgress.java:49) 在 org.mockito.internal.MockHandler.handle(MockHandler.java:71) 在 org.mockito.internal.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:36) 在 org.mockito.internal.creation.MethodInterceptorFilter.intercept(MethodInterceptorFilter.java:48) 在 org.mockitousage.JavadocExamplesTest$Sample$$EnhancerByMockitoWithCGLIB$$d5ac41.getId() 在 org.mockitousage.JavadocExamplesTest.probableMockitoBug(JavadocExamplesTest.java:404) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 org.mockito.internal.runners.JUnit45AndHigherRunnerImpl.run(JUnit45AndHigherRunnerImpl.java:37) 在 org.mockito.runners.MockitoJUnitRunner.run(MockitoJUnitRunner.java:62)

    【讨论】:

    • 如果是这样,那么简单的解决方法是:doThrow(Exception.class).when(manager).deleteVariome("a", "b");
    【解决方案4】:

    您必须提供 Exception.class 的 实例 而不是 Exception 类本身。

    doThrow(new Exception()).when(sampleManager).deleteVariome(sample1.getId(), analysisId);
    

    编辑 好吧,@DavidWallace 纠正了我,所以请注意(或者说是开明的),从 1.9 开始,您可以只提供要抛出的异常类,它会为您构造一个。

    【讨论】:

    • 不,从 Mockito 1.9.0 开始,您可以提供异常类,它会按预期工作。但是,即使 OP 使用的是旧版本的 Mockito,他们也不会得到他们在这里描述的症状。我相信问题是不同的。
    • 谢谢大卫。不知道那个。我会在这里留下我的答案,以便其他人可以通过您的评论了解。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-07
    • 1970-01-01
    • 2023-03-18
    • 2014-04-25
    • 2023-03-05
    • 2021-06-10
    相关资源
    最近更新 更多