PowerMockito简介(以上都是自我琢磨,错误之处请批评指正)
在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖,这些依赖项又会有依赖,导致在单元测试代码里几乎无法完成构建,尤其是当依赖项尚未构建完成时会导致单元测试无法进行。为了解决这类问题我们引入了Mock的概念,简单的说就是模拟那些尚未构建完成的类或者资源,用Mock模拟出来供测试使用。业内的Mock工具有很多,也已经很成熟了,这里我们将直接使用最流行的Mockito进行实战演练,完成mockito教程。
EasyMock 以及 Mockito 都因为可以极大地简化单元测试的书写过程而被许多人应用在自己的工作中,但是这两种 Mock工具都不可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟,但是这些方法往往是我们在大型系统中需要的功能。
以上简介参考源自:https://www.cnblogs.com/zishi/p/6780719.html
Demo用到的类
Controller类:
package demo.mock;
import java.io.File;
/**
* @author wangg
* @date 2018年3月14日 下午8:15:58
* @description
*/
public class Controller {
public boolean sentPost(){
System.out.println("发送post");
return true;
}
public final boolean isLive(){
System.out.println("isLive");
return false;
}
public static boolean isExist(File f) {
System.out.println("isExist");
return false;
}
}
Common类:
package demo.mock;
import java.io.File;
/**
* @author wangg
* @date 2018年3月14日 下午7:45:59
* @description
*/
public class Common {
private Controller controller;
public Controller getController() {
return controller;
}
public void setController(Controller controller) {
this.controller = controller;
}
/**
* 调用普通方法
* @param f
* @return
*/
public boolean callOrdinaryMethod(Controller controller){
System.out.println("Common....callOrdinaryMethod....start");
boolean result = controller.sentPost();
System.out.println("Common....callOrdinaryMethod.....over");
return result;
}
/**
* 调用静态方法
* @param f
* @return
*/
public boolean callStaticMethod(File f){
System.out.println("Common....callStaticMethod.....start");
boolean result = Controller.isExist(f);
System.out.println("Common....callStaticMethod.....end");
return result;
}
/**
* 调用final方法
* */
public boolean callFinalMethod(Controller controller){
System.out.println("Common....callFinalMethod.....start");
boolean result = controller.isLive();
System.out.println("Common....callFinalMethod.....end");
return result;
}
/**
* 调用内部方法
* */
public boolean callInsideMethod(Controller controller){
System.out.println("Common....callInsideMethod.....start");
boolean result = insideMethod();
System.out.println("Common....callInsideMethod.....end");
return result;
}
public boolean insideMethod(){
System.out.println("........insideMethod........");
return false;
}
/**
* 调用私有方法
* */
public boolean callPrivateMethod(){
System.out.println("Common......callPrivateMethod.... start..");
privateMethod();
System.out.println("Common......callPrivateMethod.... end..");
return false;
}
private void privateMethod() {
System.out.println("Common......privateMethod......");
}
}
CommonTest类:
package demo.mock.test;
import static org.junit.Assert.*;
import java.io.File;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import demo.mock.Common;
import demo.mock.Controller;
/**
* @author wangg
* @date 2018年3月14日 下午7:48:56
* @description
*/
@RunWith(PowerMockRunner.class)
public class CommonTest {
@InjectMocks
Common common = new Common();
@Mock //如果没有加该注解,common.getController() = null
Controller controller;
/**
* 测试
* @InjectMocks
* @Mock
* */
@Test
public void testAnnotation(){
System.out.println(common.getController());
System.out.println(common.getController() == null);
}
/**
* 普通方法测试
* */
@Test
@PrepareForTest(Controller.class)
public void testCallOrdinaryMethod(){
//虚拟一个controller对象
Controller controller = PowerMockito.mock(Controller.class);
//创建要测试的对象
Common common = new Common();
//拦截:当走到controller.sentPost()方法时,直接返回fasle,不执行sentPost()方法体
PowerMockito.when(controller.sentPost()).thenReturn(false);
//调用测试对象的方法
assertFalse(common.callOrdinaryMethod(controller));
}
/**
* final方法测试
* */
@Test
@PrepareForTest(Controller.class)
public void testCallFinalMethod(){
Controller controller = PowerMockito.mock(Controller.class);
Common common = new Common();
PowerMockito.when(controller.isLive()).thenReturn(true);
assertTrue(common.callFinalMethod(controller));
}
/**
* 静态方法错误示范
* @PrepareForTest(Util.class)没有添加
* */
// @Test
// public void testCallStaticMethodError() {
// File file = PowerMockito.mock(File.class);
// PowerMockito.mockStatic(Util.class);
// Common common = new Common();
// //错误代码
// PowerMockito.when(Util.isExist(file)).thenReturn(true);
// assertTrue(common.callStaticMethod(file));
// }
/**
* 静态方法测试
* */
@Test
@PrepareForTest(Controller.class)
public void testCallStaticMethod() {
File file = PowerMockito.mock(File.class);
PowerMockito.mockStatic(Controller.class);
Common common = new Common();
PowerMockito.when(Controller.isExist(file)).thenReturn(true);
assertTrue(common.callStaticMethod(file));
}
/**
* 使用spy进行部分模拟
* */
@Test
@PrepareForTest(Controller.class)
public void testCallInsideMethod(){
Common common = PowerMockito.spy(new Common());
Controller controller = PowerMockito.mock(Controller.class);
//调用内部方法
PowerMockito.doReturn(true).when(common).insideMethod();
// PowerMockito.doNothing().when(common).insideMethod();
assertTrue(common.callInsideMethod(controller));
}
/**
* 使用spy进行私有方法模拟
* @throws Exception
* */
@Test
@PrepareForTest(Common.class)//之前没有加该注解,一直报错,百思不得其解,后来忽然想到static,final,private 方法都的需要加这个注解才可以
public void testCallPrivateMethod() throws Exception {
Common common = PowerMockito.spy(new Common());
//调用私有方法
PowerMockito.doNothing().when(common,"privateMethod");
boolean result = common.callPrivateMethod();
assertFalse(result);
PowerMockito.verifyPrivate(common).invoke("privateMethod");
}
}
PowerMock两个重要的注解
@InjectMocks:创建一个实例对象,如果属性为Mock对象可以自动注入
@Mock:Mock一个对象,该对象可以自动注入到InjectMocks对象中(前提InjectMocks有属性为Mock类型)
@RunWith(PowerMockRunner.class)
@prepareForTest({MyObect.class})
PowerMock去mock静态,final或者私有方法时,需要加上这两个注解
如果调用时不加以上注解(测试类有错误示范)会报以下错误
通过看注解@PrepareForTest注解说明:
本人英语不好,直接拷贝到翻译上,大体的意思是:
这个注释告诉PowerMock为测试准备某些类。使用此注释定义的类通常是那些。需要对字节码进行操作。这包括最后的类和类。最终的、私有的、静态的或本地的方法应该被嘲笑。应该在实例化时返回模拟对象的类。
总结:
当我们做项目时,经常会依赖同事的接口(现在比较流行微服务嘛),有一种情况就是你这边开发完毕了,但是你依赖的接口还没有开发完毕,但是呢,你又还得做单元测试,要不然代码提交不了啊,母鸡啊!这怎么办呢,他完事不了,我测试不了啊!!!这时候Mock就派上用场了,通过Mock可以虚拟一个你依赖的服务,这样我们就可以愉快的做单元测试了~