Mockito简单实用教程 - 第一部分mock
Mockito简单实用教程 - 第一部分mock
- 环境介绍
- 依赖
- 内容
- 1. 检验方法是否有被调用
- 2. 指定mock方法的返回值
- 3. 验证指定次数
- 4. 验证异常
- 5. 校验执行顺序
- 6. 校验形参
- 7. 参数匹配
- 参考
环境介绍
- Junit 4
依赖
分别引入Junit4和Mockito的依赖
<dependencies><dependency><groupId>org.mockito</groupId><artifactId>mockito-all</artifactId><version>1.9.5</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency>
</dependencies>
引入完依赖后,就可以开始我们的Mockito的使用了。
内容
1. 检验方法是否有被调用
@Testpublic void should_call_add_and_clear_method() {// 我们可以mock 一个List接口List mockedList = mock(List.class);mockedList.add(1);mockedList.clear();verify(mockedList, times(1)).add(1);// 因为verify方法默认times为1,还可以写为下面这种形式verify(mockedList).clear();}
2. 指定mock方法的返回值
@Testpublic void should_return_10_when_get_0() {List mockList = mock(List.class);when(mockList.get(0)).thenReturn(10);assertEquals(10, mockList.get(0));//针对于一下没有mock返回值的方法,都会返回默认值(基本类型返回0或者false,引用类型则为null)assertNull(mockList.get(999));}
3. 验证指定次数
@Testpublic void indicate_explicit_verify_count() {List mockList = mock(List.class);mockList.add("once");mockList.add("twice");mockList.add("twice");mockList.add("three times");mockList.add("three times");mockList.add("three times");verify(mockList).add("once");verify(mockList,times(2)).add("twice");verify(mockList,times(3)).add("three times");verify(mockList,times(0)).add("never added");}
4. 验证异常
验证异常有三种方法:
- @Test(expected=XXX) (Mockito可以只看这种方式)
- 使用try…catch…fail()
- 使用JUnit的@Rule注解
- @Test(expected=XXX)
@Test(expected = RuntimeException.class)public void should_throw_RuntimeException1() {List mockList = mock(List.class);//mock当调用add()方法并且参数是1时,抛出RuntimeExceptionwhen(mockList.add(1)).thenThrow(new RuntimeException());//下面的mock抛出异常的方式,其实是上面这一个方法的变种,具体差别不大//doThrow(new RuntimeException()).when(mockList).add(1);mockList.add(1);}
- 使用try…catch…fail()
@Testpublic void should_throw_RuntimeException_use_try_catch_fail() {List mockList = mock(List.class);when(mockList.add(1)).thenThrow(new RuntimeException());try {mockList.add(1);// 如果没有跑异常,则执行到fail方法时,该测试就不通过了fail();}catch (RuntimeException e){// 如果具体方法实现中有catch住异常,还有打logger的话就可以verify logger使用有被调用// 或者继续assert其他的结果}}
- 使用JUnit的@Rule注解
如果要使用这种方式进行校验时,需要加多一个依赖,并且需要放在JUnit依赖的前面。
@Rulepublic ExpectedException expectedException = ExpectedException.none();@Testpublic void should_throw_RuntimeException_use_rule() {List mockList = mock(List.class);when(mockList.get(1)).thenThrow(new RuntimeException("this is runtime exception"));expectedException.expect(RuntimeException.class);// 下面是检验异常信息(非必要)expectedException.expectMessage("runtime exception");mockList.get(1);}
三种校验异常的校验方式的区别:
- @Test(expected=xxx)。只能校验抛出的异常,但是无法再继续校验 抛出异常地方后面的内容了。
- try…catch…fail。fail也是Junit的方法,对比第一种的校验方式,出现异常后,还能在被catch后继续校验后面的内容
- 使用JUnit的@Rule注解,跟第一种相同,但是它还能校验异常的信息,支持正则匹配和SubString.
总的来说,第一二种就够用了,第三种稍微是麻烦了点。
5. 校验执行顺序
@Testpublic void verify_method_called_in_order() {List mockList = mock(List.class);mockList.add("first");mockList.add("second");mockList.add("third");mockList.add("fourth");//此处可以加入多个对象到InOrder中,必须按照调用的顺序去verifyInOrder inOrder = inOrder(mockList);// 如果调换了一下顺序,测试就跑不过了inOrder.verify(mockList).add("first"); // 1inOrder.verify(mockList).add("second"); // 2inOrder.verify(mockList).add("third"); // 3inOrder.verify(mockList).add("fourth"); // 4}
6. 校验形参
@Testpublic void test_capturing_arguments() {ArgumentCaptor<Integer> ageCaptor = ArgumentCaptor.forClass(Integer.class);// 关于spy在下一部分再说,这里可以当成简单去new了一个实例Person person = spy(new Person());person.increaseAge(100);person.increaseAge(1000);// 在verify中校验调用次数,并且使用capture方法捕获形参verify(person,times(2)).setAge(ageCaptor.capture());// 获取调用set方法时所有的形参// 我们调用了两次increaseAge,所以也会调用两次setAge, params:{100,1000}List<Integer> params = ageCaptor.getAllValues();assertEquals(2, params.size());assertEquals(Integer.valueOf(100), params.get(0));assertEquals(Integer.valueOf(1000), params.get(1));}class Person{private int age;public void setAge(int age){this.age = age;}public void increaseAge(int increment){setAge(increment);}}
除了上面的方式,我们还可以通过注解的方式去实现捕获参数
// 第一种,直接在测试类上加
@Runwith(MockitoJUnitRunner.class)
public class TestMockitoOneTest {// 第二种,在@Before的方法中加入
// @Before
// public void setUp() throws Exception {// MockitoAnnotations.initMocks(this);
// }// 第三种,放在构造方法中
// public TestMockitoOneTest() {// MockitoAnnotations.initMocks(this);
// }@CaptorArgumentCaptor<Integer> argumentCaptor;@Testpublic void test_capturing_arguments_by_annotation() {Person person = spy(new Person());person.increaseAge(100);person.increaseAge(1000);verify(person,times(2)).setAge(argumentCaptor.capture());List<Integer> params = argumentCaptor.getAllValues();assertEquals(2, params.size());assertEquals(Integer.valueOf(100), params.get(0));assertEquals(Integer.valueOf(1000), params.get(1));// getValue则是保存最后一次捕获时,参数的值assertEquals(Integer.valueOf(1000), argumentCaptor.getValue());}
}
如果要使用Mockito的注解的话,我们必须还需要额外多加一点内容,让注释能够正常生效,不然测试会直接报NPE。
方法有三种:
- 直接在测试类上加上@Runwith(MockitoJUnitRunner.class)
- 在加了@Before注解的方法中加上 MockitoAnnotations.initMocks(this)
- 可以在测试类的构造方法中加上 MockitoAnnotations.initMocks(this).
但是第三种方法目前仅限于JUnit 4,因为JUnit 4 为了让各个测试方法不相互影响,执行每个测试方法时,会重新实例化测试类对象。
7. 参数匹配
@Testpublic void test_argument_matcher_by_Anonymous_class() {// 类似java里面可以自定义比较器一样,Mockito也可以自定义参数的比较器// 如果有需要mock 对比集合里面的元素时,我们就可以去自定义比较器List mockList = mock(List.class);// 参数一般填需要比较的对象的类型即可when(mockList.contains(argThat(new ArgumentMatcher<Integer>() {public boolean matches(Object o) {return (Integer)o == 1;}}))).thenReturn(true);assertTrue(mockList.contains(1));}@Testpublic void test_argument_matcher_by_inner_class() {List mockList = mock(List.class);when(mockList.contains(argThat(new OddMatcher()))).thenReturn(true);assertFalse(mockList.contains(1));assertTrue(mockList.contains(2));assertFalse(mockList.contains(3));assertTrue(mockList.contains(4));}class OddMatcher extends ArgumentMatcher<Integer>{public boolean matches(Object o) {return ((Integer)o & 1) == 0;}}
参考
官网
Mockito简单实用教程 - 第一部分mock相关推荐
- 【ffmpeg】最全简单实用教程|安装音频视频剪切融合拼接抽帧等
ffmpeg 实用教程(非常全) FFmpeg Download(Mac) brew ffmpeg 常用操作(最全最简单) 音频 音频转换格式 多个音频混音 改变音量大小 音频淡入淡出 调整音频速率 ...
- knockout.js简单实用教程1
第一次接触knockout是在一年多之前吧.当时是接手了一个别人的项目,在项目中有用到knockout来进行数据的绑定.也就开始学习起来knockout.在之后的项目中也多次用到了这个.在第一次开始学 ...
- 【超简单实用教程】mkv、flv格式转mp4格式(附网盘资源)
原写在自己的B站专栏,为了方便,把那篇删了,只放在CSDN里了. 之前看到有人推荐过类似的技术入门帖,想到了自己当初也是从什么都不明白一点点摸索的.不过这篇文章只提了mkv的格式转换,我想顺着这个思路 ...
- 安装Windows、Ubuntu双系统超简单实用教程
目录 一.版本选择 二.安装步骤 1.查看电脑配置 2.制作系统盘 3.在windows下创建空白分区 4.安装系统 Hey, guys!相信很多小伙伴在安装Windows.Ubuntu双系统过程中遇 ...
- 网站制作---科讯万能搜索系统的简单实用教程
很多科汛fans已对系统自带的的简单搜索感谢不满足了,比如做人才网的用户希望能根据职位类型,工作地点,关键字等进行精确搜索,这时如果用KesionCMS自带搜索标签显然不符合要求.很幸运KesionC ...
- 库卡kuka仿真软件sim Pro 3.1简单实用教程
实验目的 建立机器人,自定义抓手,导入外部模型,掌握工具坐标.基坐标的使用,自动生成轨迹. 实验步骤 打开KUKA.Sim Pro 3.1.2仿真软件,依次点击KUKA Sim Library 3.1 ...
- 华硕电脑怎么录屏?华硕电脑录屏功能在哪?简单实用教程来了
有很多小伙伴对如何录制华硕电脑的屏幕知识和信息知之甚少.现在大家都想多了解一些关于华硕电脑怎么录屏的相关知识和信息.所以今天小编收集了一些关于如何录制华硕电脑屏幕的知识和信息,与大家分享. 华硕电脑 ...
- EVE安装与简单使用教程
一.简单安装教程 第一步:eve软件下载(汉化.英文) 参考网址:http://eve-ng.cn/doku.php,里面很全,根据自己需求进行下载,我下载的汉化版 第二步:用VMware虚拟机打开下 ...
- matlab简单程序实例_visual basic VB.NET实例系列教程第一节(简单实用抽奖程序)...
近期疫情原因,工作比较不忙,所以打算出一套零基础,VB.NET实例系列入门教程,实用又好玩,带大家进入VB的编程世界里,希望这套图文教程能帮到有需要的人! 第一节(简单实用抽奖程序) 内容准备:编译环 ...
最新文章
- Ubuntu~Tensorflow~GPU
- 使用帆软finereport实现跳转的一点心得
- 【PAT乙级】1065 单身狗 (25 分)
- vue教程4:自定义组件的使用
- 再谈全局网HBase八大应用场景
- SQL笔记-Oracle中varchar和varchar2的区别
- 软件工程 speedsnail 第二次冲刺1次
- c语言正则表达式库,c语言正则表达式库--PCRE
- 文件操作命令(TYPE)
- 如何在excel表格中查找重复值
- 连接mysql失败怎么办_数据库连接失败有什么原因?怎么解决?
- 域用户本地管理员密码破解
- 对于神经网络学习 Maxwell 方程的思考——泛化能力
- 浏览器指纹:原来我们一直被互联网巨头监视,隐私在网上裸奔、无处可藏
- sqlserver-创建表
- 超级炫酷的动态登陆界面视频背景
- 接口测试平台代码实现2:本平台项目目录解析
- 自动复制吱口令html,【月入六万】吱口令,网页自动复制,进支付宝提示领红包源码...
- 用快解析内网穿透实现零成本自建网站
- 技术2---swagger2
热门文章
- 通过以太坊实现自己的ICO
- 学习人工智能必读这30本书!
- mysql: [Warning] Using a password on the command line interface can be insecure.解决方法
- 【blender建模功能】06 多边形建形工具
- CLion配置STM32开发环境(JLink GDB Server)
- 163VIP邮箱如何注册?163VIP企业邮箱申请介绍!
- NASA全球生态系统动态调查激光雷达(GEDI)
- 机器学习的一些感悟(一)
- html和css学习课件(新版)
- commons-io工具包的基本使用