我必须测试一种使用可变对象的方法
private final List<LogMessage> buffer;
...
flushBuffer() {
sender.send(buffer);
buffer.clear();
}
我需要测试它是否发送具有精确尺寸的缓冲区。
ArgumentCaptor
不适用,因为捕获的集合在断言时清楚。
是否有一种匹配器可以重复使用Hamcrest的hasSize()
并在方法呼叫时正确检查吗?
我更喜欢这种假设的collectionWhich
匹配器:
bufferedSender.flushBuffer();
verify(sender).send(collectionWhich(hasSize(5)));
大卫想法的轻量级替代品:使用Answer
在呼叫时制作副本。未经测试的代码,但这应该非常接近:
final List<LogMessage> capturedList = new ArrayList<>();
// This uses a lambda, but you could also do it with an anonymous inner class:
// new Answer<Void>() {
// @Override public Void answer(InvocationOnMock invocation) { /* ... */ }
// }
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> argument = (List<LogMessage>) invocation.getArguments()[0];
capturedList.addAll(argument);
});
bufferedSender.flushBuffer();
assertThat(capturedList).hasSize(5);
杰夫·鲍曼(Jeff Bowman(的答案很好,但我认为我们可以通过将Answer
对象本身中的断言来改进它。它避免创建不必要的复制对象和其他本地变量。
在我们需要复制自定义对象状态的情况下(通过执行深度副本(,这种方式要简单得多。实际上,它不需要任何自定义代码或库来执行副本,因为断言是在即时完成的。
在Java 8中,它将给出:
import static org.mockito.Mockito.*;
when(sender.send(any())).thenAnswer(invocation -> {
List<LogMessage> listAtMockTime = invocation.getArguments()[0];
Assert.assertEquals(5, listAtMockTime.getSize());
});
bufferedSender.flushBuffer();
请注意,InvocationOnMock.getArgument(int index)
返回无限的通配符(?
(。因此,由于返回的类型由目标定义,因此不需要呼叫者的铸件:此处声明的变量我们分配了结果。
您将遇到与ArgumenCaptor
相同的问题,因为verify()
方法在执行后使用对象状态检查调用。没有执行任何捕获以在调用时保持状态。
因此,使用一个可变的对象,我认为更好的方法是不使用Mockito,而是创建Sender
类的存根,在其中您可以捕获集合的实际大小,因为send()
被调用。
这是一个样本存根类(您当然可以丰富/适应的最小示例(:
class SenderStub extends Sender {
private int bufferSize;
private boolean isSendInvoked;
public int getBufferSize() {
return bufferSize;
}
public boolean isSendInvoked(){
return isSendInvoked;
}
@Override
public void send(List<LogMessage> buffer ) {
this.isSendInvoked = true;
this.bufferSize = buffer.size();
}
}
现在,您可以检查发件人是否被调用,并且大小(甚至更多(。
,因此请抛开嘲讽以创建此模拟并验证其行为:
SenderStub sender = new SenderStub();
MyClassToTest myClass = new MyClassToTest(sender);
// action
myClass.flushBuffer();
// assertion
Assert.assertTrue(sender.isInvoked());
Assert.assertEquals(5, sender.getBufferSize());