一、什么是Mock&为什么要Mock
Mock就是在测试过程中对于那些不容易构建的依赖进行模拟,以保证系统的测试流程可以正常运行,即生成一个和实际使用场景不一样的对象;
为什么需要Mock呢?
1、在测试环境中构建一些依赖的成本比较高
如一些硬件的操作,像串口和USB输入;
还有一些第三方依赖,像支付系统要调用很多外部支付网关,如果直接调用生产环境的网关就会产生脏数据的问题;
2、分而测之
以上面的例子来说,生产环境中就是要从硬件输入,那这块是不是不测试呢?肯定是要测试的,不过分开来测,一部分测试软件上的流程,即从硬件输入后系统的处理流程是否正常,在一些异常下数据是否准确;而硬件输入的测试可以由单独的团队测试,这样就可以并行测试提高效率。
二、Mockito介绍
Mockito是一款优秀的Mock工具,以下是其相关的介绍:
Mockito源码:
https://github.com/mockito/mockito
Mockito2.x新特性介绍:
https://github.com/mockito/mockito/wiki/What%27s-new-in-Mockito-2
接下来介绍Mockito的具体使用:
1、引入依赖:
<dependency><groupId>org.mockito</groupId><artifactId>mockito-core</artifactId><version>3.7.7</version><scope>test</scope></dependency>
2、模拟对象
具体的方式有2种:调用spy方法,或加Spy注解;
先讲下我们的范例代码,假设我们有个简单的PostService,用来操作帖子的:
public class PostService {@Resourceprivate UserService userService;/*** 添加帖子* @return*/public void addPost(Post post){User user = userService.findUser(post.getUserId());if (user.isDisabled()){//用户被禁用}}}
上面是个简单的例子,在添加帖子的时候需要调用用户服务来查询用户信息,这里不讨论代码组织是否合理,是否用到了DDD,只是一个例子说明如何使用Mockito;
先看看spy方法如何Mock:
import static org.mockito.Mockito.spy;public class PostServiceTest extends TestMain {@Autowiredprivate UserService userService;@Testpublic void testAddPost() throws Exception {UserService mockUserService = spy(userService);Post post = new Post();post.setTitle("test");post.setAutor("Edward");post.setUserId(123);Mockito.when(mockUserService .findUser(Mockito.anyInt()).thenReturn(new User(123, "edward", 1)//用户ID,用户名,用户状态1:正常,0:禁用));}}
Spy注解
public class PostServiceTest extends TestMain {@Autowired@Spyprivate UserService userService;private AutoCloseable autoCloseable;@BeforeClasspublic void initMock() {autoCloseable = MockitoAnnotations.openMocks(this);}@AfterClasspublic void close() throws Exception {autoCloseable.close();}}
注意这里要调用MockitoAnnotations.openMocks,不然会报错;
可以看到上面拦截方法调用的语法是Mockito.when(..).thenReturn
when传方法,thenReturn传递要返回的结果,如果when要带参数,一般是这样的格式, Mockito.anyInt(),Mockito定义了很多常用类型,可以根据自己需要选择;
3、模拟静态方法
如果要用Mockito模拟静态方法,一是要保证Mockito包版本在3.4.0以上,二是需要额外加mockito-inline依赖,如下:
<dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>3.7.7</version><scope>test</scope></dependency>
加好依赖后,通过 Mockito.mockStatic 来模拟静态方法。
@Testpublic void testStaticMethod() {LocalDate dummy = LocalDate.of(2021, 10, 4);try (MockedStatic<LocalDate> theMock = Mockito.mockStatic(LocalDate.class)) {theMock.when(LocalDate::now).thenReturn(dummy);LocalDate now = LocalDate.now();System.out.println(now);Assert.assertEquals(2021, now.getYear());}}
这里要注意dummy一定要放在mockStatic前面,因为后面一旦Mock了,所有静态方法都被Mock掉,of静态方法没有设置返回值会报错的。




