匹配无参数captor的可变对象



我必须测试一种使用可变对象的方法

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());

相关内容

  • 没有找到相关文章

最新更新