有了它(powermock)再也不担心单元测试不达标了
为什么要写单元测试
- 优点:单元测试可以减少bug率,提升代码的质量。还可以通过单元测试来熟悉业务。
- 公司硬性要求:有些公司可能还会强制要求,每次新增代码、或者变更代码单测覆盖率要达到多少比例才能申请代码合并请求。
选择哪个单元测试框架
目前应用比较普遍的java单元测试工具 junit4+Mock(Mockito、jmock、EasyMock、powermock)。为什么会选择powermock?
在做单元测试的时候,我们会发现我们要测试的方法会有很多外部依赖的对象或者一些其他服务的调用比如说(发送邮件,网络通讯,soa调用)。 而我们没法控制这些外部依赖的对象。 为了解决这个问题,我们需要用到Mock来模拟这些外部依赖的对象,从而控制它们。只关心我们自己的业务逻辑是否正确。而这时powermock就起作用了,它不仅可以mock外部的依赖,还可以mock私有方法、final方法,总之它的功能很强大。
什么是powerMocker
PowerMock是一个框架,它以更强大的功能扩展了其他模拟库,例如EasyMock。 PowerMock使用自定义的类加载器和字节码操作来模拟静态方法,构造函数, 最终类和方法,私有方法,删除静态初始化程序等。通过使用自定义类加载器,无需对IDE或持续集成服务器进行任何更改,从而简化了采用过程。熟悉受支持的模拟框架的开发人员会发现PowerMock易于使用,因为整个期望API都是相同的,
无论是静态方法还是构造函数。PowerMock 旨在通过少量方法和注释扩展现有的API,以启用额外的功能。
常用注解
- @RunWith(PowerMockRunner.class)
告诉JUnit使用PowerMockRunner进行测试 - @PrepareForTest({DemoDao.class})
所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类 - @PowerMockIgnore({“javax.management.", "javax.net.ssl.”})
为了解决使用powermock后,提示classloader错误 - @SuppressStaticInitializationFor
不让静态代码加载
其他更多注解可以参考:https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior
如何开始
JUnit 4.4及以上
<properties>
<powermock.version>2.0.2</powermock.version>
</properties>
<dependencies>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>${powermock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
powerMock样例
这是一个需要被mock的类里面有私有方法、静态方法、等等下面一一来演示各个方法的mock功能。
/**
*
* @Date: 2020/3/31
* @Description:
*/
@Repository
public class DemoDao {
public String mockPublicMethod(String type) throws Throwable {
throw new Throwable();
}
public final String mockFinalMethod(String type) throws Throwable {
throw new Throwable();
}
public static String mockStaticMethod(String type) throws Throwable {
throw new Throwable();
}
}
/**
* @Date: 2020/3/31 11:34
* @Description:
*/
@Component
public class DemoService extends AbstractDemo{
@Autowired
private DemoDao demoDao;
public String mockPublicMethod() throws Throwable {
return demoDao.mockPublicMethod("demo");
}
public String mockFinalMethod() throws Throwable {
return demoDao.mockFinalMethod("demo");
}
public String mockStaticMethod() throws Throwable {
return DemoDao.mockStaticMethod("demo");
}
private String callPrivateMethod(String type) {
return type;
}
public String mockPublicMethodCallPrivateMethod(String type) throws Throwable {
return callPrivateMethodThrowable(type);
}
private String callPrivateMethodThrowable(String type) throws Throwable {
throw new Throwable();
}
public String mockExtendMethod(String type) throws Throwable {
return getExtendMethod();
}
public static String UUID = "uuid";
}
mock普通公共方法
/**
* @Date: 2020/4/24
* @Description:
*/
@RunWith(PowerMockRunner.class)
public class DemoServiceTest {
@InjectMocks
private DemoService demoService;
@Mock
private DemoDao demoDao;
/**
* mock 普通方法
* @throws Throwable
*/
@Test
public void mockPublicMethod() throws Throwable {
String type = UUID.randomUUID().toString();
PowerMockito.when(demoDao.mockPublicMethod(any())).thenReturn(type);
String result = demoService.mockPublicMethod();
Assert.assertEquals(type, result);
}
mock Final方法
跟普通方法是一样的,唯一的区别是需要在类上加入PrepareForTest注解
@RunWith(PowerMockRunner.class)
@PrepareForTest(DemoDao.class)
public class DemoServiceTest {
@InjectMocks
private DemoService demoService;
@Mock
private DemoDao demoDao;
/**
* mock final方法
* @throws Throwable
*/
@Test
public void mockFinalMethod() throws Throwable {
String type = UUID.randomUUID().toString();
PowerMockito.when(demoDao.mockFinalMethod(any())).thenReturn(type);
String result = demoService.mockFinalMethod();
Assert.assertEquals(type, result);
}
mock静态方法(使用 PowerMockito.mockStatic)被mock的类也要用PrepareForTest注解修饰。
@RunWith(PowerMockRunner.class)
@PrepareForTest(DemoDao.class)
public class DemoServiceTest {
@InjectMocks
private DemoService demoService;
@Mock
private DemoDao demoDao;
/**
* mock 静态方法
* @throws Throwable
*/
@Test
public void mockStaticMethod() throws Throwable {
String type = UUID.randomUUID().toString();
PowerMockito.mockStatic(DemoDao.class);
PowerMockito.when(DemoDao.mockStaticMethod(any())).thenReturn(type);
String result = demoService.mockStaticMethod();
Assert.assertEquals(type, result);
}
调用 private方法
/**
* 调用私有方法
*
* @throws Throwable
*/
/**
* 调用私有方法
*
* @throws Throwable
*/
@Test
public void callPrivateMethod() throws Throwable {
// 第一种方式
String type = UUID.randomUUID().toString();
Method method = PowerMockito.method(DemoService.class, "callPrivateMethod", String.class);
String result = (String) method.invoke(demoService, type);
Assert.assertEquals(type, result);
//第二种方式
String result1 = Whitebox.invokeMethod(demoService, "callPrivateMethod", type);
Assert.assertEquals(type, result1);
}
mock 私有方法(被mock的类也要用PrepareForTest注解修饰。)
/**
* mock私有方法
*
* @throws Throwable
*/
@Test
public void mockPrivateMethod() throws Throwable {
String type = UUID.randomUUID().toString();
// 重点这一句
demoService = PowerMockito.spy(demoService);
PowerMockito.doReturn(type).when(demoService,"callPrivateMethodThrowable",type);
String result = demoService.mockPublicMethodCallPrivateMethod(type);
Assert.assertEquals(type, result);
}
mock父类方法
/**
* mock父类方法
*
* @throws Throwable
*/
@Test
public void mockExtendMethod() throws Throwable {
String type = UUID.randomUUID().toString();
// 需要mock的父类的方法
Method method = PowerMockito.method(AbstractDemo.class, "getExtendMethod");
// InvocationHandler
PowerMockito.replace(method).with((proxy, method1, args) -> type);
String result = demoService.mockExtendMethod(type);
Assert.assertEquals(type, result);
}
mock构造方法
public DemoService() {
throw new NullPointerException();
}
@Test
public void mockConstructorMethod() throws Throwable {
PowerMockito.whenNew(DemoService.class).withNoArguments().thenReturn(demoService);
}
mock字段
/**
* mock 字段
*/
@Test
public void mockFiled(){
String uuid = UUID.randomUUID().toString();
Whitebox.setInternalState(DemoService.class, "UUID",uuid);
Assert.assertEquals(DemoService.UUID, uuid);
}
mock new对象调用的方法
class DemoDao {
public void newMethod(){
DemoDao demoDao = new DemoDao();
demodao.init();
}
public void init(){
throw new NullPointerException();
}
}
DemoDao demoDao= PowerMockito.mock(DemoDao .class);
PowerMockito.whenNew(DemoDao .class).withNoArguments().thenReturn(demoDao);
PowerMockito.when(demoDao.newMethod()).thenReturn(null);
结束
- 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
- 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
- 感谢您的阅读,十分欢迎并感谢您的关注。
有了它(powermock)再也不担心单元测试不达标了的更多相关文章
- 保姆级神器 Maven,再也不用担心项目构建搞崩了
今天来给大家介绍一款项目构建神器--Maven,不仅能帮我们自动化构建,还能够抽象构建过程,提供构建任务实现:它跨平台,对外提供了一致的操作接口,这一切足以使它成为优秀的.流行的构建工具,从此以后,再 ...
- 妈妈再也不用担心别人问我是否真正用过redis了
1. Memcache与Redis的区别 1.1. 存储方式不同 1.2. 数据支持类型 1.3. 使用底层模型不同 2. Redis支持的数据类型 3. Redis的回收策略 4. Redis小命令 ...
- 锋利的js之妈妈再也不用担心我找错钱了
用js实现收银功能. <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <hea ...
- 【阿里云产品公测】离线归档OAS,再也不用担心备份空间了
[阿里云产品公测]离线归档OAS,再也不用担心备份空间了 作者:阿里云用户莫须有3i 1 起步 1.1 初识OAS 啥是OAS,请看官方说明: 引用: 开放归档服务(Open Archive Se ...
- 有了 tldr,妈妈再也不用担心我记不住命令了
引言 有一次我在培训时说「程序员要善于使用 Terminal 以提高开发效率」,一位程序员反驳道:「这是 21 世纪,我们为什么要用落后的命令行,而不是先进的 GUI?」 是的,在一些人眼里,这个黑黑 ...
- 妈妈再也不用担心我使用git了
妈妈再也不用担心我使用git了 Dec 29, 2014 git git由于其灵活,速度快,离线工作等特点而倍受青睐,下面一步步来总结下git的基本命令和常用操作. 安装msysgit 下载地址:ms ...
- 利用CH341A编程器刷新BIOS,恢复BIOS,妈妈再也不用担心BIOS刷坏了
前几天,修电脑主析就捣鼓刷BIOS,结果刷完黑屏开不了机,立刻意识到完了,BIOS刷错了.就从网上查资料,各种方法试了个遍,什么用处都没有.终于功夫不负有心人,找到了编码器,知道了怎么用.下面看看具体 ...
- python爬虫07 | 有了 BeautifulSoup ,妈妈再也不用担心我的正则表达式了
我们上次做了 你的第一个爬虫,爬取当当网 Top 500 本五星好评书籍 有些朋友觉得 利用正则表达式去提取信息 太特么麻烦了 有没有什么别的方式 更方便过滤我们想要的内容啊 emmmm 你还别说 还 ...
- zzulioj--1841--so easy!麻麻再也不用担心我的数学了!(数学水题)
1841: so easy!麻麻再也不用担心我的数学了! Time Limit: 1 Sec Memory Limit: 128 MB Submit: 27 Solved: 15 SubmitSt ...
随机推荐
- CSRF&SSRF-初探准备
了解CSRF之前的必备知识 1.同源策略 同源策略-三个相同:协议.域名.端口 举例说明: 源URL为:http://www.example.com/dir/page.html 协议为:http 域名 ...
- kali putty远程连接允许以root身份登录
原文链接:https://blog.csdn.net/long_long_chuang/article/details/70227874 kali linux通过ssh+putty来实现远程登录(亲测 ...
- CSP2020复赛游记
CSP2020复赛游记 由于本蒟蒻侥幸通过PJ和TG的分数线并且侥幸的拿了一等,所以侥幸的来参加复赛 11.04~11.05 期中考,挂 11.06 对答案,炸 11.07 开始了第一次CSP复赛 坐 ...
- .Net Core JWT 动态设置接口与权限
通过上一篇.Net Core官方的 JWT 授权验证学习到了JWT的授权.可以发现一个问题,就是如果每个接口可以使用的角色都是写死的,这样如果有所修改会非常麻烦,虽然用policy可以一定程度上缓解, ...
- moviepy音视频剪辑:使用rotate函数实现视频变换处理以及参数expand取值为True时的花屏问题解决方案
☞ ░ 前往老猿Python博文目录 ░ 一.rotate函数功能介绍 moviepy的rotate函数用于将剪辑逆时针旋转指定的角度或弧度. 调用语法:rotate(clip, angle, uni ...
- 第6章 Python中的动态可执行方法 第6.1节 Python代码编译
在介绍动态可执行方法前,本节先介绍一下Python代码编译有关的知识,因为部分内容和动态执行有些关联. 一. Python解释器的功能 Python虽然是解释型语言,但Python代码也是可编译 ...
- 老猿学5G:融合计费的Nchf和Nchf‘服务化接口消息Nchf_ConvergedCharging_Create、Update、Release和Notify
☞ ░ 老猿Python博文目录░ 一.引言 在<老猿学5G扫盲贴:中国移动的5G计费架构解读>介绍了5G融合计费的服务化接口包括: CHF提供给CTF使用的Nchf接口 OCF提供给CH ...
- 老猿学5G扫盲贴:3GPP中的5G计费架构
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.计费逻辑架构和信息流 在32240子系列文档内 ...
- 第11.11节 Python正则表达式的指定重复次数匹配模式及元字符”{}”功能介绍
在<第11.8节 Pytho正则表达式的重复匹配模式及元字符"?". "". "+"功能介绍>和<第11.10节 Pyth ...
- PyQt(Python+Qt)学习随笔:QTableView的wordWrap属性
老猿Python博文目录 老猿Python博客地址 wordWrap属性用于控制视图中数据项文本的换行策略.如果此属性为True,则在数据项文本中分词的适当处进行换:否则数据项文本不进行换行处理.默认 ...