Mockito:模拟一个操纵输入参数的方法

时间:2017-11-18 13:10:03

标签: junit mockito

以前曾经问过,但我看不出相同的问题。当然看不出解决方案。

我正在尝试模拟将数据库保存到数据库的数据库Dao调用。 Dao调用返回新的PK,但也通过更新PK来修改传递的对象。

我的测试正在按照我的意愿运行,但验证失败说我没有传递预期的对象。然而,当我在调试器中暂停时,我可以看到插入确实接受了没有PK的对象。然后修改它&调用控制器可以看到更改的对象。

@Test
public void insertSampleAnalyteLabConfig() throws Exception {
    int newInt = 99;

    SampleAnalyteLabConfig sampleAnalyteLabConfig = createMockSampleAnalyteLabConfig(null);
    SampleAnalyteLabConfig sampleAnalyteLabConfig2 = createMockSampleAnalyteLabConfig(null);

    when(sampleAnalyteLabConfigService.save(sampleAnalyteLabConfig)).thenAnswer( invocation -> {
                SampleAnalyteLabConfig foo = (SampleAnalyteLabConfig) invocation.getArguments()[0];
                foo.setId(newInt);
                return new Long(newInt);
            }
    );

    mockMvc.perform(post("/api/lab/sampleanalytelab")
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .content(getBytes(sampleAnalyteLabConfig))).andExpect(status().isCreated());

    verify(sampleAnalyteLabConfigService, times(1)).save(sampleAnalyteLabConfig2);
}

测试输出如下:

争论是不同的!通缉: sampleAnalyteLabConfigService.save(     SampleAnalyteLabConfig {{id = 0} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null} ); - >在com.foo.controllers.LabControllerTest.insertSampleAnalyteLabConfig(LabControllerTest.java:236) 实际调用有不同的参数: sampleAnalyteLabConfigService.save(     SampleAnalyteLabConfig {{id = 99} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null} ); - >在com.foo.controllers.LabController.saveSampleAnalyteLabConfig(LabController.java:165)

比较失败:

争论是不同的!通缉: sampleAnalyteLabConfigService.save(     SampleAnalyteLabConfig {{id = 0} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null} ); - >在com.foo.controllers.LabControllerTest.insertSampleAnalyteLabConfig(LabControllerTest.java:236) 实际调用有不同的参数: sampleAnalyteLabConfigService.save(     SampleAnalyteLabConfig {{id = 99} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null} ); - >在com.foo.controllers.LabController.saveSampleAnalyteLabConfig(LabController.java:165)

at com.foo.controllers.LabControllerTest.insertSampleAnalyteLabConfig(LabControllerTest.java:236)
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.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
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.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)

与目标虚拟机断开连接,地址:'127.0.0.1:61076',传输:'socket'

处理以退出代码-1

结束

2 个答案:

答案 0 :(得分:2)

默认情况下,当您将直接值传递给equalswhen时,Mockito会使用Java verify。你所看到的是你创建了两个独立的SampleAnalyteLabConfig个实例,你在一个实例(它被修改为添加其ID)中传递了一个不同的实例(未被修改)。假设equalshashCode有效,请确保您正在准备要验证的实例,以匹配您要比较的修改后的实例。

SampleAnalyteLabConfig sampleAnalyteLabConfig = createMockSampleAnalyteLabConfig(null);
SampleAnalyteLabConfig sampleAnalyteLabConfig2 = createMockSampleAnalyteLabConfig(null);

// ...
verify(sampleAnalyteLabConfigService, times(1)).save(sampleAnalyteLabConfig2);
  

争论是不同的!通缉:sampleAnalyteLabConfigService.save(SampleAnalyteLabConfig { {id = 0} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null}); - >在com.foo.controllers.LabControllerTest.insertSampleAnalyteLabConfig(LabControllerTest.java:236)

     

实际调用具有不同的参数:sampleAnalyteLabConfigService.save(SampleAnalyteLabConfig { {id = 99} sampleId = 2,analyteId = 3,labId = 1,numberOfRounds = null,absolutePerformanceScoreWarning = null}); - >在com.foo.controllers.LabController.saveSampleAnalyteLabConfig(LabController.java:165)

来自评论:

  

我知道我可以在sampleAnalyteLabConfig2上设置setId(),但这是我的问题,因为没有使用Id设置调用save()方法,所以要求verify()确认调用setId()调用是错误的IMO。

Mockito不在制作对象副本:当您使用verify检查对象时,您正在检查实例的当前状态,包括在此期间对其进行的任何修改或致电您的服务后。在考虑对象的三个实例时,记住这一点很重要:您的sampleAnalyteLabConfig,您的sampleAnalyteLabConfig2以及ObjectMapper创建的实例,然后将其传递到您的服务中。

您所做的验证声明将验证ObjectMapper创建的一个实例的后save状态,包括您在答案中对foo.setId(newInt);的调用。您没有验证在通话期间制作的实例的快照,因为Mockito没有制作实例。

一般来说,我认为在setId(newInt)上调用sampleAnalyteLabConfig2并对其进行测试是安全的,因为newInt是一个唯一的整数,除了您的测试之外不太可能来自任何地方:您可以从成功的验证中推断出该对象已经完全传递和修改,并且只能按照您的预期进行修改。那肯定是我会做的。但是,如果要检查传递到save的实例的修改前状态,则应该删除状态修改答案将你的断言移到答案中。 (您也可以在更改答案中的状态之前克隆该实例,并测试克隆,但除了使用已编写的库或帮助程序传入该状态之外,这并不具有太多价值。)

答案 1 :(得分:0)

所以我去过的解决方案 - 感谢@Jeff Bowman在上面的讨论中的帮助是将验证嵌入到Answer()中。

为了清楚起见,我把它作为一个单独的答案。

count