MockiTo 测试用mock框架
引入
编写UT测试用例时,使用mock可以只针对待测方法进行验证,而无需考虑真实数据和调用方法的影响。
依赖
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.10.19</version> <scope>test</scope> </dependency>
使用
参考文章:https://www.cnblogs.com/yinyunmoyi/p/14203794.html
初始化
测试类中进行UT编写之前需要初始化MockiTo,自动创建mock对象
@BeforeClass public void initMocks() throws Exception{ System.out.println("Before Class"); //MockitoAnnotations.initMocks(this),其中this就是单元测试所在的类,在initMocks函数中Mockito会根据类中不同的注解(如@Mock, @Spy等)创建不同的mock对象,即初始化工作 MockitoAnnotations.initMocks(this); }
@Before, @BeforeClass, @BeforeEach 和 @BeforeAll 之间的不同
特性 |
Junit 4 | Junit 5 |
|
@BeforeClass | @BeforeAll |
|
@AfterClass | @AfterAll |
|
@Before | @BeforeEach |
|
@After |
@AfterEach |
标记的代码@Before
在每次测试之前执行,而@BeforeClass
在整个测试夹具之前运行一次。如果你的测试类有十个测试,则@Before
代码将执行十次,但@BeforeClass
仅执行一次。
通常,
@BeforeClass
当多个测试需要共享相同的计算昂贵的设置代码时,可以使用。建立数据库连接属于此类。你可以将代码从@BeforeClass
移到@Before
,但是测试运行可能需要更长的时间。注意,标记的代码@BeforeClass
作为静态初始化程序运行,因此它将在创建测试夹具的类实例之前运行。
-https://www.cnblogs.com/yaoyaoo/p/14344684.html
坑:
1.@BeforeClass 可能导致没法初始化,建议使用@BeforeEach
2.不加@RunWith可能没法初始化Mock对象
3.initMocks 过时,用openMocks
@BeforeEach public void init() { System.out.println("init"); MockitoAnnotations.openMocks(this); }
@RunWith(MockitoJUnitRunner.class)// import org.mockito.junit.MockitoJUnitRunner;
创建mock
一般使用注解方式
@InjectMocks
用它标注的类会自动装配其中已经被在当前测试类中用 @Mock 和 @Spy 标注的字段(按名称匹配),该类.method(param...)是真实方法调用 =》该注解标记在待测类上
@InjectMocks ModelDaoImpl modelDao; @Mock Mediator mediator; ...{ // 这里调用的create是真实的方法,这里面如果有mediator调用某个方法,就可以通过自动装配事先设置它的行为了 Mockito.when(mediator.get(0)).thenReturn("foo"); modelDao.create(); ... }
设置一类行为
有返回值
方式一:会进入方法内,只是返回值是设定的返回值
Mockito.when(A.method(param...)).thenReturn(B);
方式二:并不会进入方法内,触发该方法就直接返回设定的值
Mockito.doReturn(C).when(A).method(B);
无返回值
返回值类型为 void的方法才能使用
doNothing().when(A.method(param...));
部分模拟
对于局部变量,有时候是不好准确模拟的,即使创建一个相同的对象
如这种情况
methodA() { Request request = new Request(); // 设置request的属性 ... // 调用方法 Response response = serviceInvoker.invoke(SERVICE_NAME, request); }
即便模拟invoke
// 创建request对象并设置其属性 Mockito.when(serviceInvoker.invoke(SERVICE_NAME, request)).thenReturn("foo");
也是行不通的,因为在待测试的代码中,request 是一个局部变量,它的地址和我们创建出来的对象地址是不同的,也就无法准确的进行模拟
解决方式可以是将生成Request的代码抽出来为一个方法,将该方法局部模拟,使用spy,spy部分模拟的对象,除了设定的方法,其他的都会按照原有真实方法执行
spy:
一,注解 @spy
二,手动
// 使用部分模拟需要用spy方法,它必须是某个已经建立好的对象的封装,不能用class对象为构造参数 List list = new LinkedList(); List mockedList = Mockito.spy(list);
将生成Request的代码抽出来为一个方法
Request request = getRequest(); // 调用方法 Response response = serviceInvoker.invoke(SERVICE_NAME, request);
来mock,instance是spy出来的
// 模拟getRequest方法的行为 Mockito.when(instance.getRequest()).thenReturn(request); // 完成我们一开始想要的行为定义 Mockito.when(serviceInvoker.invoke(SERVICE_NAME, request)).thenReturn("foo");
或者不在意参数,直接用any()
mock多次调用返回不同结果
// 第一次返回1,第二次返回2 Mockito.doReturn(1).doReturn(2).when(b).method();
mock静态和私有方法
这是个坑,try出来就无效了,只适合单独测试静态方法
验证(verify)
作者: deity-night
出处: https://www.cnblogs.com/deity-night/
关于作者:码农
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出, 原文链接 如有问题, 可邮件(***@163.com)咨询.