专栏名称: 凤凰牌老熊
互联网金融,软件架构,资深Java工程师
目录
相关文章推荐
芋道源码  ·  日常工作,MQ的8种常用使用场景 ·  昨天  
芋道源码  ·  Redis Plus 来了,性能炸裂! ·  昨天  
芋道源码  ·  面试官问我:自己写String类,包名也是j ... ·  2 天前  
芋道源码  ·  四步帮你把Controller 的代码变得简洁 ·  2 天前  
Java编程精选  ·  手把手教你Java文件断点下载 ·  3 天前  
51好读  ›  专栏  ›  凤凰牌老熊

20180731-pmock单元测试框架

凤凰牌老熊  · 公众号  · Java  · 2018-08-03 07:00

正文

今天分享主要面向java语言的开发和测试开发同学。 先说单元测试、mock测试的定义,再比较几个主流的用于单元测试的mock框架。 说说我遇到的痛点,我在跟踪了公司很多工程的git源码,很少同学进行单元测试,即使做单元测试,java开发童鞋也是使用springjunit,springjunit实际上要启动整个spring框架,相当于基于联通、联调式的单元测试。 根据我的痛点和大家面临的问题,设计了产品思路,然后快速用代码实现了一个mock框架,右面迭代了几个版本,添加了好几个特性。

一、单元测试&mock

1.1 单元测试定义

定义:为检查某个方法是否如预期工作,而写的测试代码。
单元:代码中可度量的最小单元,方法或者函数。
结果:不同的case输入对应的输出是否与预期一致。

1.2 测试层次

如微基准测试、单元测试、功能测试、集成联调测试。如下图,还有一些,我没列出来。

1.3 单元测试的例子

public int sum(int a,int b){
	return a + b;}@Testpublic void sumTest(){
	int sum = sum(1,2);
	assertTrue(sum==3);}

例子很简单,现实中很少这样简单的代码,现实中的代码很复杂,相互依赖多。就引发了mock造假数据进行测试。

二、mock测试的简介

定义:用来虚拟制造对象及数据的,被虚拟制造的对象。
作用:辅助单元测试快速进行的主要手段。
原因:被测试的方法里,依赖的对象,需要被快速被虚拟制造。

mock就是俗称的挡板。

mock测试的好处,主要是隔离系统或者模块,快速并行开发测试和演示。

当然单元测试本身也会倒逼你进行代码抽象和简洁。通常进行codereview,从单元测试入手,是比较鸡贼的好方法。

2.1 被测试方法的示例

public List saveStudent(Student student){
    List<Student> studentList = studentDao.query(student);
    。。。。。
    studentDao.save(student);
    }

省略了很多代码(可以见文末的github源码)。这示例里,case做的不太好,篇幅限制。 mock对象:studentDao,mock方法:query、save。 用例case:输入参数student,mock的返回值,示例里没有展示。

2.2 主流mock框架

java用于单元测试的主流mock框架:easymock、mockito、powermock、spock。 这些框架要学习的关键词包括:given、and、when、 then、 thenReturn 、andReturn、 verify、 where、 times、 expect、 replay等…… 底层实现原理:无非是对被mock的类、接口、方法,进行动态代理或者字节码增强;

2.3 Mockito使用示例

左边图片是被测试的方法,里面调用几个外部对象,包括dao、rpc,然后根据返回的数据进行过滤、处理。右边是mockito框架进行mock测试,可以看出用了刚才提到的很多关键词。 这些都是高阶函数,目前jdk8也支持了函数式编程。函数编程用户体验好。

import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; 

可以通过import static 引入让高阶函数达到最简易。

2.4 Spock使用示例

它使用groovy脚本编写。 groovy另一个杀手级应用是gradle,代替xml实现maven经纬度的繁琐配置。 groovy最大程度兼容了java语法,同时也能用自己的胶水语言风格,也能和java所用框架轻易结合起来,比容spring。 左边图不变,是被测试方法内容。 右边是groovy的mock测试,坐过BDD开发的,应该感到很亲切。

以上介绍了两款mock测试框架,熟悉java开发的同学,应该看出来了,有些缺点。

2.5 主流mock框架缺点

  • 学习成本高、case硬编码&分散、单独维护mock的单元测试。

  • 应对需求变化也不足。

基于以上问题,我根据痛点出发,琢磨了自己的产品思路。

三、pmock框架介绍

我做的这个产品,取名pmock。主要特点:

  • 集中管理case、cese

  • 支持多种jvm脚本编写

  • 0学习成本

  • 无侵入兼容springjunit测试。

如下图的概览。

3.1 pmock代码学习成本

如上图的mockTarget、mockObject、mockField、target四个词。
实现原理:是通过对被mock的类、方法,绑定case脚本文件,进行代理或者代码增强。
如下图:被mock的类和caseConfig目录下的脚本文件一 一映射。可以支持js、groovy、ruby、python等脚本。

3.2 具体使用讲解

  1. PersonBusinessDao.java里有queryPersonList方法,所以需要对PersonBusinessDao的方法queryPersonList进行mock,那么如上图脚本文件里也有。

  2. 上图可以认为就是某个被mock方法的case管理,case无非就是一堆if else,根据输入参数,返回预期想要的数据。

  3. 输入参数由pmock框架对输入对象序列化成json字符串,然后返回的json串有pmock反序列化成对象。当然如果是基本类型,pmock也会自动识别。

另外,如果要返回异常、设置超时、设置响应时间,都可以在脚本的方法里,根据脚本语言特性自己编写。

3.3 PMock特性

详细介绍下pmock优点的几个特性

特性1:兼容springjunit测试,零侵入。即启动spring容器进行单元测试。

下图是正常的springjunit单元测试,实际上PersonBusinessService是被pmock框架进行代理注入的。最终queryStudents方法里面依赖外部调用,都走mock。 不小心创造的好处:单元测试之外的mock。 最后一个特点,可以方便让基于spring框架的微服务之间快速进行各种case的mock测试。不用跨网络,在本机调用就可以。 强调一点:一定要对spring容器启动进行优化,不该注入别注入(可以索要ppt,里面讲如何优化spring容器启动)。

特性2:显式使用pmock方法,侵入性极简。使用了mockTarget、mockObject、mockField、target四个词进行mock制作。

特性3:case在线集中配置,让case配置彻底脱离工程,这和配置中心一个原理。

右图和左图在一个页面。右图可以在线运行你左图配置的case,在线输入参数,然后返回你预期的数值。 pmock框架启动,如果不走本地工程case映射,将向case中心请求case文件。源码工程pmockserve需要单独部署服务器,用于case配置中心。

特性4:也是最早的版本,使用探针javaagent无侵入

下图红框里即是通过探针进行代码增强的。现在不鼓励使用这个特性,容易忘记配置javaagent,且不能实现接口mock。







请到「今天看啥」查看全文