如何使用 Mockito 验证带有 ByteBuffer 参数的调用?
Posted
技术标签:
【中文标题】如何使用 Mockito 验证带有 ByteBuffer 参数的调用?【英文标题】:How can I use Mockito to verify calls with ByteBuffer arguments? 【发布时间】:2020-04-22 15:57:37 【问题描述】:我正在尝试为使用 ByteBuffer
的库创建测试。
这里有一个简化版:
public class ByteBufferTest
public static class Stuff
public void doSomething(Target target, ByteBuffer buffer)
ByteBuffer slice = buffer.slice();
slice.limit(1);
target.accept(slice);
target.command();
buffer.position(1);
target.accept(buffer);
// do more with the buffer
buffer.get();
private interface Target
void accept(ByteBuffer slice);
void command();
@Test
public void doSomething()
final Stuff stuff = new Stuff();
final Target mockTarget = Mockito.mock(Target.class);
stuff.doSomething(mockTarget, ByteBuffer.wrap(new byte[]1, 2, 3, 4));
InOrder inOrder = Mockito.inOrder(mockTarget);
inOrder.verify(mockTarget).accept(ByteBuffer.wrap(new byte[]1));
inOrder.verify(mockTarget).command();
inOrder.verify(mockTarget).accept(ByteBuffer.wrap(new byte[]2, 3, 4));
如果doSomething
方法不在末尾有buffer.get();
,这会正常工作。
此测试失败,因为在调用 inOrder.verify(mockTarget).accept(ByteBuffer.wrap(new byte[]2, 3, 4));
时,传入的参数已被之后的 buffer.get()
调用修改。
有没有办法在调用时验证该缓冲区的内容?
【问题讨论】:
这并不意味着测试确实失败了;如果doSomething
方法调用buffer.get()
,则生成的 ByteBuffer 将删除一个附加元素。
在调用accept
时,它包含正确的数据。 doSomething
的约定恰恰是 accept
方法是用数据的子集和数据缓冲区调用的,但 accept
在返回后并不拥有缓冲区。真正的用例要复杂一些(它实际上是解析ByteBuffer
的内容,并将其拆分为 3 部分,前数据、命令和后数据。然后它负责确保消费后数据。
为什么 target 是 mock,但 buffer 不是?这似乎很奇怪。
我处理缓冲区的主要原因不是模拟,是 ByteBuffer 非常“原始”,除了它们是可变的。您可能不会模拟 String 实例,甚至不会模拟原始包装器。所以对我来说,不模拟缓冲区是可以的。
【参考方案1】:
选项A。如果很难测试,也许实现也有问题?每个Target
都应该立即作用于这个缓冲区吗?也许我们只是在第二次调用时交出另一个切片:
target.accept(buffer.slice());
选项 B。不测试平台,只测试交互:
@Test
public void doSomething1()
final Stuff stuff = new Stuff();
final Target mockTarget = mock(Target.class);
final ByteBuffer buffer = mock(ByteBuffer.class);
final ByteBuffer slice = mock(ByteBuffer.class);
given(buffer.slice()).willReturn(slice);
stuff.doSomething(mockTarget, buffer);
final InOrder inOrder = Mockito.inOrder(mockTarget);
inOrder.verify(mockTarget).accept(slice);
inOrder.verify(mockTarget).command();
inOrder.verify(mockTarget).accept(buffer);
选项 C。您自己的 ByteBuffer
测试双重实现通常会给您完全控制权,除非 Buffer/ByteBuffer/HeapByteBuffer 类层次结构不像它那样对测试不友好。
【讨论】:
感谢您的周到回复。这是性能关键代码,所以我想尽可能避免不必要的切片。总的来说,能够在调用时验证参数状态似乎应该得到 Mockito 的支持。 @Daniel 我在回答中又添加了两个想法。 您展示的代码 sn-p 不必要地与 doSomething 的实现细节耦合。 doSomething 的合约是发送数据,发送命令,发送更多数据。它没有(也不应该)指定数据是切片、传入的缓冲区还是构造函数字节缓冲区。 无论如何,我现在决定更改我的代码以重用之前的切片。 好的。是的,最后,要断言的特定交互取决于您的要求。减少这些 slice() 调用听起来像是一种改进。以上是关于如何使用 Mockito 验证带有 ByteBuffer 参数的调用?的主要内容,如果未能解决你的问题,请参考以下文章