它是开发模式: 测试驱动开发前端
它是工具:EasyMock, JMock, Mockito, Powermock-*java
EasyMock,JMock,Mockito: 对象模拟技术,只能模拟公共非静态方法。
Powermock: PowerMock基于三者扩展,可以模拟静态类、静态方法、私有方法、构造方法等等。git
它强调的是业务逻辑的联通性,通常用于单元测试和集成测试!github
No Dependency:每个团队都但愿本身开发的模块不依赖任何其它的外界条件,沟通成本仅限于双方接口定义。后端
敏捷、轻量级api
避免开发模块之间的耦合框架
简单 极为灵活函数
经过定义基于方法的模拟调用规则模拟任何代码的调用过程替代真实代码执行!工具
模拟RPC服务:目前存在不少应用经过RPC服务调用获取数据,应用前端的展示严重依赖后端服务的稳定性,在测试阶段能够选择经过模拟的方式直接模拟后端服务。单元测试
Mockito+Powermock-*
相对于EasyMock和JMock,Mockito的书写风格更为简洁。
模拟公共方法(public)
模拟私有方法(private)
模拟公共静态方法(public static)
模拟私有静态方法(private static)
模拟构造函数(public constructor)
模拟私有构造函数但存在公共建立实例的方法(private construtor)
模拟包含final修饰符的函数(非静态函数同private, 静态函数同private static)
模拟公共方法
业务代码
UserAction: public void executeForPublic(String something){ userService.sayHi(something); System.out.println(userService.sayHello(something)); }
UserService: public void sayHi(String arg){ System.out.println("real"+arg+"!"); } public String sayHello(String arg){ return "real"+arg+"!"; }
测试样例
``` java
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.mockito.Mockito;
import org.wit.service.UserAction;
import org.wit.service.UserService;
public class MockForPublicDemo {
@Test public void demo(){ UserService userService = mock(UserService.class); //userService.sayHi(any(String.class)); //对无返回值的方法 mock(UserService.class);后内部执行逻辑会被空调用覆盖. Mockito.doNothing().when(userService).sayHi(any(String.class)); //有返回值的方法 when(userService.sayHello(any(String.class))).thenReturn("mock sayHello!"); // 设置业务服务. UserAction userAction = new UserAction(); userAction.setUserService(userService); // 执行目标业务方法. userAction.executeForPublic("public"); // 执行校验. verify(userService, times(1)).sayHello(any(String.class)); verify(userService, times(1)).sayHi(any(String.class)); }
}
```
输出:mock sayHello!
模拟私有方法
业务代码
UserAction: public void executeForPrivate(String something){ userService.secreteSay(something); }
UserService: public void secreteSay(String arg){ secreteSayHi(arg); System.out.println(secreteSayHello(arg)); } private void secreteSayHi(String arg){ System.out.println("real"+arg+"!"); } private String secreteSayHello(String arg){ return "real"+arg+"!"; }
测试代码
```java
import static org.mockito.Matchers.any;
import org.junit.Test;
import org.junit.runner.RunWith;
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.wit.service.UserAction;
import org.wit.service.UserService;
@RunWith(PowerMockRunner.class)
@PrepareForTest({UserService.class,UserAction.class})
public class MockForPrivateDemo {
@Test public void demo() throws Exception { UserService userService = PowerMockito.spy(new UserService()); // 模拟返回值私有方法. PowerMockito.doReturn("mock").when(userService, "secreteSayHello", any(String.class)); // 模拟私有空方法. PowerMockito.doNothing().when(userService, "secreteSayHi", any(String.class)); // 设置业务服务. UserAction userAction = new UserAction(); userAction.setUserService(userService); // 调用业务方法. userAction.executeForPrivate("private"); // 验证. PowerMockito.verifyPrivate(userService, Mockito.times(1)).invoke("secreteSayHello", any(String.class)); PowerMockito.verifyPrivate(userService, Mockito.times(1)).invoke("secreteSayHi", any(String.class)); }
}
```
输出:mock
模拟静态公共方法
业务代码
java UserAction: public void executeForPublicStatic(String something){ StaticUserService.sayHi(something); System.out.println(StaticUserService.sayHello(something)); }
```java
StaticUserService:
public static void sayHi(String arg){
System.out.println("real"+arg+"!");
}
public static String sayHello(String arg){
return "real"+arg+"!";
}
**测试代码**
java
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
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.wit.service.StaticUserService;
import org.wit.service.UserAction;
@RunWith(PowerMockRunner.class)
@PrepareForTest({StaticUserService.class,UserAction.class})
public class MockForPublicStaticDemo {
@Test public void demo() throws Exception { //mock会模拟全部的方法. //PowerMockito.mock(StaticUserService.class); //spy只会模拟指定模拟行为的方法. PowerMockito.spy(StaticUserService.class); //模拟返回值的public T static 方法. when(StaticUserService.sayHello(any(String.class))).thenReturn("mock"); //模拟无返回值的public void static 方法 PowerMockito.doNothing().when(StaticUserService.class, "sayHi", anyString()); // 业务方法调用. UserAction userAction = new UserAction(); userAction.executeForPublicStatic("public static"); // 验证 sayHello. PowerMockito.verifyStatic(Mockito.times(1)); StaticUserService.sayHello(anyString()); // 验证 sayHi. PowerMockito.verifyStatic(Mockito.times(1)); StaticUserService.sayHi(anyString()); }
}
```
输出:mock
模拟静态私有方法
业务代码
UserAction: public void executeForPrivateStatic(String something){ StaticUserService.secreteSay(something); }
public static void secreteSay(String arg){ secreteSayHi(arg); System.out.println(secreteSayHello(arg)); } private static void secreteSayHi(String arg){ System.out.println("real"+arg+"!"); } private static String secreteSayHello(String arg){ return "real"+arg+"!"; }
测试代码
import static org.mockito.Matchers.any; import org.junit.Test; import org.junit.runner.RunWith; 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.wit.service.StaticUserService; import org.wit.service.UserAction; @RunWith(PowerMockRunner.class) @PrepareForTest({StaticUserService.class}) public class MockForPrivateStaticDemo { @Test public void demo() throws Exception { PowerMockito.spy(StaticUserService.class); //模拟返回值私有方法. //PowerMockito.when(userService, "secreteSayHello", any(String.class)).thenReturn("mock"); PowerMockito.doReturn("mock").when(StaticUserService.class, "secreteSayHello", any(String.class)); //模拟私有空方法. PowerMockito.doNothing().when(StaticUserService.class, "secreteSayHi", any(String.class)); // 执行业务方法. UserAction userAction = new UserAction(); userAction.executeForPrivateStatic("real"); userAction.executeForPrivateStatic("real"); // 验证私有方法. PowerMockito.verifyPrivate(StaticUserService.class,Mockito.times(2)).invoke("secreteSayHello", any(String.class)); PowerMockito.verifyPrivate(StaticUserService.class,Mockito.times(2)).invoke("secreteSayHi", any(String.class)); } }
输出: mock
输出: mock
模拟构造函数
业务代码
java UserAction: public void executeForConstructor(String arg){ System.out.println(new ConstructorService(arg).doNoting()); }
```java
ConstructorService
public class ConstructorService {
private String tag; public ConstructorService(String tag){ this.tag = tag; } public String doNoting(){ return tag+" doNoting!"; }
}
```
测试代码
``` java
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.times;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.wit.service.ConstructorService;
import org.wit.service.UserAction;
@RunWith(PowerMockRunner.class)
@PrepareForTest({ConstructorService.class,UserAction.class})
public class MockForConstructorDemo {
@Test public void testMockForConstructor() throws Exception { UserAction userAction = new UserAction(); //模拟构造函数. //value必须提早构造. ConstructorService value = new ConstructorService("mock"); PowerMockito.spy(ConstructorService.class); //模拟构造函数. PowerMockito.whenNew(ConstructorService.class).withArguments(anyString()).thenReturn(value); //执行业务逻辑. userAction.executeForConstructor("real"); //验证构造方法. PowerMockito.verifyNew(ConstructorService.class, times(1)).withArguments(anyString()); }
}
```
输出:mock doNoting!
模拟私有构造函数
业务代码
UserAction: public void executeForPrivateConstrutor(String arg){ System.out.println(PrivateConstructorService.createInstance().getDetail(arg)); }
PrivateConstructorService: public class PrivateConstructorService { private PrivateConstructorService(){ } public String getDetail(String arg){ return "private service " + arg; } public static PrivateConstructorService createInstance(){ return new PrivateConstructorService(); } }
测试代码
import static org.mockito.Mockito.when; import org.junit.Test; import org.junit.runner.RunWith; 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.wit.service.PrivateConstructorService; import org.wit.service.UserAction; @RunWith(PowerMockRunner.class) @PrepareForTest({PrivateConstructorService.class,UserAction.class}) public class MockForPrivateConstrutorDemo { @Test public void demo() throws Exception { PowerMockito.spy(PrivateConstructorService.class); // 使用PowerMockito建立拥有私有构造函数类的实例 PrivateConstructorService instance = PowerMockito.constructor(PrivateConstructorService.class).newInstance(new Object[]{}); // 模拟静态函数. when(PrivateConstructorService.createInstance()).thenReturn(instance); // 业务方法调用. UserAction userAction = new UserAction(); userAction.executeForPrivateConstrutor("real"); // 验证 sayHello. PowerMockito.verifyStatic(Mockito.times(1)); PrivateConstructorService.createInstance(); } }
输出:private service real
Mock是CI利器,可以在测试阶段最大程度减小各开发团队之间的耦合,但它并不是万能,毕竟实际上线时业务模块之间必然是真实调用,因此它并不能替代联调测试!