如何使用在mockito中调用之间更改状态的相同参数来验证相同模拟方法的调用?

Spa*_*ker 3 java unit-testing mockito

我有以下代码进行单元测试:

public void foo() {
    Entity entity = //...
    persistence.save(entity);
    entity.setDate(new Date());
    persistence.save(entity);
}
Run Code Online (Sandbox Code Playgroud)

我想在第一次调用persistence.save entity.getDate()返回时验证null.

因此,我无法使用,Mockito.verify(/*...*/)因为那时方法foo已经完成entity.setDate(Date)并被调用.

所以我认为我需要在调用发生时对调用进行验证.我如何使用Mockito做到这一点?

Spa*_*ker 6

我创建了以下Answer实现:

public class CapturingAnswer<T, R> implements Answer<T> {

    private final Function<InvocationOnMock, R> capturingFunction;

    private final List<R> capturedValues = new ArrayList<R>();

    public CapturingAnswer(final Function<InvocationOnMock, R> capturingFunction) {
        super();
        this.capturingFunction = capturingFunction;
    }

    @Override
    public T answer(final InvocationOnMock invocation) throws Throwable {
        capturedValues.add(capturingFunction.apply(invocation));
        return null;
    }

    public List<R> getCapturedValues() {
        return Collections.unmodifiableList(capturedValues);
    }

}
Run Code Online (Sandbox Code Playgroud)

此答案捕获正在进行的调用的属性.然后capturedValues可以将其用于简单断言.该实现使用Java 8 API.如果不可用,则需要使用能够将其转换InvocationOnMock为捕获值的接口.测试用例中的用法如下:

@Test
public void testSomething() {
    CapturingAnswer<Void,Date> captureDates = new CapturingAnswer<>(this::getEntityDate)
    Mockito.doAnswer(captureDates).when(persistence).save(Mockito.any(Entity.class));

    service.foo();

    Assert.assertNull(captureDates.getCapturedValues().get(0));
}

private Date getEntityDate(InvocationOnMock invocation) {
    Entity entity = (Entity)invocation.getArguments()[0];
    return entity.getDate();
}
Run Code Online (Sandbox Code Playgroud)

Answer使用Mockitos无法实现由所呈现的实现完成的捕获,ArgumentCaptor因为这仅在调用被测方法之后使用.