2021年2月————技术分享博文(Mock)
作者: 周磊 日期:2021.2.26
参考链接1:基础知识储备-java-Java单元测试之Mock实战
参考链接2:使用TestableMock
参考链接3:Mockito 简明教程
-
应用场景:单元测试
-
解决痛点:单元测试部分内容依赖外部/其他元素,而创建这些元素可能需要创建一连串依赖链上的内容/需要外部环境,创建内容会费时费力,mock技术可将需要依赖的元素替换(拦截)掉, 这样可以把测试的重心完全放在目标类上,达到真正的单元测试
-
技术前置要求:了解单元测试
-
相关产品:Mockito(老牌且名气高)、JMockit、TestableMock(阿里)
Mock技术
Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
比如一段代码有这样的依赖:

当我们需要测试A类的时候,如果没有 Mock,则我们需要把整个依赖树都构建出来,而使用 Mock 的话就可以将结构分解开,像下面这样:

Mock 对象使用范畴
真实对象具有不可确定的行为,产生不可预测的效果(如:股票行情,天气预报) :
- 真实对象很难被创建的
- 真实对象的某些行为很难被触发
- 真实对象实际上还不存在的(和其他开发小组或者和新的硬件打交道)等等
使用 Mock 对象测试的关键步骤
-
使用一个接口来描述这个对象
-
在产品代码中实现这个接口
-
在测试代码中实现这个接口
-
在被测试代码中只是通过接口来引用对象,所以它不知道这个引用的对象是真实对象,还是 Mock 对象。
TestableMock
优点
- 使单元测试能直接调用和访问被测类的私有成员,解决私有成员初始化和私有方法测试的问题
- 使被测类的任意方法调用快速替换为Mock方法,实现"指哪换哪",解决传统Mock工具使用繁琐的问题
- 利用Mock校验器对方法的内部逻辑进行检查
不足
-
官方代码较为简洁,用户量小
-
访问私有变量时,IDE会显示语法错误的问题
-
相关教程较少
Mock方法定义变得零散,生命周期管理起来相对困难,对现有开发者的Mock编写习惯会带来一定改变。(取自官方文档)
简单使用
-
添加相关依赖及配置操作,其余操作请跟随官方说明文档
<dependencies> <dependency> <groupId>com.alibaba.testable</groupId> <artifactId>testable-all</artifactId> <version>0.4.8</version> <scope>test</scope> </dependency> </dependencies>
-
访问私有变量
/* * @program: buildtemplate * * @description: EditController单元测试 * * @author: Zhou Lei * * @create_date: 2021-02-26 09:08:09 * **/ @EnablePrivateAccess //开启私有内容访问设置 public class EditControllerTest { private EditController editController = new EditController(); @Rule public ExpectedException thrown= ExpectedException.none(); @MockConstructor private File createFile(String text) { //mock构造类方法改写new File的动作 return new File("" + text); } @Test public void testgetYmlMap(){ Map map = new HashMap<String, Object>(); Map map1 = new HashMap<String, Object>(); map1.put("port", 8096); map.put("server", map1); Assert.assertEquals(map, editController.getYmlMap("D:\\Project\\look-201221\\test-clone\\new-template\\web\\src\\main\\resources\\application.yml")); verify("createFile").with("D:\\Project\\look-201221\\test-clone\\new-template\\web\\src\\main\\resources\\application.yml"); } @Test public void testaddIntoYaml() throws IOException { Map map = new HashMap<String, Object>(); Map map1 = new HashMap<String, Object>(); map1.put("port", 8096); map.put("server", map1); editController.addIntoYaml("D:\\Project\\look-201221\\test-clone\\new-template\\web\\src\\main\\resources\\application.yml", map); Assert.assertEquals(map, editController.getYmlMap("D:\\Project\\look-201221\\test-clone\\new-template\\web\\src\\main\\resources\\application.yml")); System.out.println("测试访问私有变量"+JSON.toJSONString(editController.dataMap)); thrown.expect(FileNotFoundException.class); thrown.expectMessage(""); editController.addIntoYaml("", map1); } }
-
结果输出