2019独角兽企业重金招聘Python工程师标准>>>

许多同事怕写单元测试的一个主要原因(或借口)就是依赖太多(redis,mysql,webservice等)。但其实可以用Mockito来模拟相关行为,不用费力去准备各种依赖环境,这时只需专注于业务逻辑即可。

比如有这么一个业务需求,若用户已经购买了容量(20GB,200GB),直接返回容量,若未购买,再判断该用户是否存在,若不存在,提示该用户不存在;若存在则判断是否为激活用户,若为激活用户返回2GB, 若为非激活用户返回1GB。

controller代码如下:

@Autowired
private StorageService storageService;
@Autowired
private UserService userService;
@RequestMapping({ "/storage/userId/{userId}" })
@ResponseBody
public CommonResultDTO getUserStorage(@PathVariable("userId") String userId){CommonResultDTO result = new CommonResultDTO();Integer capacity = storageService.getUserStorage(userId); //查询用户是否购买了容量if(capacity==null){ //没有购买User user = userService.getUser(userId); //查询该用户if(user==null){ //用户不存在result.setStatus(FAILURE_STATUS);result.setMessage(USER_NOT_EXIST);}else if(user.getStatus()==ACTIVE) //激活用户 默认返回2GBcapacity = DEFAULT_ACTIVE_USER_CAPACITY;else if(user.getStatus() == INACTIVE) //未激活用户 默认返回1GBcapacity = DEFAULT_INACTIVE_USER_CAPACITY;}result.setData(capacity);return result;
}

假如只想测试上述业务逻辑,而不想费力去开启本地数据库,并准备各种数据,如插入一条用户购买记录(insert user_storage (user_id, product_id) values(1, 1)),插入一个激活用户(insert into user(user_id, status) values(1, 0)),一个非激活用户。若上述业务还用到了缓存,那准备的工作就更多了.。估计此时大部分开发人员已经打消了写单元测试的念头了,并祈祷这段代码能平平安安。

于是轻易地就把命运交给老天了。

幸好有了Mockito框架,命运又可以掌握在自己手中了,它提供了易用的Api可以让我们仅需关注主要业务逻辑而无需耗费精力在准备繁琐的测试环境上。

见如下示例代码:

@RunWith(MockitoJUnitRunner.class)
public class StorageControllerTest {@InjectMocksprivate StorageController controller;@Mockprivate UserService userService;@Mockprivate StorageService storageService;@Testpublic void test_user_not_exist(){//1. 验证用户不存在String userId = "notexist";// 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);// 当执行userService.getUser(userId)时 返回空 表示用户不存在Mockito.when(userService.getUser(userId)).thenReturn(null);CommonResultDTO result = controller.getUserStorage(userId);Assertions.assertThat(result.getStatus()).isEqualTo(FAILURE_STATUS);Assertions.assertThat(result.getMessage()).isEqualTo(USER_NOT_EXIST);//验证是否执行了storageService.getUserStorage(userId)一次;Mockito.verify(storageService).getUserStorage(userId);//验证是否执行了userService.getUser(userId)一次;Mockito.verify(userService).getUser(userId);}@Testpublic void test_inactive_and_not_buy_user_storage(){//2. 验证未购买且未激活用户的返回容量// 定义一未激活状态用户String userId = "1";User user = new User();user.setStatus(INACTIVE);// 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);// 当执行userService.getUser(userId)时 返回上面定义的未激活状态UserMockito.when(userService.getUser(userId)).thenReturn(user);CommonResultDTO result = controller.getUserStorage(userId);Assertions.assertThat(result.getData()).isEqualTo(DEFAULT_INACTIVE_USER_CAPACITY);//验证是否执行了storageService.getUserStorage(userId);Mockito.verify(storageService).getUserStorage(userId);//验证是否执行了userService.getUser(userId);Mockito.verify(userService).getUser(userId);}@Testpublic void test_active_and_not_buy_user_storage(){//3. 验证未购买但激活用户的返回容量// 定义一激活状态用户对象String userId = "1";User user = new User();user.setStatus(ACTIVE);// 当执行storageService.getUserStorage(userId)时直接返回空 表示未购买Mockito.when(storageService.getUserStorage(userId)).thenReturn(null);// 当执行userService.getUser(userId)时 返回上面定义的激活状态UserMockito.when(userService.getUser(userId)).thenReturn(user);CommonResultDTO result = controller.getUserStorage(userId);Assertions.assertThat(result.getData()).isEqualTo(DEFAULT_ACTIVE_USER_CAPACITY);//验证是否执行了storageService.getUserStorage(userId);Mockito.verify(storageService).getUserStorage(userId);//验证是否执行了userService.getUser(userId);Mockito.verify(userService).getUser(userId);}@Testpublic void test_had_bought_user_storage(){//4. 验证已购买用户的返回容量String userId = "1";// 当执行storageService.getUserStorage(userId)时直接返回20 表示用户购买了20GB的容量final int CAPACITY_20 = 20;Mockito.when(storageService.getUserStorage(userId)).thenReturn(CAPACITY_20);CommonResultDTO result = controller.getUserStorage(userId);Assertions.assertThat(result.getData()).isEqualTo(CAPACITY_20);//验证是否执行了storageService.getUserStorage(userId);Mockito.verify(storageService).getUserStorage(userId);//用户已购买的情况下 不会执行userService.getUser(userId) 故此处设置times(0) 表示未执行Mockito.verify(userService,Mockito.times(0)).getUser(userId);}
}

无需依赖外部环境,只须通过Mockito.when().thenReturn()来准备各种待测条件下的数据(如用户不存在、激活用户、非激活用户等)。

我想若通过了上面这个逻辑严密的测试,对这段代码应该是格外有信心了吧。不用每天在胸前画十字了。

见测试结果:

补充:

Mockito maven 坐标

<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>1.9.5</version>
</dependency>

转载于:https://my.oschina.net/zhuguowei/blog/406764

对代码更有信心--单元测试工具Mockito简单介绍相关推荐

  1. 如何写好测试用例以及go单元测试工具testify简单介绍

    背景 ​ 最近在工作和业余开源贡献中,和单元测试接触的比较频繁.但是在这两个场景之下写出来的单元测试貌似不太一样,即便是同一个代码场景,今天写出来的单元测试和昨天写的也不是很一样,我感受到了对于单元测 ...

  2. 多通道振弦传感器无线采集仪参数配置工具SETP简单介绍

    多通道振弦传感器无线采集仪参数配置工具SETP简单介绍 VS208/416/432 是以振弦.温度传感信号为主的多通道无线采集仪,并可扩展其它 模拟(电流.电压.电阻)信号和数字信号(RS485.RS ...

  3. Postman工具的简单介绍

    Postman工具简单介绍 前言 一.侧边栏 二.工具栏 三.构建器 四.控制台 五.菜单栏 六.状态栏 七.选项卡和窗口 八.键盘快捷键 九.数据编辑器 十.支持多行 前言 Postman提供了一种 ...

  4. python代码自检工具 flake8简单介绍

    PEP 8 是 Python 代码风格规范,它规定了类似行长度.缩进.多行表达式.变量命名约定等内容.尽管你的团队自身可能也会有稍微不同于 PEP 8 的代码风格规范,但任何代码风格规范的目标都是在代 ...

  5. IOS手机自动化一些工具的简单介绍

    工具1XCTest     XCTest是苹果在iOS 7和Xcode5引入的一个简单而强大的测试框架,它的测试编写起来非常简单,并且遵循xUnit风格.XCTest的优点是与Xcode深度集成,有专 ...

  6. 安卓手机自动化一些工具的简单介绍

    工具1Monkey: 工具介绍:Monkey是一个程序,运行在您的模拟器或设备上,并生成伪随机的用户事件流,如点击,触摸或手势,以及一些系统级事件. 您可以使用Monkey以随机但可重复的方式对您正在 ...

  7. java 测试工具 oracle_几种测试工具的简单介绍

    负载测试(Load Test):负载测试是一种性能测试,指数据在超负荷环境中运行,程序是否能够承担. 二.WinRunner WinRunner 是一种企业级的功能测试工具,用于检验企业应用程序是否能 ...

  8. otrs软件_开源ITIL管理工具OTRS简单介绍

    OTRS的名字是由Open-source Ticket Request System首字母縮略字而来,是一个开源的缺陷跟踪管理系统软件.OTRS将电话,邮件等各种渠道提交进来的服务请求归类为不同的队列 ...

  9. 大数据离线分析工具Hive简单介绍

    Hive是Facebook为了解决海量日志数据的分析而开发的,后来开源给了Apache软件基金会,可见Apache软件基金会是个神奇的组织,我们之前学过的很多开源工具都有Apache软件基金会的身影. ...

  10. Linux系统自带日志管理工具rsyslog简单介绍

    1,可以已查看本机的rsyslog服务状态 sudo systemctl status rsyslog 2,可以查看服务的包的版本及配置所在目录 2.1,可以看出这个 /etc/logrotate.d ...

最新文章

  1. android网络获取经纬,Android中透过GPS或NetWork获取当前位置的经纬度
  2. 脚手架koa2+mockjs
  3. Linux Shell脚本实现根据进程名杀死进程
  4. 深究AngularJS——校验(非form表单)
  5. linux搜索文件内容含有星号,文本内容查找grep、文件查找find、正则匹配
  6. 《斑点狗眼里的世界》一书的铅笔画插图
  7. MATLAB中的光照处理
  8. 任正非为什么向两千多年前的李冰父子学习?
  9. 微信小程序开发笔记——开发者工具介绍
  10. abaqus中python怎么建立参考点_怎么在abaqus中选定中心为参考点
  11. 无为而无不为——论老子哲学的深度悖论(转载)
  12. 语音识别-食物声音识别
  13. 原滴滴副总裁叶杰平加盟贝壳找房,任首席科学家,用AI帮你找房
  14. GDAL / OGR 学习手册 [02] :栅格数据读取
  15. 一种基于区块链的身份认证方法
  16. 【QGIS插件安装】buildseg: QGIS plugin for building extraction
  17. vue中同一个依赖引入不同版本
  18. 英特尔的指令集体系结构_INTEL 体系结构 MMX™ 技术开发者手册
  19. OpenWrt 编译及batman-adv组件选择(for Netgear WNDR3800)
  20. C++ map和set

热门文章

  1. 方舟生存进化联机显示没有找到服务器,方舟生存进化搭建服务器联机教程_方舟生存进化怎么联机_牛游戏网...
  2. mysql 复制权限不够_解决不能mysqldump备份权限不够的问题
  3. android期末课设选题_Android课程设计报告书.doc
  4. mysql 修改密码_经验总结 | MYSQL修改密码脚本,值得收藏
  5. sublime配置python开发环境_【教程】把Sublime Text 2用作Python的IDE去实现Python的开发...
  6. 关系抽取;串联抽取和联合抽取论文总结
  7. UnicodeDecodeError: 'gbk' codec can't decode byte 0xab in position 11126: illegal multibyte sequence
  8. 又一轮子?Typescript+React+Redux,放弃saga,支持服务器渲染同构
  9. abrt-hook-ccpp: Saved core dump of pid 12224导致dn挂掉问题
  10. 关于线程join方法的理解