Mockito ArgumentMatchers – Mockito ArgumentMatchers

最后修改: 2018年 6月 7日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this tutorial, we’ll learn how to use the ArgumentMatcher, and discuss how it differs from the ArgumentCaptor.

在本教程中,我们将学习如何使用ArgumentMatcher,并讨论它与ArgumentCaptor的区别。

For an introduction to the Mockito framework, please refer to this article.

关于Mockito框架的介绍,请参考这篇文章

2. Maven Dependencies

2.Maven的依赖性

We need to add a single artifact:

我们需要添加一个人工制品。

<dependency>
    <groupId>org.mockito</groupId> 
    <artifactId>mockito-core</artifactId>
    <version>2.21.0</version> 
    <scope>test</scope>
</dependency>

The latest version of Mockito can be found on Maven Central.

Mockito的最新版本可以在Maven Central找到。

3. ArgumentMatchers

3.ArgumentMatchers

We can configure a mocked method in various ways. One option is to return a fixed value:

我们可以通过各种方式来配置一个模拟方法。一个选择是返回一个固定的值。

doReturn("Flower").when(flowerService).analyze("poppy");

In the above example, the String “Flower” is returned only when the analyze service receives the String “poppy.”

在上面的例子中,只有当分析服务收到String “poppy “时,String “Flower “才被返回。

But there may be a case where we need to respond to a wider range of values or unknown values.

但可能会有这样的情况:我们需要对更大范围的价值或未知的价值作出反应。

In these scenarios, we can configure our mocked methods with argument matchers:

在这些情况下,我们可以用argument matchers配置我们的mocked方法:

when(flowerService.analyze(anyString())).thenReturn("Flower");

Now, because of the anyString argument matcher, the result will be the same no matter what value we pass to analyze. ArgumentMatchers allow us flexible verification or stubbing.

现在,因为有了anyString参数匹配器,无论我们传递什么值来分析,结果都是一样的。参数匹配器允许我们灵活地验证或存根。

If a method has more than one argument, we can’t just use ArgumentMatchers for only some of the arguments. Mockito requires that we provide all arguments either by matchers or exact values.

如果一个方法有一个以上的参数,我们不能只对部分参数使用ArgumentMatchersMockito要求我们通过matchers或精确的值来提供所有参数。

Here we can see an example of an incorrect approach:

在这里我们可以看到一个不正确方法的例子。

when(flowerService.isABigFlower("poppy", anyInt())).thenReturn(true);

To fix this and keep the String name “poppy” as desired, we’ll use eq matcher:

为了解决这个问题,并使String的名字 “poppy “符合要求,我们将使用eq matcher

when(flowerService.isABigFlower(eq("poppy"), anyInt())).thenReturn(true);

There are two more points to note when we use matchers:

当我们使用matchers时,还有两点需要注意。

  • We can’t use them as a return value; we require an exact value when stubbing calls.
  • We can’t use argument matchers outside of verification or stubbing.

As per the second point, Mockito will detect the misplaced argument and throw an InvalidUseOfMatchersException.

根据第二点,Mockito将检测到错误的参数并抛出一个InvalidUseOfMatchersException

A bad example of this would be:

这方面的一个坏例子是。

String orMatcher = or(eq("poppy"), endsWith("y"));
verify(flowerService).analyze(orMatcher);

The way we’d implement the above code is:

我们实现上述代码的方式是。

verify(flowerService).analyze(or(eq("poppy"), endsWith("y")));

Mockito also provides AdditionalMatchers to implement common logical operations (‘not’, ‘and’, ‘or’) on ArgumentMatchers that match both primitive and non-primitive types.

Mockito还提供了AdditionalMatchers来实现ArgumentMatchers上的常见逻辑操作(’not’、’and’、’or’),这些操作同时匹配原始和非原始类型。

4. Custom Argument Matcher

4.自定义参数匹配器

Creating our own matcher allows us to select the best possible approach for a given scenario and produce high-quality tests that are clean and maintainable.

创建我们自己的matcher使我们能够为给定的场景选择最佳的方法,并产生高质量的测试,这些测试是干净和可维护的。

For instance, we can have a MessageController that delivers messages. It’ll receive a MessageDTO, and from that, it’ll create a Message that MessageService will deliver.

例如,我们可以有一个MessageController来传递消息。它将接收一个MessageDTO,并从中创建一个Message,由MessageService来传递。

Our verification will be simple; we’ll verify that we called the MessageService exactly 1 time with any Message:

我们的验证将很简单;我们将验证我们是否用任何消息精确地调用了MessageService1次:任何消息。

MessageDTO messageDTO = new MessageDTO();
messageDTO.setFrom("me");
messageDTO.setTo("you");
messageDTO.setText("Hello, you!");

messageController.createMessage(messageDTO);

verify(messageService, times(1)).deliverMessage(any(Message.class));

Since the Message is constructed inside the method under test, we must use any as the matcher.

由于Message是在被测方法中构建的,我们必须使用any作为matcher

This approach doesn’t let us validate the data inside the Message, which can be different from the data inside the MessageDTO.

这种方法不能让我们验证Message中的数据,这可能与MessageDTO中的数据不同。

For this reason, we’ll implement a custom argument matcher:

出于这个原因,我们将实现一个自定义参数匹配器。

public class MessageMatcher implements ArgumentMatcher<Message> {

    private Message left;

    // constructors

    @Override
    public boolean matches(Message right) {
        return left.getFrom().equals(right.getFrom()) &&
          left.getTo().equals(right.getTo()) &&
          left.getText().equals(right.getText()) &&
          right.getDate() != null &&
          right.getId() != null;
    }
}

To use our matcher, we need to modify our test and replace any by argThat:

为了使用我们的匹配器,我们需要修改我们的测试,用argThat替换any

MessageDTO messageDTO = new MessageDTO();
messageDTO.setFrom("me");
messageDTO.setTo("you");
messageDTO.setText("Hello, you!");

messageController.createMessage(messageDTO);

Message message = new Message();
message.setFrom("me");
message.setTo("you");
message.setText("Hello, you!");

verify(messageService, times(1)).deliverMessage(argThat(new MessageMatcher(message)));

Now we know our Message instance will have the same data as our MessageDTO.

现在我们知道我们的Message实例将有与我们的MessageDTO相同的数据。

5. Custom Argument Matcher vs ArgumentCaptor

5.自定义参数匹配器与ArgumentCaptor对比

Both techniques, custom argument matchers and ArgumentCaptor can be used to make sure certain arguments are passed to mocks.

这两种技术,自定义参数匹配器ArgumentCaptor都可以用来确保某些参数被传递给mocks。

However, ArgumentCaptor may be a better fit if we need it to assert on argument values to complete the verification, or our custom argument matcher isn’t likely to be reused.

然而,ArgumentCaptor可能更适合,如果我们需要它断言参数值来完成验证,或者我们的自定义参数匹配器不可能被重用

Custom argument matchers via ArgumentMatcher are usually better for stubbing.

<通过ArgumentMatcher的自定义参数匹配器通常更适合于存根。

6. Conclusion

6.结语

In this article, we explored ArgumentMatcher, a feature of Mockito. We also discussed how it differs from ArgumentCaptor.

在这篇文章中,我们探讨了ArgumentMatcher,这是Mockito的一个功能。我们还讨论了它与ArgumentCaptor的区别。

As always, the full source code of the examples is available over on GitHub.

一如既往,这些示例的完整源代码可在GitHub上获得over