无所不能的PowerMock,mock私有方法,静态方法,测试私有方法,final类
1、为什么要用mock
我的一本书的解释:
(1)创建所需的DB数据可能需要很长时间,如:调用别的接口,模拟很多数据
(2)调用第三方API接口,测试很慢,
(3)编写满足所有外部依赖的测试可能很复杂,复杂到不值得编写,Mock模拟内部或外部依赖可以帮助我们解决这些问题
另一本TDD书的解释:
(1)对象的结果不确定,如每获取当前时间,得到的结果都不一样,无法符合我们的预期;
(2)实现这个接口的对象不存在;
(3)对象速度缓慢
对于TDD还有一个更重要原因:通过模拟可以隔离当前方法使用的的所有依赖,让我们更加专注于单个单元,忽略其调用的代码的内部工作原理
一本博客的干货:
(1)Mock可以用来解除测试对象对外部服务的依赖(比如数据库,第三方接口等),使得测试用例可以独立运行。不管是传统的单体应用,还是现在流行的微服务,这点都特别重要,因为任何外部依赖的存在都会极大的限制测试用例的可迁移性和稳定性。
(2)Mock的第二个好处是替换外部服务调用,提升测试用例的运行速度。任何外部服务调用至少是跨进程级别的消耗,甚至是跨系统、跨网络的消耗,而Mock可以把消耗降低到进程内。比如原来一次秒级的网络请求,通过Mock可以降至毫秒级,整整3个数量级的差别。
(3)Mock的第三个好处是提升测试效率。这里说的测试效率有两层含义。第一层含义是单位时间运行的测试用例数,这是运行速度提升带来的直接好处。而第二层含义是一个测试人员单位时间创建的测试用例数。
以单体应用为例,随着业务复杂度的上升,为了运行一个测试用例可能需要准备很多测试数据,与此同时还要尽量保证多个测试用例之间的测试数据互不干扰。为了做到这一点,测试人员往往需要花费大量的时间来维护一套可运行的测试数据。有了Mock之后,由于去除了测试用例之间共享的数据库依赖,测试人员就可以针对每一个或者每一组测试用例设计一套独立的测试数据,从而很容易的做到不同测试用例之间的数据隔离性。而对于微服务,由于一个微服务可能级联依赖很多其他的微服务,运行一个测试用例甚至需要跨系统准备一套测试数据,如果没有Mock,基本上可以说是不可能的。因此,不管是单体应用还是微服务,有了Mock之后,QE就可以省去大量的准备测试数据的时间,专注于测试用例本身,自然也就提升了单人的测试效率。
现如今比较流行的Mock工具如jMock 、EasyMock 、Mockito等都有一个共同的缺点:不能mock静态、final、私有方法等。而PowerMock能够完美的弥补以上三个Mock工具的不足
2、实战:
好了,我们用PoweMockito框架,直接上代码:如何mock私有方法,静态方法,测试私有方法,final类
依赖:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.7.4</version>
<scope>test</scope>
</dependency>
powermock可能与mockito有版本冲突,我们可以讲mockito版本改成2.8.47 :
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mockito.version>2.8.47</mockito.version>
</properties>
service层代码:一个简单的保存,返回user,这里就不调用持久层了
@Override
public User save(User user) {
return user;
}
controller层代码:一些简单的调用,接下来写个test 调用controller方法,mock service里面的保存,mock controller的私有方法和静态方法,测试controller的private的私有方法
package com.example.demo.controller; import com.example.demo.entity.User;
import com.example.demo.service.UserService; public final class UserController { private final UserService service; public UserController(UserService service) {
this.service = service;
} public User saveUser(User user) {
User save = service.save(user);
return save;
} public String returnName(){
return getStaticName("ljw1");
} public static String getStaticName(String name) {
return "A_" + name;
}
public String getPrivateName(String name) { if (publicCheck()){
return "public 被mock 了";
}
if (check(name)){
return "private 被mock 了";
}
return "A_" + name;
} public boolean publicCheck() {
return false;
} private boolean check(String name) {
return false;
} private String say(String content) {
return "ljw say " + content;
} }
test:测试,注释写的很清楚,把代码拷贝过去,就可以用了,我已经验证过,user类就一个字段id,不附代码了,注意:测试private方法和mock private方法的区别
package com.example.demo.demo1; import com.example.demo.controller.UserController;
import com.example.demo.entity.User;
import com.example.demo.service.impl.UserServiceImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.powermock.api.mockito.PowerMockito.when;
@RunWith(PowerMockRunner.class)
@PrepareForTest(UserController.class)
public class LastMock {
@Mock
private UserServiceImpl serviceImpl; @InjectMocks
private UserController controller; /**
* mock service的保存方法
*/
@Test
public void mockSave() {
User user1 = new User();
User user2 = new User();
user1.setId("1");
user2.setId("2");
Mockito.when(serviceImpl.save(user1)).thenReturn(user2); //当调用service的save()时,mock让他返回user2
User saveUser = controller.saveUser(user1); //调用
Mockito.verify(serviceImpl,Mockito.times(1)).save(user1);//verify验证mock次数
assertEquals(user2, saveUser);//断言是否mock返回的是user2
} /**
* mock spy public方法
* @throws Exception xx
*/
@Test
public void spy_public_method() throws Exception {
UserController spy = PowerMockito.spy(controller); //监视controller的publicCheck方法,让他返回true
Mockito.when(spy.publicCheck()).thenReturn(true);
String name = spy.getPrivateName("ljw");//执行该方法
assertEquals("public 被mock 了", name);//验证
} /**
* mock私有方法
* @throws Exception xx
*/
@Test
public void spy_private_method() throws Exception {
UserController spy = PowerMockito.spy(controller);
PowerMockito.when(spy, "check", any()).thenReturn(true);//私有方法mockito不行了,需要用无所不能的PowerMock监视spy
String name = spy.getPrivateName("ljw");
assertEquals("private 被mock 了", name);
} /**
* mock 静态方法
*/
@Test
public void mockStaticMethod() {
PowerMockito.mockStatic(UserController.class);//mock静态方法
when(UserController.getStaticName(any())).thenReturn("hi");
String staticName = UserController.getStaticName("ljw");//执行
assertEquals("hi", staticName);//验证
} @Test
public void mockStaticMethod_2() {
PowerMockito.mockStatic(UserController.class);
when(UserController.getStaticName(any())).thenReturn("hi");
String staticName = controller.returnName();//通过returnName()调用,看能否被mock
assertEquals("hi", staticName);
} /**
* 测试私有方法一
* @throws InvocationTargetException xx
* @throws IllegalAccessException xx
*/
@Test
public void testPrivateMethod() throws InvocationTargetException, IllegalAccessException {
Method method = PowerMockito.method(UserController.class, "say", String.class);
Object say = method.invoke(controller, "hi");
assertEquals("ljw say hi", say);
} /**
* 测试私有方法二
* @throws Exception xx
*/
@Test
public void testPrivateMethod_2() throws Exception {
Object say = Whitebox.invokeMethod(controller, "say", "hi");
assertEquals("ljw say hi", say);
} }
无所不能的PowerMock,mock私有方法,静态方法,测试私有方法,final类的更多相关文章
- 使用PowerMockito和Mockito进行模拟测试,包括静态方法测试,私有方法测试等,以及方法执行的坑或者模拟不成功解决
依赖:这个很重要,不同版本用法也有点区别: <dependency> <groupId>org.mockito</groupId> <artifactId&g ...
- final类与final方法
inal---用于类.方法前. final类---不可被继承. final方法---不可被覆盖. final类不能被继承. 如果我们不希望一个类被继承,我们使用final来修饰这个类.这个类将无法被继 ...
- PHP 面向对象 final类与final方法
final---用于类.方法前. final类---不可被继承. final方法---不可被覆盖. final类不能被继承. 如果我们不希望一个类被继承,我们使用final来修饰这个类.这个类将无法被 ...
- 用PowerMock mock 由工厂方法产生的对象
有些对象需要mock的对象是由工厂方法产生出来的,而工厂方法一般是静态方法,这时候就需要同时mock工厂方法及对象 被测方法: public class EmployeeServiceFactory ...
- 用PowerMock mock static方法
在编写代码时,经常需要调用别人已经写好的工具类,而这些工具提供的方法经常是static方法,在这里,直接贴出<PowerMock实战手册>中的例子 待测试方法: public class ...
- JUnit 3.8 通过反射测试私有方法
测试私有(private)的方法有两种: 1)把目标类的私有方法(修饰符:private)修改为(public),不推荐,因为修改了源程序不佳 2)通过反射 (推荐) 代码演示: 目标程序 Priva ...
- day16-封装(私有静态属性、私有属性、私有方法、类方法、静态方法)
# 一: class P: __age = 30 #私有静态属性 def __init__(self,name): self.__name = name #私有属性:属性名前面加上双下划线是私有属性. ...
- [bug]spring项目通过反射测试私有方法时,注入对象异常
背景 遇到问题:在进行Spring单元测试编写时,发现被测方法是一个私有方法,无法直接通过注入对象调用 解决思路:首先想到通过反射获取该私有方法的访问权限,并传入注入对象,最终调用对象的私有方法. 出 ...
- TDD学习笔记【三】---是否需针对非public方法进行测试?
前言 在Visual Studio 2012 中,针对Unit Test 的部分,有一个重要的变动: 原本针对「测试对象非public 的部分」,开发人员可通过Visual Studio 2010 自 ...
随机推荐
- BSOJ 1562 【堆练习】丑数3576
Description 丑数是指素因子都在集合{2,3,5,7}内的整数,第一个丑数是1. 现在输入n(n<=4000),输出第n个丑数. Input 输入文件仅一行为一个整数n. Output ...
- linux调度全景指南
- Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战
转: Java开发不懂Docker,学尽Java也枉然,阿里P8架构师手把手带你玩转Docker实战 Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一 ...
- pytorch(12)ContainersAndAlexNet
containers graph LR A["Containers"] --> B["nn.Sequetial"] B["nn.Sequetia ...
- Flink的日志配置
------------恢复内容开始------------ 介绍flink在本地运行和on yarn运行时的日志配置. 很多现代框架都是用门面模式进行日志输出,例如使用Slf4j中的接口输出日志,具 ...
- JDBC 连接池 & Template
数据库连接池 # 概念:其实就是一个容器(集合),存放数据库连接的容器. * 当系统初始化号以后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容其中获取连接对象,用户访问完之后,会将 ...
- KL散度相关理解以及视频推荐
以下内容基于对[中字]信息熵,交叉熵,KL散度介绍||机器学习的信息论基础这个视频的理解,请务必先看几遍这个视频. 假设一个事件可能有多种结果,每一种结果都有其发生的概率,概率总和为1,也即一个数据分 ...
- (数据科学学习手札110)Python+Dash快速web应用开发——静态部件篇(下)
本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 这是我的系列教程Python+Dash快速web ...
- 2020年12月-第01阶段-前端基础-HTML常用标签
1. HTML常用标签 首先 HTML和CSS是两种完全不同的语言,我们学的是结构,就只写HTML标签,认识标签就可以了. 不会再给结构标签指定样式了. HTML标签有很多,这里我们学习最为常用的,后 ...
- Mongo的相关语法
mongod的条件操作符 $gt -------- greater than > $gte --------- gt equal >= $lt -------- less than < ...