java – Mockito验证一个方法在间谍之后调用onces虽然它永远不会调用

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

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

除了模拟我的对象之外我什么都没做,然后我验证了从不调用mock方法.

但结果给了我:

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;
    }

}

解决方法:

你在嘲笑间谍,所以你应该坚持这种嘲笑的顺序:

    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方法内的间谍上的实际方法调用.

上一篇:如何在JUnit测试中忽略Toast?


下一篇:java – Mockito Capture在捕获时不维护捕获的列表