PowerMocker&Jacoco单元测试全解

第一章 pom文件的引入与各种坑

1. pom文件

<!-- 测试包 -->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope>
</dependency>
<!-- 主要是PowerMocker的工具包 -->
<dependency><groupId>org.powermock</groupId><artifactId>powermock-api-mockito2</artifactId><version>2.0.2</version><scope>test</scope>
</dependency>
<!-- jacocomaven插件包 -->
<dependency><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.2</version>
</dependency>
<!-- powermock -->
<dependency><groupId>org.powermock</groupId><artifactId>powermock-module-junit4</artifactId><version>2.0.2</version><scope>test</scope>
</dependency>

2. 插件

<build><plugins><!-- 主要的插件,我这个用的是离线模式,一定要用离线模式,因为@PrepareForTest 会和传统模式冲突--><plugin><groupId>org.jacoco</groupId><artifactId>jacoco-maven-plugin</artifactId><version>0.8.2</version><executions><execution><id>default-instrument</id><goals><goal>instrument</goal></goals></execution><execution><id>default-restore-instrumented-classes</id><goals><goal>restore-instrumented-classes</goal></goals></execution><execution><id>report</id><phase>prepare-package</phase><goals><goal>report</goal></goals><configuration><dataFile>${project.build.directory}/jacoco.exec</dataFile></configuration></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.22.2</version><configuration><systemPropertyVariables><!-- 生成的jacoco.exec文件就是统计覆盖率的文件--><jacoco-agent.destfile>${project.build.directory}/jacoco.exec</jacoco-agent.destfile></systemPropertyVariables></configuration></plugin><!-- 会生成大量的Test测试文件,但是不建议使用,后面会介绍插件使用--><plugin><groupId>com.github.houbb</groupId><artifactId>gen-test-plugin</artifactId><version>0.0.1</version><configuration><encoding>UTF-8</encoding><isOverwriteWhenExists>false</isOverwriteWhenExists><junitVersion>4</junitVersion></configuration></plugin></plugins>
</build>
########################################################################################
##
## Available variables:
##         $entryList.methodList - List of method composites
##         $entryList.privateMethodList - List of private method composites
##         $entryList.fieldList - ArrayList of class scope field names
##         $entryList.className - class name
##         $entryList.packageName - package name
##         $today - Todays date in yyyy-MM-dd format
##
##            MethodComposite variables:
##                $method.name - Method Name
##                $method.signature - Full method signature in String form
##                $method.reflectionCode - list of strings representing commented out reflection code to access method (Private Methods)
##                $method.paramNames - List of Strings representing the method's parameters' names
##                $method.paramClasses - List of Strings representing the method's parameters' classes
##
## You can configure the output class name using "testClass" variable below.
## Here are some examples:
## Test${entry.ClassName} - will produce TestSomeClass
## ${entry.className}Test - will produce SomeClassTest
##
########################################################################################
##
#macro (cap $strIn)$strIn.valueOf($strIn.charAt(0)).toUpperCase()$strIn.substring(1)#end
## Iterate through the list and generate testcase for every entry.
#foreach ($entry in $entryList)
#set( $testClass="${entry.className}Test")
##
package $entry.packageName; import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.modules.junit4.PowerMockRunner;import java.util.Date;import java.util.List;
import java.util.Map;/*** APPConstant Tester.** @author shihaoyan* @version 1.0* @since ${today}*/
@RunWith(PowerMockRunner.class)
public class $testClass { private ${entry.className} entry = new ${entry.className}();
################################## 属性 #############################
##    #foreach($field in $entry.fieldList)
##    @Mock
##    private $field.valueOf($field.charAt(0)).toUpperCase()$field.substring(1) $field;
##    #end
###################controller层,如果需要注入request、respose进行创建######set($a=0)#foreach($method in $entry.methodList)#foreach($classes in $method.paramClasses)#if($classes.contains('HttpServletRequest')&&$a==0)private MockHttpServletRequest request = new MockHttpServletRequest();       #set($a=1)#end#end#end#set($a=0)#foreach($method in $entry.methodList)#foreach($classes in $method.paramClasses)#if($classes.contains('HttpServletResponse')&&$a==0)private MockHttpServletResponse response = new MockHttpServletResponse();       #set($a=1)#end#end#end
#################### end ###########################################@Beforepublic void setUp() {try {${entry.className} entry1 = new ${entry.className}();entry = PowerMockito.spy(entry);entry.hashCode();entry.equals(entry1);
#####################################################################foreach($field in $entry.fieldList)PowerMockito.field(${entry.className}.class,"$field").set(entry,$field);EasyTestUtils.initMock($field);#end
####################################################################} catch (Exception e) {}}#foreach($method in $entry.methodList) #set($k=0)#set($j=0)#foreach($classes in $method.paramClasses)#set($j=$j+1)#end/** * * Method: $method.signature * */ @Testpublic void test#cap(${method.name})() { try {entry.${method.name}(#foreach($classes in $method.paramClasses)#set($k=$k+1)#if($classes.contains('String')&&!$classes.contains('<')&&!$classes.contains('>')&&!$classes.contains('['))"abcd"#elseif($classes.contains('List'))null#elseif($classes.contains('HttpServletRequest'))request#elseif($classes.contains('HttpServletResponse'))response#elseif($classes.contains('long'))1000L#elseif($classes.contains('Date'))new Date()#elseif($classes.contains('int')&&!$classes.contains('['))1#elseif($classes.contains('int')&&$classes.contains('['))new int[]{1}#elseif($classes.contains('short'))(short)1#elseif($classes.contains('boolean'))true#elseif($classes.contains('byte[]'))"abcd".getBytes()#elseif($classes.contains('String')&&$classes.contains('['))new String[]{"abcd"}#elseif($classes.contains('byte')&&!$classes.contains('['))(byte)1#else null#end#if($k<$j),#end#end);} catch (Exception e) {}} #end
#foreach($method in $entry.privateMethodList) #set($i=0)#set($length=0)#foreach($classes in $method.paramClasses)#set($length=$length+1)#end#set($n=0)/** * * Method: $method.signature **/@Testpublic void test#cap(${method.name})() {  try {PowerMockito.method(${entry.className}.class, "${method.name}"#foreach($classes in $method.paramClasses)#set($i=$i+1)#if($i==1),#end#if($classes.contains('String')&&!$classes.contains('<')&&!$classes.contains('>'))${classes.substring($classes.indexOf('String'))}.class#elseif($classes.contains('List'))List.class#elseif($classes.contains('Set'))Set.class#elseif($classes.contains('HttpServletRequest'))HttpServletRequest.class#elseif($classes.contains('HttpServletRespone'))HttpServletRespone.class#elseif($classes.contains('Map'))Map.class#else${classes}.class#end#if($i<$length),#end#end).invoke(entry #foreach($classes in $method.paramClasses)#set($n=$n+1)#if($n==1),#end#if($classes.contains('String')&&!$classes.contains('<')&&!$classes.contains('>'))"abcd"#elseif($classes.contains('List'))null#elseif($classes.contains('int')&&!$classes.contains('['))1#elseif($classes.contains('short'))(short)1#elseif($classes.contains('boolean'))true#elseif($classes.contains('byte[]'))"abcd".getBytes()#elseif($classes.contains('byte')&&!$classes.contains('[')) (byte)1 #else null #end#if($n<$length),#end#end);} catch (Exception e) {}}
#end
}
#end

第二章 关于插件的使用

第一种:gen-test-plugin

这个是git提供的一个自动插件,能根据模板生成所有Test文件,但是灵活性比较差。推荐使用下面介绍的一款

第二种:JUnitGeneratorV2.0插件

  1. 安装方式:直接在idea设置里面安装就行了。
  2. 配置:

**注意:**Output Path:SOURCEPATH/../../test/java/{SOURCEPATH}/../../test/java/SOURCEPATH/../../test/java/{PACKAGE}/${FILENAME}

这个一定改掉

  1. 模板配置

    ​ 放在上面了。研究一下就能看懂,直接中就行。

  2. 使用方式:alt+insert

  3. 注意事项

    • 如何使用了lomback 会出现错误,需要把源码中的lomback删掉然后手动生成getter/setter,在使用。
    • 如果是service/controller这种需要注入服务对象的类需要把有一段代码开开,会自动生成Field并进行自动Mock
    • 其他的直接用就行,但是会出现错误,但是错误不会很多,我们生成之后 简单调一下就行。

第三章 模板语言 Velocity 语法规则

  1. 定义变量: #set(i=1)
  2. 想要让变量+1:#set(i=i+1)
  3. 引用变量 $i
  4. 循环:#foreach($method in $entry.methodList) … #end
  5. 分支:#if() … #else() … #end
  6. 多分支:#if()… #elseif() … #end
  7. Java中的字符串处理函数都能,所以能玩很多东西。
  8. 学习网址:http://www.51gjie.com/javaweb/900.html

第四章 PowerMocker详解

1. 注解详解

  1. @RunWith(PowerMockRunner.class):每个测试类必须添加
  2. @PowerMockIgnore({“javax.management.*”}):不标记这个注解会出现一个红色的错误,虽然没有任何影响,但是真的非常丑。
  3. @PrepareForTest({}):这个注解非常重要,我们需要测试某些静态方法,或者私有方法,需要XXX.class写在上面。建议先把当前测试类 直接写进去。
  4. Mock:最重要的注解,我们当测试一个类的时候,肯定会出现调用其他的对象,比如说XxxService类,但是这个类可能就是一个接口,也可能太复杂了,不能直接使用,甚至有的还是spring注入的,那就没办法了。我们需要通过声明一个需要的对象,然后添加一个Mock注解,这样就不会出现空指针了,然后交给PowerMock进行管理。

2. 常用方法详解

  1. PowerMockito.when(xxxAAA.getId()).thenReturn(“123”); 这个方法是最重要的,先说明,当我们在一个方法中调用了另一个对象的方法,我们可以直接通过这个方法去模拟返回值,这个是必须的,因为我们调用任何方法都是为了得到一个结果。所以他是必须要会的。
  2. PowerMockito.doNothing().when(对象实例,“方法”,参数);这个可以模拟void方法
  3. Mockito.any()模拟一个任何参数
  4. Mockito.anyString()模拟String类型的参数
  5. Mockito.isNull()模拟null
  6. Mockito.anyXxx()什么都能模拟
  7. 注意:如果要模拟一个方法,出现一个模拟参数,那必须全部都用模拟参数,模拟的方法需要的参数需要注意是不是为null,需要一一对应的不然模拟不到。
  8. PowerMockito.mock(Xxxxx.class) 这个是模拟一个对象类似于@Mock
  9. PowerMockito.mockStatic(Xxxx.class) 如果需要模拟一个静态方法,需要先进行mockstatic,注意需要在@PrepareForTest中添加这个静态类。
  10. PowerMockito.spy(Xxx.class); 其实相当于我们能模拟这个实体类,也会走真正的方法。mock的对象不会走真正的方法的。
  11. PowerMockito.doReturn(返回值).when(对象实例, “方法”,参数列表); 这个方法表示不执行的模拟的方法体,就是调用这个方法 不走原先的方法体直接给你个值。
  12. PowerMockito.field(Xxxxxxxxx.class, “属性名称”).set(对象实例, 注入的值); 能够对方法中的某个属性进行注入。

3. 模拟各种方法

1. 模拟普通:PowerMockito.when(userInfo.getId()).thenReturn("123");
2. 模拟void方法:PowerMockito.doNothing().when(UserInfo.class,"setId","123"));
3. 模拟static方法(模拟静态方法)PowerMockito.when(UserInfo.getId()).thenReturn("123");
4. 模拟static void方法(模拟静态无返回值方法)和模拟void方法一样的。
5. 如果模拟一个普通方法,但是这个方法有异常,我们就需要不走真实的方法,直接走模拟:PowerMockito.doReturn(返回值).when(对象实例, "方法",参数列表);
6. 所有的模拟方法返回参数都可以设置多个,挺有意思的,因为这样可以根据第几次调用某个方法,得到不同的结果。

第五章 各种问题踩坑整理

PowerMocker和jacoco统计覆盖率为零的问题

这个问题其实很多是因为@PrepareForTest注解和jacoco出冲突了。因为jacoco是通过字节码插桩的方式进行统计的,所以有冲突,解决办法就是直接使用离线模式,就是前面介绍的方式。

模拟方法失效的问题

  1. 可能是因为参数不对,就是可能有的参数是null,这个需要单独模拟的。
  2. 可能模拟方式不对,需要变换一个模拟方式 比如所doReturn 或者 thenReturn啊

静态方法模拟失败

可能是没有在注解上声明@PrepareForTest

其他问题

如果碰到其他问题可以私信联系我,一般都能解决。

PowerMockerJacoco单元测试全解相关推荐

  1. Android单元测试全解

      自动化测试麻烦吗?说实在,麻烦!有一定的学习成本.但是,自动化测试有以下优点: 节省时间:可以指定测试某一个activity,不需要一个个自己点 单元测试:既然Java可以进行单元测试,Andro ...

  2. 安卓单元测试全攻略,让代码测试一劳永逸

    本文讲的是 安卓单元测试全攻略,让代码测试一劳永逸, 安卓单元测试,只看这一篇就足够啦.真正的完全解析,真正的从0到1,Junit结合Mockito与Robolectric实现从M到V再到P,Jaco ...

  3. 一般将来时语法课教案_「英语语法」一般过去时用法技巧全解

    大家好,我是教课蚪英语的张老师,今天我们来学习英语语法100讲的第一课,一般过去时! 一.首先我们了解一下什么是一般过去时? 英语语法 1. 概念: 描述过去的状态或过去的动作. 在英语中,非现在的以 ...

  4. atca背板_ATCA介绍全解.ppt

    ATCA介绍全解 ATCA - 概述Advanced Telecommunications Computing Architecture 高性能计算机和网络通信设备的要求: 1) 足够强的数据处理能力 ...

  5. 生成对抗网络gan原理_中国首个“芯片大学”即将落地;生成对抗网络(GAN)的数学原理全解...

    开发者社区技术周刊又和大家见面了,萌妹子主播为您带来第三期"开发者技术联播".让我们一起听听,过去一周有哪些值得我们开发者关注的重要新闻吧. 中国首个芯片大学,南京集成电路大学即将 ...

  6. Java IO编程全解(五)——AIO编程

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7794151.html 前面讲到:Java IO编程全解(四)--NIO编程 NIO2.0引入了新的异步通道的 ...

  7. Sql Server函数全解三数据类型转换函数和文本图像函数

    原文:Sql Server函数全解<三>数据类型转换函数和文本图像函数 一:数据类型转换函数 在同时处理不同数据类型的值时,SQL Server一般会自动进行隐士类型转换.对于数据类型相近 ...

  8. html5相关介绍ppt,html5介绍全解.ppt

    html5介绍全解 渐变 (Gradients) 线性渐变: background: linear-gradient(to right, red, orange, yellow, green, blu ...

  9. 语义分割中的深度学习方法全解:从FCN、SegNet到各版本DeepLab

    语义分割中的深度学习方法全解:从FCN.SegNet到各版本DeepLab 原文:https://www.sohu.com/a/155907339_610300 图像语义分割就是机器自动从图像中分割出 ...

最新文章

  1. 从R-CNN到Mask R-CNN的思维跃迁
  2. python基础学习[python编程从入门到实践读书笔记(连载六)]:数据可视化项目第17章
  3. 单载波调制和OFDM调制比较
  4. 在选择屏幕的标准应用工具条上增加自定义按钮
  5. 关于 SAP 电商云 Spartacus UI 路由 routes 配置的数据源问题
  6. android studio syso快捷键,AndroidStudio代码段简写Live Template
  7. 链表C++ | 根据 位置 / 值 删除节点_2
  8. 如何设置省略号对其序号 html,html – 包含省略号和垂直对齐中间的框中的多行...
  9. QT实现可移动和改变尺寸的无边框窗口
  10. Android 意图和意图过滤器(二)
  11. 英特尔贡献基于 Kubernetes 分布式深度学习平台:Nauta
  12. MySQL 入门(六)—— 索引
  13. Java网络编程之通过代码实现Socket通信
  14. 【SQL】数据库模糊查询
  15. 【计算机基础】防火墙
  16. 淘宝app搜索排名优化技巧
  17. 两个L组成的括号?(取整符号)
  18. php公众号提现功能,公众号赞赏提现
  19. mysql如何不停机迁移_如何实现真正的不停机数据迁移?
  20. 计算机网络 自顶向下 笔记

热门文章

  1. ubuntu播放mp4的插件
  2. word分词器、ansj分词器、mmseg4j分词器、ik-analyzer分词器分词效果评估
  3. 生命体征检测雷达,人体存在感知应用
  4. 还没搞懂正则?熬夜到虚脱整理出来的Python的正则表达式总结(Regular Expression)
  5. 星力+手游运营版本完整版打包下载 代理+服务端+后台+更新+APP
  6. 社区发现算法python视频_社区发现FN算法Python实现
  7. 我对 大内核锁BKL 的理解
  8. Python 中的 Plotly 是什么?
  9. 数据泄露的常见原因是什么,后果是什么?
  10. 谷歌云端硬盘快速下载方法_如何在Google云端硬盘中禁用“快速访问”快捷方式...