Spring环境下的单元测试--Junit4下Mockito包的使用
1.Mockito包是做什么的?
Mockito 是一个强大的 Java 单元测试框架,用于创建和管理 Mock 对象,帮助开发者在测试中模拟复杂的依赖关系。它通过简洁的 API 和强大的功能,使单元测试更加高效和易于维护。
其实也就是帮助我创建一些对象,并且赋值上默认值,当然,这是针对方法也可以直接返回一个特定的想要的值,让我们除去复杂的数据而直接检验方法的逻辑。
2.怎么用?
<1>.注解使用
先看Mokcito中的一些注解(以Junit4举例)
| 注解 | 作用 | 注意事项 |
|---|---|---|
| @RunWith(SpringRunner.class) | Spring进入测试生命周期的标识 | |
| @Mock | 模拟一个对象,全部属性赋上默认值,里边的值都是虚拟的 | mock的对象不可以再手动set其对应的属性,不会生效 |
| @Spy | 模拟一个真实对象,修改特定方法或属性,未修改的保留原有真实对象 | |
| @InjectMocks | 将Mock的对象注入使用注解的对象中 | 一般来说你测试哪个类,就用在哪个类上 |
这几个注解已经足够满足大部分的单元测试,当然还有一个静态方法的模拟。
由于静态方法是类,并不为对象,对此@Mock和@Spy注解无能为力,那那么就该另一个注解登场,或者是不使用注解。
先看注解:@MockStatic,之后还需要写一个MockStatic<你的对象>
java
@MockStatic(你的对象.class)
private MockStatic<你的对象> 别名;
不过建议放在ry-with-resources中,可以在使用完静态方法后自动关闭,防止脏数据影响到其他测试。
java
try (MockedStatic<你的对象> mocked = mockStatic(你的对象.class)) {
//写具体的调用
}
讲完注解的,说说不用注解的
java
//先创建对象
private MockedStatic<你的对象> 别名;
//在测试中的加上@before注解的方法中首先进行加载
别名 = Mockito.mockStatic(你的对象.class);
别名.when( () -> 你的对象.静态方法(参数)).thenReturn(具体值);
//这个时候还需要进行关闭,防止数据污染,在@after注解使用的方法中关闭
this.别名.close();
<2>.方法的调用
一般来说都是用when进行包裹,这是Mockito中的一个静态方法
框架大概为:
when(别名.方法(可填各种参数匹配的规则类型)).返回一个特定类型
1>. 返回特定值
java
//下边解释为:当调用metaModelDao.findBySelectedIds()这个方法的时候,匹配的参数如果为任意的一个Sting数组的类,即返回一个自定义的result对象
when(metaModelDao.findBySelectedIds(any((String[].class)))).thenReturn(result);
//参数匹配还有哪些
when(metaModelDao.findBySelectedIds(eq("一个值或者是想要的对象等,一般用来比对值")))
.thenReturn(result);
参数匹配器大家可自行查阅,这里不做赘述,有了框架根据需求套就可以。
2>.动态返回值
被测试的方法中对象不可能总是去手动打桩或者去mock,有的对象是会在方法中动态更新的。
举一个例子来说:
我现在需要修改一条数据,等到修改完毕之后 ,我需要从数据库中检查一下我的数据是否更新,那么此时我就需要再次调用一个dao层中的方法来获取,但在测试的时候完全没有必要这样,因为我们做单元测试一般来说会去做service层的测试,dao对象很明显就是mock出来的,那么它的方法也基本都是用when()来mock出来的,所以当其再查询一次的话,我就可以直接给他返回一个被测试方法中的对象,代码如下:
原方法如下
java
public void updateUser(User user,PromptMessage promptmessage){
//检查判空等操作先不管
User user = userDao.findOne(user);
user.setAge(18);
//类似于这种,具体逻辑先不管,此时的这个方法就没有必要再去mock了,直接把这个user返回就行了
User user = userDao.update(user);
......
}
//测试方法
//解释:返回传入方法的第一个参数,第二个可以改变下标
when(userDao.update(any(User.class))).thenAnswer(ino -> ino.getArgument(0));
3>. 检验
这是测试的关键一步,决定是否测试通过的一步。
Assert断言是经常被用到的。
java
assertEquals(预期值,实际值);
//测试某个方法被调用了多少次,Times(1)可以省略,省略即默认为测试调用1次
verify(mock的类,Times(1)).方法(参数);
掌握这些基本可以解决90%的问题,剩下的问题就是不停的mock,mock,mock,打桩