如何在mock方法中获取值

时间:2016-09-02 13:23:28

标签: mockito

我在FooService

中有一个服务方法
public void doSomething(){
    ArrayList<Foo> fooList = ...;
    barService.batchAddFoos(fooList); 

    List<String> codeList = new ArrayList<>();
    for (Foo foo : fooList) {
        codeList.add(foo.getCode());
    }
    String key = "foo_codes";
    redisService.sadd(key,codeList.toArray(new String[]{}));
    // other code also need use code
}

BarService.batchAddFoos

    for (Foo foo : foos) {
        foo.setCode(UUID.randomUUID().toString()); // dynamically generate the code value
    }

然后我有一个单元测试来测试FooService逻辑

@Test
public void doSomething() throws Exception {
    fooService.doSomething();
    ArgumentCaptor<List<Foo>> fooListCaptor = ArgumentCaptor.forClass(List.class);
    verify(barService).batchAddFoos(fooListCaptor.capture());
    List<Foo> fooList = fooListCaptor.getValue();
    Assert.assertNotNull(fooList.get(0).getCode()); // check code value is generated successfully
    List<String> codeList = new ArrayList<>();
    for (Foo foo : fooList) {
        codeList.add(foo.getCode());
    }
    verify(redisService).sadd("foo_codes",codeList.toArray(new String[]{}));
}

但它失败了,因为code值为null,实际上它不执行BarService.batchAddFoos中的任何代码。我甚至尝试显式填充代码值,

    fooList.get(0).setCode("aaa");
    fooList.get(1).setCode("bbb");

但它仍然失败。

Argument(s) are different! Wanted:
redisService.sadd("foo_codes", "aaa", "bbb");
Actual invocation has different arguments:
redisService.sadd("foo_codes", null, null);

有什么想法解决这个问题?

2 个答案:

答案 0 :(得分:0)

由于 fooList FooService.doSomething 的局部变量,因此无法从测试中填充它。如果断言如下,则您的测试不会失败:

Mockito.verify(barService).batchAddFoos(fooListCaptor.capture());
List<Foo> fooList = fooListCaptor.getValue();
//Assert.assertNotNull(fooList.get(0).getCode());
Assert.assertFalse(fooList.isEmpty());
...

如果您要使用 Strings.EMPTY 或任何其他非空初始化 Foo 构造函数中的代码价值,你的原始断言将起作用。

答案 1 :(得分:0)

在这种情况下,可以根据需要填充某些对象参数的某些属性,例如

    doAnswer(new Answer() {
        @Override
        public Void answer(InvocationOnMock invocationOnMock) throws Throwable {
            List<Foo> fooList = invocationOnMock.getArgumentAt(0, List.class);
            fooList.get(0).setCode("aaa"); // explicitly specify the first foo object have code of "aaa"
            fooList.get(1).setCode("bbb"); // explicitly specify the second foo object have code of "bbb"
            return null;
        }
    }).when(barService).batchAddFoos(anyList());