我必须测试一个使用可变对象的方法
private final List<LogMessage> buffer;
...
flushBuffer() {
sender.send(buffer);
buffer.clear();
}
我需要测试它是否发送具有确切大小的缓冲区
ArgumentCaptor
不适用,因为在断言时捕获的集合是清晰的。
是否有一种匹配器可以重复使用Hamcrest的hasSize()
并在方法调用时及时检查?
我更喜欢这个假设的collectionWhich
匹配器:
bufferedSender.flushBuffer();
verify(sender).send(collectionWhich(hasSize(5)));
答案 0 :(得分:2)
David的想法的轻量级替代方法:使用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);
答案 1 :(得分:2)
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)
返回一个无界通配符(?
)。因此,调用者不需要强制转换,因为返回的类型是由目标定义的:这里是声明的变量,我们为其分配结果。
答案 2 :(得分:1)
您将遇到与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();
}
}
现在,您可以检查是否已调用发件人以及其大小(甚至更多)。
所以放下Mockito来创建这个模拟并验证它的行为:
SenderStub sender = new SenderStub();
MyClassToTest myClass = new MyClassToTest(sender);
// action
myClass.flushBuffer();
// assertion
Assert.assertTrue(sender.isInvoked());
Assert.assertEquals(5, sender.getBufferSize());