前言:学习一下Mock测试
作用
Mock可以用来解除测试对象对外部服务的依赖(比如数据库,第三方接口等),使得测试用例可以独立运行,与JUnit结合使用,但是不可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟
实际工作中,测试可能会遇到如下情况:
- 场景一:依赖接口不通,甲开发A模块,乙开发B模块,甲的进度比乙快,但A模块的方法依赖于B模块,要测试A模块接口怎么办?
- 场景二:异常数据难模拟,当需要测试接口一些异常数据,接口正常情况是否无法提供异常数据的。那么如何简便地构造接口的异常数据?
- 场景三:依赖接口性能参数无法保障。在对接口性能压测的时候,需要下游接口及时返回数据,满足上游接口的调用频度。在依赖接口多的情况下,如何减轻工作量?
比较流行的Mock有:
- JMock
- EasyMock
- Mockito
- powermock
maven依赖
1 2 3 4 5
| <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.10.19</version> </dependency>
|
或者
1 2 3 4 5
| <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.10.19</version> </dependency>
|
注:mockito-all发行已经停止,Mockito 2以上版本使用mockito-core。
创建mock对象(模拟对象)
可以对类和接口进行mock对象的创建,创建时可以为mock对象命名。对mock对象命名的好处是调试的时候容易辨认mock对象,也可以Mock对象的期望行为和返回值设定。
设置对象调用的预期返回值
通过 when(mock.someMethod()).thenReturn(value) 来设定 Mock 对象某个方法调用时的返回值
使用when(mock.someMethod()).thenThrow(new RuntimeException) 的方式来设定当调用某个方法时抛出的异常。
简单实例 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
public class Test {
public static void main(String[] args) { List<String> list = Mockito.mock(List.class);
Mockito.when(list.get(0)).thenReturn("mock"); Mockito.when(list.get(1)).thenThrow(new RuntimeException("mock exception"));
System.out.println(list.get(0)); try{ list.get(1); }catch (Exception e){ System.out.println(e.getMessage()); } } }
|
运行结果
简单实例 2
现在有A、B两个模块,A需要调用B,但B未开发完成,此时使用mock测试
模块A
1 2 3 4 5 6 7 8 9 10 11
|
public class AService { public void aFunction(BService bService){ if(bService.isAccess(new Object())){ System.out.println("AService 业务操作"); } } }
|
模块B
1 2 3 4 5 6 7 8 9 10
|
public class BService { public Boolean isAccess(Object user){ System.out.println("BService 业务操作"); return null; } }
|
Test
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public class Test {
public static void main(String[] args) { AService aService = new AService(); BService bService = Mockito.mock(BService.class); when(bService.isAccess(any())).thenReturn(true); aService.aFunction(bService); } }
|
运行结果
成功调用了AService的方法
注解
@Mock: 创建一个Mock,感觉没什么用,还是用Mockito.mock(class)……
@InjectMocks: 创建一个实例
MockitoAnnotations.initMocks(this):自动将依赖的类注入待测类,如果依赖类在spring的管理下有自己的name,那么甚至在待测类中都不需要写setter方法
代码
XxService是XxxJob的有Spring注入的属性,先mock XxxJob的excute方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
|
public class XxxTest extends TestSupport{ @InjectMocks @Autowired private XxxJob xxxJob;
@Mock private XxService xxService;
@Before public void setUp() { xxService = Mockito.mock(XxService.class); when(xxService.xxxQuery(any())).thenReturn(...); when(xxService.xxxAdd(any())).thenReturn(...); MockitoAnnotations.initMocks(this); } @Test public void executeTest(){ xxxJob.excute(); } }
|