【问题标题】:Mock and argument capture in the same method call在同一方法调用中模拟和参数捕获
【发布时间】:2018-08-17 21:03:53
【问题描述】:

我有以下方法/类

public class SomeServiceImpl{

    @Value("${someUrl}")
    private String someUrl;

    @Autowired
    private RestClientUtil restClientUtil;

    @Autowired
    private ObjectMapper objectMapper;

    public Some getSomeData(String place,String date) throws Exception{

        String response = null;
        someUrl = someUrl+ "?location="+place+"+date=+"+date;
        try {
            response = restClientUtil.getHttpCall(null, null, someUrl, null);
        } catch (Exception e) {
            e.printStackTrace();
            throw new Exception("Some Data Api call failed ");
        }

        Some some = objectMapper.readValue(response,Some.class);

        return some;
    }
}

下面是我尝试使用spring boot test mockito框架编写的对应测试用例。

@RunWith(SpringRunner.class)
@SpringBootTest
@TestPropertySource(properties={"someUrl = http://www.some_url.com"})
public class SomeServiceImplTests {

    @Value("${someUrl}")
    private String someUrl;

    @MockBean
    private RestClientUtil mockRestClientUtil;

    @MockBean
    private ObjectMapper mockObjectMapper;

    @Autowired
    private SomeServiceImpl someServiceImpl;



    @Test
    public void testGetSomeData() throws Exception{
        String place = "NewYork";
        Date date = new Date();
        String response = "xyz";
        Some  some = new Some();
        String username=  null;
        String password=  null;
        Map<String,String> headerMap = null;

        ArgumentCaptor<String> userNameCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> passwordCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<String> urlCaptor = ArgumentCaptor.forClass(String.class);
        ArgumentCaptor<Map<String,String>> headerCaptor = ArgumentCaptor.forClass(Map.class);

        String capusername = userNameCaptor.capture();
        String cappassword = passwordCaptor.capture();
        String capurl = urlCaptor.capture();
        Map<String,String> capHeader = headerCaptor.capture();



        when(mockRestClientUtil.getHttpCall(capusername,cappassword,capurl,capHeader)).thenReturn(response);

        ArgumentCaptor<String> responseCaptor = ArgumentCaptor.forClass(String.class);
        String capresponse = responseCaptor.capture();
        when(mockObjectMapper.readValue(capresponse,eq(Some.class))).thenReturn(some);

        assertEquals(some,someServiceImpl.getSomeData(place,date.toString()));


        verify(mockRestClientUtil, times(1)).getHttpCall(capusername,cappassword,capurl,capHeader);
        verify(mockObjectMapper,times(1)).readValue(capresponse, eq(Some.class));




        assertEquals(response,capresponse);
        assertEquals(username,capusername);
        assertEquals(password,cappassword);
        assertEquals(someUrl+ "?location="+place+"+date=+"+date,urlCaptor.getValue());
        assertEquals(headerMap,capHeader);
    }
}

我无法捕获和验证 httpcall 方法的参数并随后验证整个 getSomeData 方法。

我目前面临以下异常。

Argument(s) are different! Wanted:
restClientUtil bean.getHttpCall(
    null,
    null,
    null,
    null
);
-> at com.x.x.service.impl.SomeServiceImplTests.testGetSomeData(SomeServiceImplTests.java:83)
Actual invocation has different arguments:
restClientUtil bean.getHttpCall(
    null,
    null,
    "http://www.some_url.com?location=NewYork+date=+Sat Aug 18 02:15:28 IST 2018",
    null
);
-> at com.x.x.service.impl.SomeServiceImpl.getSomeData(SomeServiceImpl.java:36)

    at com.x.x.service.impl.SomeServiceImplTests.testGetSomeData(SomeServiceImplTests.java:83)
    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:497)
    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.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
    at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
    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.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

我尝试重新排序 verify、capture 和 assert 语句来试试我的运气。没有任何效果!

需要帮助。 谢谢

【问题讨论】:

  • 您正在尝试在调用该方法之前进行捕获。在这种情况下,无需将参数捕获到mockRestClientUtil。只需when(mockRestClientUtil.getHttpCall(null,null,someUrl,null)).thenReturn(response)。如果没有使用这些参数值调用它,则结果将为null,并且验证将失败。

标签: java spring unit-testing junit mockito


【解决方案1】:

通常的做法是先处理mocking,然后用capture做verify,再处理assertions。

类似的东西(未经测试,并且不想使用与您一样多的参数):

@Test
public void testThing() {
    final String response = "Pong";
    final String arg = "Ping";

    doReturn(response).when(mockService).call(arg);

    serviceWhichCallsMockService.triggerPing();

    final ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);

    verify(mockService).call(captor.capture());

    final String receivedArg = captor.getValue();

    // Confirms 'triggerPing' passed 'Ping' to your 'mockService'
    assertEquals(arg, receivedArg);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-12
    • 1970-01-01
    • 1970-01-01
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多