Mockito的参数匹配器

该系列文章翻译自https://www.baeldung.com/mockito-series

1.maven依赖


    org.mockito 
    mockito-core
    2.21.0 
    test

Mockito的最新版本请参考https://search.maven.org/classic/#search%7Cgav%7C1%7Cg%3A%22org.mockito%22%20AND%20a%3A%22mockito-core%22

2.参数匹配器

下面的例子中,当analyze方法接受的参数是"poppy"时,会返回"Flower"

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

如果要做到,不管接受的参数是什么,都会返回"Flower",则需要用到anyString匹配器

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

注意,当使用参数匹配器时,必须所有的参数都要用匹配器的方式,而不允许一部分参数是固定值,一部分参数试用匹配器,下面是一个错误的示例:

abstract class FlowerService {
    public abstract boolean isABigFlower(String name, int petals);
}
 
FlowerService mock = mock(FlowerService.class);
 
when(mock.isABigFlower("poppy", anyInt())).thenReturn(true);

可使用eq匹配器修改如下:

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

在使用匹配器时,有两点注意事项

  1. 不能将匹配器作为返回值,而需要返回精确的值
  2. 只能在校验或者模拟过程中使用匹配器,否则Mockito会抛出InvalidUseOfMatchersException异常。

针对第二个情况,一个错误的示例如下:

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

可修改为:

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

在上面的例子中可以看到,Mockito支持在参数匹配器上进行常规的逻辑运算,如‘not’、 ‘and’、‘or’.

3. 自定义参数匹配器


@Controller
@RequestMapping("/message")
public class MessageController {

    @Autowired
    private MessageService messageService;

    @PostMapping
    public Message createMessage (@RequestBody MessageApi messageDTO) {
        Message message = new Message();
        message.setText(messageDTO.getText());
        message.setFrom(messageDTO.getFrom());
        message.setTo(messageDTO.getTo());
        message.setDate(Date.from(Instant.now()));
        message.setId(UUID.randomUUID());

        return messageService.deliverMessage(message);
    }
}
@Service
public class MessageService {

    public Message deliverMessage (Message message) {

        return message;
    }
}

public class Message {

    private String from;
    private String to;
    private String text;
    private Date date;
    private UUID id;

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    public UUID getId() {
        return id;
    }

    public void setId(UUID id) {
        this.id = id;
    }
}

假设我们有一个MessageController,它的createMessage方法接受一个MessageDTO,并构造出Message对象,传递给messageService的deliverMessage().
以下是我们的校验,messageService调用了任何Message对象一次

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

使用any匹配器无法校验Message对象内部更多的细节,比如是否和MessageDTO内部封装的data一致。自定义的参数匹配器如下:

public class MessageMatcher implements ArgumentMatcher {
 
    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;
    }
}

使用自定义参数匹配器时,需要使用argThat,如下:

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

现在我们就可以验证传递到messageService.deliverMessageMessage()方法的mesage和MessageDTO包含相同的数据了。

你可能感兴趣的:(Mockito的参数匹配器)