为什么要使用Mock?

Mock 测试就是在测试过程中,创建一个假的对象,避免你为了测试一个方法,却要自行构建整个 Bean 的依赖链。

举个例子:

类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D、E、F 等,假设类 D 是一个外部服务,那就会很难测,因为你的返回结果会直接的 受外部服务影响,导致你的单元测试可能今天会过、但明天就过不了了。

而当我们引入 Mock 测试时,就可以创建一个假的对象,替换掉真实的 Bean B 和 C,这样在调用B、C的方法时,实际上就会去调用这个假的 Mock 对象的方法,而我们就可以自己设定这个 Mock 对象的参数和期望结果,让我们可以专注在测试当前的类 A,而不会受到其他的外部服务影响,这样测试效率就能提高很多。

比如你现在想要测试一个方法是否是正常的,但是这个方法中有很多调用数据库的代码,那么我们就可以在每个调用数据库的地方打桩,模拟一下访问完数据库之后的返回值,这样我们就可以在测试的时候避免访问数据库了,可以非常高效地完成我们的单元测试,已达到验证我们写的方法到底对不对的目的。

导入依赖

如果你不想自己动手构建一套Mock解决方案,市面上也提供了很多现存的Mock方案。

常用的有:EasyMock、Mockito 、WireMock、JMockit、Mock、Moco。

在这里是使用Mockito做为本次演示使用。

<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>2.8.47</version></dependency><dependency><groupId>org.mockito</groupId><artifactId>mockito-all</artifactId><version>1.7</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency>

使用Mock模拟测试某个类中的某个方法是否可以成功执行

如果我们想要测试某个类中的某个方法是否可以执行,我们不用直接调用这个类的这个方法,我们可以模拟一下这个类,让模拟的对象调用这个方法,然后再去检验一下这个模拟对象是否成功的调用到了这个方法,只要这个模拟对象成功调用到了这个方法,那么就说明,我们真实类中的这个方法是可以被成功执行的。这就是使用mockito来进行某个类的单元测试,如下图:

 /*** 通过mock模拟一个对象,然后检验这个对象的某个方法是否可以执行* */@Testpublic void test1(){//模拟创建一个List对象List mock = mock(List.class);//使用mock模拟出来的List对象,让这个对象添加一个元素1,(我们其实是为了验证List类中的add方法是否正常)mock.add(1);//验证模拟的对象List的add(1)方法是否执行,如果正常发生了,说明List类中的add(1)方法是正常的。这样我们的单元测试就算通过,//verify()的作用主要是检验我们模拟出来的这个对象中的方法是否成功执行,如果成功执行控制台什么信息都没有,如果没有成功//执行,控制台会报错误信息verify(mock).add(1);}

使用Mock模拟某个类的方法,自己给这个方法返回我们指定的值

我们在测试一个控制器中的方法的时候,这个控制器中肯定是有一些方法是需要访问数据库的,但是我们自己在进行单元测试的时候,其实不必访问数据库,我们只需要知道访问数据库之后得到的这个值是什么,所以我们就可以使用Mock来模拟出访问数据库的方法返回的值,下面的这个例子就是我们自己给某个类中的方法直接指定一个返回值,如下图:

 /*** 模拟对象中的某个方法,给这个方法指定一个返回值,那么我们再执行这个模拟对象的方法的时候,返回的值就不再是真实* 对象返回的值,而应该是我们自己设置的返回值。* <p>* 比如我们这里有一个Iterator迭代器,原本调用迭代器对象的next()方法之后返回的值是集合中的下一个元素,我们这里来模拟* 这个方法的返回值,模拟的是第一次调用next()方法返回值是"hello",第二次调用next()方法返回值是"world",第三次以及往后调用* next()方法返回值是"abc"* <p>* 使用到了when(),thenReturn()方法,第一个thenReturn()代表第一次执行iterator.next()方法的返回值是"hello",* 第二个thenReturn()代表第二次执行iterator.next()方法的返回值是"world",* 第三个thenReturn()代表第三次即以后执行iterator.next()方法的返回值都是"abc"* <p>* 还是用到了assertEquals(猜想值,变量)断言方法*/@Testpublic void test2() {//使用mock模拟出一个Iterator类Iterator iterator = mock(Iterator.class);//自己设置迭代器对象方法next()的返回值when(iterator.next()).thenReturn("hello").thenReturn("world").thenReturn("abc");//使用mock模拟的iterator对象,去看看iterator调用next()方法之后的返回值是否是我们想的那样String result = iterator.next() + " " + iterator.next() + " " + iterator.next() + " " + iterator.next();//使用断言验证猜想的结果是否正确assertEquals("hello world abc abc", result);}

使用Mock模拟某个方法调用后会抛出指定的异常

  /*** 使用Mock模拟对象,规定某个方法要抛出一个异常* */@Test(expected = IOException.class)public void test3() throws IOException {OutputStream outputStream = mock(OutputStream.class);//我们自己规定当执行OutputStream对象的close()方法的时候,会主动的抛出一个IOException异常doThrow(new IOException()).when(outputStream).close();outputStream.close();}

什么叫做打桩?以及什么情况下需要打桩什么情况下不需要打桩?

打桩其实就是在真实代码的地方用一个模拟方法代替,然后真实方法执行到这个地方的时候,它的返回值是我们模拟的返回值。when().thenReturn(),用这句代码我们可以自己给某个方法设定返回值,这就叫做打桩。

在什么时候需要打桩呢?如果我们想要自测的方法有返回值,我们需要打桩。

在现实开发中遇到的问题

我们大部分在开发的生活都会遇到这种情况,在一个开发中需要去调用外部的服务,但是由于外部需要远程调用或者还未开发完毕,这个时候为了能正常开发或者单元测试通过。我们需要进行mock这个服务。

例如以下案例:

一个学生的信息需要调用其他外部服务,但是由于外部服务还未开发好,因此先使用Mock进行测试开发。


//邮件服务
public interface MailService {public String getMail();
}
//地址服务
public interface AddressService {public String getAddress();
}

//获取信息汇总
public class StudentManager {@Resourceprivate MailService mailService;@Resourceprivate AddressService addressService;public String getStudentInfo(){return mailService.getMail()+addressService.getAddress();}
}

最后测试:

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;@RunWith(MockitoJUnitRunner.class)
public class StudentManagerTest{@InjectMocksprivate StudentManager studentManager;@Mockprivate AddressService addressService;@Mockprivate MailService mailService;@Testpublic void testGetStudentInfo() {Mockito.when(addressService.getAddress()).thenReturn("杭州市西湖区");Mockito.when(mailService.getMail()).thenReturn("123456@163.com");String studentInfo = studentManager.getStudentInfo();Assert.assertEquals("123456@163.com杭州市西湖区",studentInfo);}
}

使用方法可以参考mockito中文文档

hehonghui/mockito-doc-zh: Mockito框架中文文档 (github.com)。

欢迎关注微信公众号:Java的学习之路

里面资料非常全,从java初级到高级都有,视频,电子书,面试宝典,简历模板,经典案例,源码分析程序员故事以及解决bug方法。。。。应有尽有,可以推荐大家一起学习下!!

如何使用Mock进行单元测试相关推荐

  1. 【全面解析Mock】Mock在单元测试中扮演一个什么角色?

    目录 一.Mock在单元测试中扮演一个什么角色 二.测试准备 三.使用Mock的理由 四.使用Python Mock 五.MagicMock类 六.mock.create_autospce 七.moc ...

  2. 带你读懂mock测试——单元测试实践篇

    1.什么是mock测试? Mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的比较复杂的对象,用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法. 2.为什么要进行Mock测试? ...

  3. Mock进行单元测试

    文章目录 @InjectMocks 使用 1.Maven 2.创建Mock对象 Spy 我认为比较好的一种方式: Mockito 使用 Mock 对象的行为验证 验证调用次数 Spy 对象验证 中文文 ...

  4. mock 抛出一个异常如何终止_教你使用Mock完成单元测试

    更多精彩文章请关注本人微信公众号 1.什么是Mock? mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为.比如说你需要调用B服务,可是B服务还没有开发完成, ...

  5. Mock完成单元测试

    转自:https://zhuanlan.zhihu.com/p/98074553 1.什么是Mock? mock是在测试过程中,对于一些不容易构造/获取的对象,创建一个mock对象来模拟对象的行为.比 ...

  6. 使用Mock进行单元测试

    一.第一次做UT,有一些自己的小收获,记录下,顺便希望能够帮助到别人. 二.Mock mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法 说 ...

  7. Go Mock 接口测试 单元测试 极简教程

    gomock 是 Google 开源的 Golang 测试框架. GoMock is a mocking framework for the Go programming language.https ...

  8. Mock和Java单元测试中的Mock框架Mockito介绍

    什么是Mock? 在面向对象程序设计中,模拟对象(英语:mock object,也译作模仿对象)是以可控的方式模拟真实对象行为的假的对象.程序员通常创造模拟对象(mock object)来测试其他对象 ...

  9. 单元测试中使用Mock对象

    单元测试中使用Mock对象 单元测试中使用Mock对象 一.简单的替换 二.Mock 对象 三.测试 Servlet 单元测试中使用Mock对象 一.简单的替换 假设在代码中,你调用你自己的 getT ...

最新文章

  1. 链表问题7——判断一个链表是否为回文结构(进阶)
  2. 里程碑 | 原来大脑有两套GPS!陆军军医大学张生家团队发现海马外全新空间导航系统...
  3. 源码阅读心得11-13
  4. Qt编程之通过鼠标滚轮事件缩放QGraphicsView里面的Item
  5. 单例模式中的懒汉式以及线程安全性问题
  6. 实现集合类的元素删除和修改的一点实践。。。
  7. ST公司STM32F4与STM32F1的区别
  8. redis的持久化方式有哪些?
  9. 决策树ID3和C4.5算法Python实现源码
  10. python输出不重复的单词_python-如何在文本文件中创建所有单词的列表,但字母重复的单词除外...
  11. 【Linux】一步一步学Linux——which命令(45)
  12. .net core 使用RSA获取私钥证书并签名
  13. 【leetcode】104. Maximum Depth of Binary Tree
  14. BZOJ 1013 球形空间产生器
  15. Stereo Matching文献笔记之(九):经典算法Semi-Global Matching(SGM)之神奇的HMI代价计算~
  16. android oppo 驱动,Android Studio无法连接OPPO
  17. BT.601和BT.656
  18. i3cpu驱动xp_Intel英特尔Core i3/Core i5/Core i7系列CPU核芯显卡驱动 32Bit
  19. 【Unity】Obi插件系列(五)—— 约束
  20. 如何实现直接将文件从windows复制到ubuntu文件夹下

热门文章

  1. 服务器的创意工坊文件,Steam 创意工坊实现指南
  2. Autocad 2007安装和序列号
  3. 【编程笔试】美团2021校招笔试-通用编程题第4场(附思路及C++代码)
  4. python是一种代表简单主义思想的语言_python区别于其他语言的优势是什么
  5. AOV和AOE之间的区别和联系
  6. 拓扑排序之AOV,关键路径之AOE
  7. 谷歌浏览器如何彻底关闭右下角弹出的广告弹窗
  8. 【uiautomation】批量给微信好友/群聊发消息
  9. 大数据的4v特征、数据预处理
  10. Flutter如何使widget始终保持在屏幕底部