java - Mockito 验证一个方法在 spy 之后被调用一次,尽管它永远不会被调用

标签 java junit mockito

我有一个单元测试,一开始就发现了一个奇怪的问题

    GSLClient gslClient = spy(new GSLSolaceClient());
    String orgId = "10006";
    int orgFlag = Destination.ORG_ID_INPUT_FLAG_APP;
    String eventId = "11010000";
    String scenario = "01";
    String inputDCN = "A00";
    String GSLRetDCN = "FT0";

    //mock
    when(gslClient.requestTargetDCNFromGSLServer(mockGSLBizSeqNo,orgId, eventId, scenario, orgFlag))
            .thenReturn(buildMockSuccessGSLRespMsg(GSLResponse.ORG_FALG_GSL_INPUT, GSLRetDCN))//success for first time
            .thenThrow(new GSLClient.GSLInvokeTimeoutException("Mock GSL timeout"));//timout for the second time

    verify(gslClient, never()).requestTargetDCNFromGSLServer(mockGSLBizSeqNo,orgId, eventId, scenario, orgFlag);

除了模拟我的对象之外,我什么也没做,然后我验证从未调用模拟方法。

但结果给了我:

org.mockito.exceptions.verification.NeverWantedButInvoked: 
gSLSolaceClient.requestTargetDCNFromGSLServer(
    "MOCKGSLBIZSEQNO_GSL_CACHE_TEST",
    "10006",
    "11010000",
    "01",
    0
);
Never wanted here:
-> at cn.webank.rmb.gsl.GSLCacheTest.test_76789232(GSLCacheTest.java:226)
But invoked here:
-> at cn.webank.rmb.gsl.GSLCacheTest.test_76789232(GSLCacheTest.java:222)


    at cn.webank.rmb.gsl.GSLCacheTest.test_76789232(GSLCacheTest.java:226)
    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 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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    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.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

我想知道是否还有其他地方调用此方法所以我尝试删除代码

        when(gslClient.requestTargetDCNFromGSLServer(mockGSLBizSeqNo,orgId, eventId, scenario, orgFlag))
            .thenReturn(buildMockSuccessGSLRespMsg(GSLResponse.ORG_FALG_GSL_INPUT, GSLRetDCN))//success for first time
            .thenThrow(new GSLClient.GSLInvokeTimeoutException("Mock GSL timeout"));//timout for the second time

然后传递结果,证明实际上没有其他地方在调用这个方法。

但是为什么 mockito 会给我这个结果?

我已经尝试了下面的测试,但它通过了!

   {
        //test mock
        Date mockD = spy(new Date());
        when(mockD.getTime())
                .thenReturn(1l)
                .thenThrow(new RuntimeException("mock ex"));
        verify(mockD, never()).getTime();
    }

----------------方法requestTargetDCNFromGSLServer的原始实现就像------------ --

Message requestTargetDCNFromGSLServer(String bizSeqNo, String targetOrgId,String serviceEventId,String scenario,int orgFlag) throws RMBValidationException, RMBIllegalAccessException, GSLInvokeTimeoutException {
    System.out.println("-------------------------------------------------------requestTargetDCNFromGSLServer");//I can only see this log one time
    SysHeader msgHeader = Util.createSysHeader(bizSeqNo,bizSeqNo, SOURCESYSID);
    Destination destination = Util.createSimpleDestination(GSL_SERVICEID,GSL_SCENARIO,GSL_DCN);
    Message reqMessage = Util.createMessage(msgHeader, GSL_APPHEADER,destination, createRequestContent(targetOrgId,serviceEventId,scenario,orgFlag));
    IMessagePublisher synPublisher = getSyncPublisherInstance();
    reqMessage.setTimeToLive(Global.onlyInstance().getGslRequestTimeout());
    Message rspMessage = synPublisher.publish(reqMessage, Global.onlyInstance().getGslRequestTimeout()) ;
    if(rspMessage == null) {
        throw new GSLClient.GSLInvokeTimeoutException("Cannot recieve GSL response at "+ Global.onlyInstance().getGslRequestTimeout()+" ms");
    }else {
        return rspMessage;
    }

}

最佳答案

你在 mock spy ,所以你应该坚持这个 mock 的顺序:

    doReturn(buildMockSuccessGSLRespMsg(GSLResponse.ORG_FALG_GSL_INPUT, GSLRetDCN))
    .doThrow(new GSLClient.GSLInvokeTimeoutException("Mock GSL timeout"))
    .when(gslClient).requestTargetDCNFromGSLServer(
             mockGSLBizSeqNo,orgId, eventId, scenario, orgFlag);

在您当前的情况下,您在模拟时调用了一个真实的实现,这就是您收到错误的原因。当您开始配置时,Mockito 可以“保护” when 方法内的 spy 的真实方法调用。

关于java - Mockito 验证一个方法在 spy 之后被调用一次,尽管它永远不会被调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43886914/

相关文章:

java - Java hashmap 搜索真的是 O(1) 吗?

java - 如何告诉 jetty 将部分 jar 文件提取到其上下文临时位置

java - JUnit 5 @EnumSource 的实际用例是什么?

Maven Surefire 并行 ='both' 的工作方式与 'methods' 相同

unit-testing - Play Framework 2 scala specs2 mockito,如何编写模拟单元测试

java - 哪种类型的 Jfreechart 更适合 Histograms?

java - 将 2d double 数组转换为 2d int 数组

java - 在 ExampleInstrumentedTest.java 文件中获取错误

java - 带有局部变量的 Mockito

java - 如何使用 commons-fileupload 编写单元测试?