这篇文章是意见。
让我们看一下Mockito中用于在Java中进行测试的verify
方法。
示例: verify(myMock).someFunction(123)
–期望在模拟ONCE上使用输入123
调用someFunction
。
BDDMockito
,我更喜欢完整的BDDMockito
替代方案,因此请编写then(myMock).should().someFunction(123)
。
相同的基本概念。
三种匹配方法
您可以通过三种不同的机制将值提供给验证功能链:
- 对象/文字价值
- 参数匹配器
- 争吵者
我认为,上述也是优先次序,而绑架者是不得已而为之。 让我们探讨一下机制。
具体的测试是最好的
理想情况下,您在理论上将测试定义为类似的内容- 给定此输入,当系统运行时,输出为X。 在验证出站函数调用时,我们冒着测试存在实现线的风险,而不是测试行为,但是可以合理地说,如果系统运行正常,那么我们期望某些事情会发生。发送到某个目标或其他目标。
通常,如果我们将模块设计为具有清晰的输入和清晰的可测量的输出,则可以预测给定输入应输出的内容。
例:
EmailBuilder builder = new EmailBuilder(mockEmailObject); builder.setRecipients( "me@you.com, him@her.com, it@them.com" ); then(mockEmailObject) .should() .addRecipient( "me@you.com" ); then(mockEmailObject) .should() .addRecipient( "him@her.com" ); then(mockEmailObject) .should() .addRecipient( "it@them.com" );
注意:在这里我没有告诉您有关周围代码的任何信息,但是我猜您可以从简单测试中读取setRecipients
的预期行为。
这就是为什么具体的测试数据在测试中占了上风,并且是我们的第一个也是最简单的方法。
当数据不重要时
有时候,我们所关心的并不是输入的价值,而是它的性质。 在上面的示例中,也许我们的某些测试可以跳过使用的电子邮件地址,而是关注更高级别的关注,例如是否拨打了电话或打了多少电话。
如果我在单元测试中看到了这一点,我不会感到震惊:
verify(mockEmailObject, times( 3 )).addRecipient(anyString());
这里使用了一个参数匹配器来进行更模糊的断言,但这也许就足够了。 将所有内容锁定为具体数据可以使测试更加脆弱,尽管对于需要清晰的输入/输出映射的低级算法来说值得这样做,但可以将其降为更高的模糊断言,因为您不必担心关于确切的值。
我们可以在这里使用Mockito的argThat
。
verify(mockEmailObject, times( 3 )) .addRecipient(argThat(recipient -> recipient.matches( "[az]+@[az]+\\.com" )));
argThat
匹配器使我们可以使用Java Predicate
来提供有关期望的一些逻辑。 这使我们能够在此处使用正则表达式来检查电子邮件地址是否正确(在此测试数据的范围内)。 此技巧对于使用GUID或时间戳等生成的值进行测试非常有用。
我们还可以使用argThat
从输入中选择字段进行检查。
但是,当您要对发送到模拟函数的对象进行复杂的断言时,本能是使用ArgumentCaptors
。 我仍然认为它们是不得已的方法。
着迷的俘虏
让我们使用ArgumentCaptor
解决电子邮件正则表达式问题。
// in the instance variable section of the test: @Captor // assuming you're using MockitoExtension/MockitoJUnitRunner... DO! private ArgumentCaptor<String> stringCaptor; @Mock private Email mockEmailObject; @Test void whenAddingRecipientsFromToLine_thenEachIsAddedSeparately() { void EmailBuilder builder = new EmailBuilder(mockEmailObject); builder.setRecipients( "me@you.com, him@her.com, it@them.com" ); then(mockEmailObject) .should(times( 3 )) .addRecipient(stringCaptor.capture()); stringCaptor.getAllValues() .forEach(value -> assertThat(value).matches( "[az]+@[az]+\\.com" ); }
在某些文章中,以上内容是讨论的结局。 饱经风霜的例子。 哇。 看看它是如何构成惊人的创造物的! 但…
尽管以上内容确实说明了如何使用捕获程序,并向您展示了如何拔出所有呼叫或一个呼叫,然后使用自己喜欢的断言库对它进行任何喜欢的断言,以及如何将其与前两个进行比较例子。
比较方式
具体的例子是:
- 叫什么时候
- 然后您得到价值为A的电话
- 还有一个值B
- 还有一个值C
匹配器示例具有:
- 叫什么时候
- 然后,您将获得三个与此表达式匹配的电话
参数捕获示例为:
- 叫什么时候
- 然后您会接到三个电话– 记住他们
- 当您检查这些调用的值时
- 然后他们匹配这些断言
注意:后面的测试在参数捕获时口吃。 接下来的步骤需要检查提取的参数, 然后再进行一些提取操作。 因此,它是一种用于特定目的的工具,其中将断言嵌入argThat
或内置的匹配器之一不够强大,或者没有提供有意义的测试失败输出。
翻译自: https://www.javacodegeeks.com/2020/04/mockito-matchers-precedence.html