初识 Mockito 这个测试框架后,我们要使用 Mock 的属性创建一个被测试类实例时,大概会下面这么纯手工来打造。
手工过程见: https://www.jianshu.com/p/bb705a56f620
如果所有的 Mock 对象全部通过手工来创建,那就不容易体现出 Mockito 的优越性出来。因此对于被测试对象的创建,Mock 属性的注入应该让 @Mock 和 @InjectMocks这两个注解大显身手了。
Mockito能力
- @Mock:对函数的调用均执行mock(即虚假函数),不执行真正部分。
- @Spy:对函数的调用均执行真正部分。
- @InjectMocks:创建一个实例,其余用@Mock(或@Spy)注解创建的mock将被注入到用该实例中。
@Autowird 方式是基于Springboot框架启动的自动注入。在单元测试中,如果没有启动 spring 框架,此时就需要通过 @ InjectMocks完成依赖注入: @InjectMocks会将带有@Spy 和@Mock 注解的对象尝试注入到被 测试的目标类中。记住下面这两句话即可:
- Usually when you are unit testing, you shouldn’t initialize Spring context. So remove Autowiring.
- Usually when you do integration testing, you should use real dependencies. So remove mocking.
这边也解释了,@RunWith(MockitoJUnitRunner::class)
的含义,其实是给下面Mockito注入的成员提供一个运行环境,为什么不直接使用@SpringBootTest
的原因主要还是启动太多,运行太重的考虑。那什么时候得用@SpringBootTest
呢?——最简单的情况,即要注入controller又要注入service,同时需要@mock
存储层的repository,由于controller和service都需要标注@InjectMocks
, 但InjectMocks字段是无法注入其他InjectMocks字段的。所以我们可以考虑使用Spring来做容器管理。
@Mock
和@MockBean
区别
MockBean的介绍:
1 | 在做单元测试时,如果想要 mock UserRepository 的逻辑,只需要声明一个变量并在上面加上 @MockBean 的注释即可, |
因此,@Mock
方便来做单元测试,@MockBean
大多用来做有依赖关系的集成测试
vertify
验证行为是否发生
verify方法用于验证 mock bean 的方法调用,要求必须是mock对象
Mockito . *verify* (mockBean ).someMethod();
表示:someMethod方法调用了一次,相当于times(1)Mockito . *verify* (mock Bean, Mockito.times(n) ).someMethod();
表示:someMethod方法调用了n次Mockito . *verify* (mock Bean, Mockito.never() ).someMethod();
表示:someMethod方法未执行Mockito . *verify* (mock Bean, Mockito. atLeastOnce() ).someMethod();
表示:someMethod方法至少执行过一次,相当于atLeast(1)
需要注意的:Mockito.*verify* (mock Bean, Mockito.only() ).someMethod();
表示: 仅有someMethod方法执行,且只有一次,不能有其他方法执行
more: https://www.jianshu.com/p/0e6a868b9da0
常用的 Mockito 方法:
Mockito的使用,一般有以下几种组合:参考链接
do/when:包括doThrow(…).when(…)/doReturn(…).when(…)/doAnswer(…).when(…)
given/will:包括given(…).willReturn(…)/given(…).willAnswer(…)
when/then: 包括when(…).thenReturn(…)/when(…).thenAnswer(…)
方法名 | 描述 |
---|---|
Mockito.mock(classToMock) | 模拟对象 |
Mockito.verify(mock) | 验证行为是否发生 |
Mockito.when(methodCall).thenReturn(value1).thenReturn(value2) | 触发时第一次返回value1,第n次都返回value2 |
Mockito.doThrow(toBeThrown).when(mock).[method] | 模拟抛出异常。 |
Mockito.mock(classToMock,defaultAnswer) | 使用默认Answer模拟对象 |
Mockito.when(methodCall).thenReturn(value) | 参数匹配 |
Mockito.doReturn(toBeReturned).when(mock).[method] | 参数匹配(直接执行不判断) |
Mockito.when(methodCall).thenAnswer(answer)) | 预期回调接口生成期望值 |
Mockito.doAnswer(answer).when(methodCall).[method] | 预期回调接口生成期望值(直接执行不判断) |
Mockito.spy(Object) | 用spy监控真实对象,设置真实对象行为 |
Mockito.doNothing().when(mock).[method] | 不做任何返回 |
Mockito.doCallRealMethod().when(mock).[method] //等价于Mockito.when(mock.[method]).thenCallRealMethod(); | 调用真实的方法 |
reset(mock) | 重置mock |
Matchers
-
匹配任意参数
-
Mockito.anyInt()
任何 int 值 ; -
Mockito.anyLong()
任何 long 值 ; -
Mockito.anyString()
任何 String 值 ; -
Mockito.any(XXX.class)
任何 XXX 类型的值 等等。
1 |
|
More:
函数名 | 匹配类型 |
---|---|
any() | 所有对象类型 |
anyInt() | 基本类型 int、非 null 的 Integer 类型 |
anyChar() | 基本类型 char、非 null 的 Character 类型 |
anyShort() | 基本类型 short、非 null 的 Short 类型 |
anyBoolean() | 基本类型 boolean、非 null 的 Boolean 类型 |
anyDouble() | 基本类型 double、非 null 的 Double 类型 |
anyFloat() | 基本类型 float、非 null 的 Float 类型 |
anyLong() | 基本类型 long、非 null 的 Long 类型 |
anyByte() | 基本类型 byte、非 null 的 Byte 类型 |
anyString() | String 类型(不能是 null) |
anyList() | List |
anyMap() | Map<K, V>类型(不能是 null) |
附录
Junit中的基本注解:
@Test:使用该注解标注的public void方法会表示为一个测试方法;
@BeforeClass:表示在类中的任意public static void方法执行之前执行;
@AfterClass:表示在类中的任意public static void方法之后执行;
@Before:表示在任意使用@Test注解标注的public void方法执行之前执行;
@After:表示在任意使用@Test注解标注的public void方法执行之后执行;
demo:
Author: Mrli
Link: https://nymrli.top/2022/01/03/Springboot-Kotlin-Mockito/
Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.