BDDMockito 快速指南,你学会了吗?
创始人
2025-06-27 22:30:35
0

概述

BDD一词最早由Dan North于2006年创造。BDD鼓励用自然的、可读的语言编写测试,重点关注应用程序的行为。

它定义了一种结构清晰的测试编写方式,分为三个部分(排列、动作、断言):

  • 给定一些先决条件(排列)
  • 行动发生时(行动)
  • 然后验证输出(Assert)

Maven依赖项:


    org.mockito
    mockito-core
    2.21.0

包含以下静态导入,我们的测试可以变得更可读:

import static org.mockito.BDDMockito.*;

BDDMockito扩展了Mockito,所以我们不会错过传统Mockito API提供的任何功能。

Mockito与BDDMockito

Mockito传统mock是在排列步骤中使用when(obj).then*()执行的,稍后,可以在Assert步骤中使用verify()验证与mock的交互。

BDDMockito为各种Mockito方法提供了BDD别名,因此我们可以使用given(而不是when)编写Arrange步骤,同样,我们可以使用then(而不是verify)编写Assert步骤。

让我们看一个使用传统Mockito的测试体示例:

when(phoneBookRepository.contains(momContactName))
  .thenReturn(false);
 
phoneBookService.register(momContactName, momPhoneNumber);
 
verify(phoneBookRepository)
  .insert(momContactName, momPhoneNumber);

让我们看看与BDDMockito相比如何:

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);
 
phoneBookService.register(momContactName, momPhoneNumber);
 
then(phoneBookRepository)
  .should()
  .insert(momContactName, momPhoneNumber);

BDDMockito Mock

让我们试着测试PhoneBookService,我们需要模拟PhoneBookRepository:

public class PhoneBookService {
    private PhoneBookRepository phoneBookRepository;

    public void register(String name, String phone) {
        if(!name.isEmpty() && !phone.isEmpty()
          && !phoneBookRepository.contains(name)) {
            phoneBookRepository.insert(name, phone);
        }
    }

    public String search(String name) {
        if(!name.isEmpty() && phoneBookRepository.contains(name)) {
            return phoneBookRepository.getPhoneNumberByContactName(name);
        }
        return null;
    }
}

BDDMockito作为Mockito允许我们返回一个可能是固定的或动态的值。它还允许我们抛出一个异常:

  • 返回固定值

使用BDDMockito,我们可以很容易地将Mockito配置为在调用mock对象目标方法时返回固定结果:

given(phoneBookRepository.contains(momContactName))
  .willReturn(false);
 
phoneBookService.register(xContactName, "");
 
then(phoneBookRepository)
  .should(never())
  .insert(momContactName, momPhoneNumber);
  • 返回动态值

BDDMockito允许我们提供一种更复杂的返回值的方法。我们可以根据输入返回一个动态结果:

given(phoneBookRepository.contains(momContactName))
  .willReturn(true);
given(phoneBookRepository.getPhoneNumberByContactName(momContactName))
  .will((InvocationOnMock invocation) ->
    invocation.getArgument(0).equals(momContactName) 
      ? momPhoneNumber 
      : null);
phoneBookService.search(momContactName);
then(phoneBookRepository)
  .should()
  .getPhoneNumberByContactName(momContactName);
  • 引发异常

告诉Mockito抛出异常非常简单:

given(phoneBookRepository.contains(xContactName))
  .willReturn(false);
willThrow(new RuntimeException())
  .given(phoneBookRepository)
  .insert(any(String.class), eq(tooLongPhoneNumber));

try {
    phoneBookService.register(xContactName, tooLongPhoneNumber);
    fail("Should throw exception");
} catch (RuntimeException ex) { }

then(phoneBookRepository)
  .should(never())
  .insert(momContactName, tooLongPhoneNumber);

注意我们是如何交换given和will的位置,这是强制性的,以防我们mock一个没有返回值的方法。

还要注意,我们使用了(any,eq)等参数匹配器,以提供一种更通用的基于标准而非固定值的mock方式。

结论

我们讨论了BDDMockito如何试图将BDD特性引入Mockito测试,并讨论了Mockito和BDDMockito之间的一些差异。

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...
《非诚勿扰》红人闫凤娇被曝厕所... 【51CTO.com 综合消息360安全专家提醒说,“闫凤娇”、“非诚勿扰”已经被黑客盯上成为了“木...
2012年第四季度互联网状况报... [[71653]]  北京时间4月25日消息,据国外媒体报道,全球知名的云平台公司Akamai Te...