文章目录

  • Mock 测试
  • What's Mockito
  • 使用 Mockito
    • pom依赖
    • Demo Code
    • 【常规操作】
    • 【Mockito】
      • thenReturn
      • thenThrow
      • verify
  • Mockito 注意事项


Mock 测试

Mock 测试就是在测试过程中,创建一个假的对象,避免你为了测试一个方法,却要自行构建整个 Bean 的依赖链。

举个例子:

类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D、E、F 等,假设类 D 是一个外部服务,那就会很难测,因为你的返回结果会直接的受外部服务影响,导致你的单元测试可能今天会过、但明天就过不了了。

而当我们引入 Mock 测试时,就可以创建一个假的对象,替换掉真实的 Bean B 和 C,这样在调用B、C的方法时,实际上就会去调用这个假的 Mock 对象的方法,而我们就可以自己设定这个 Mock 对象的参数和期望结果,让我们可以专注在测试当前的类 A,而不会受到其他的外部服务影响,这样测试效率就能提高很多。


What’s Mockito

Mockito 是一种 Java Mock 框架,主要就是用来做 Mock 测试的,它可以模拟任何 Spring 管理的 Bean、模拟方法的返回值、模拟抛出异常等等,同时也会记录调用这些模拟方法的参数、调用顺序,从而可以校验出这个 Mock 对象是否有被正确的顺序调用,以及按照期望的参数被调用。

像是 Mockito 可以在单元测试中模拟一个 Service 返回的数据,而不会真正去调用该 Service,通过模拟一个假的 Service 对象,来快速的测试当前想要测试的类。

目前在 Java 中主流的 Mock 测试工具有 Mockito、JMock、EasyMock等等,而 SpringBoot 目前默认的测试框架是 Mockito 框架。


使用 Mockito

pom依赖

 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope>
</dependency>


Demo Code

一个 UserService,两个方法

  • getUserById() -------------> 调用 UserDao 这个 bean的 getUserById()
  • insertUser() -------------> 调用 UserDao 这个 bean的 insertUser()
@Component
public class UserService {@Autowiredprivate UserDao userDao;public User getUserById(Integer id) {return userDao.getUserById(id);}public Integer insertUser(User user) {return userDao.insertUser(user);}
}

【POJO对象】

public class User {private Integer id;private String name;//省略 getter/setter
}

【常规操作】

如果这时候我们先不使用 Mockito 模拟一个假的 userDao Bean,而是真的去调用一个正常的 Spring Bean 的 userDao 的话, 注入 userService Bean,然后去调用方法,而他会再去调用 userDao 取得数据库的数据,然后我们再对返回结果做 Assert 断言检查。

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {//先普通的注入一个userService bean@Autowiredprivate UserService userService;@Testpublic void getUserById() throws Exception {//普通的使用userService,他里面会再去调用userDao取得数据库的数据User user = userService.getUserById(1);//检查结果Assert.assertNotNull(user);Assert.assertEquals(user.getId(), new Integer(1));Assert.assertEquals(user.getName(), "John");}
}

【Mockito】

但是如果 userDao 还没写好,又想先测 userService 的话,就需要使用 Mockito 去模拟一个假的 userDao 出来。

具体怎么搞呢?

在 userDao 上加上一个 @MockBean 注解

当 userDao 被加上这个注解之后,表示 Mockito 会帮我们创建一个假的 Mock 对象,替换掉 Spring 中已存在的那个真实的 userDao Bean,也就是说,注入进 userService 的 userDao Bean,已经被我们替换成假的 Mock 对象了,所以当我们再次调用 userService 的方法时,会去调用的实际上是 mock userDao Bean 的方法,而不是真实的 userDao Bean。

当我们创建了一个假的 userDao 后,我们需要为这个 mock userDao 自定义方法的返回值,这里有一个公式用法,下面这段代码的意思为,当调用了某个 Mock 对象的方法时,就回传我们想要的自定义结果。

Mockito.when( 对象.方法名() ).thenReturn( 自定义结果 )

代码如下:

@RunWith(SpringRunner.class)
@SpringBootTest
publicclass UserServiceTest {@Autowiredprivate UserService userService;@MockBeanprivate UserDao userDao;@Testpublic void getUserById() throws Exception {// 定义当调用mock userDao的getUserById()方法,并且参数为3时,就返回id为200、name为I'm mock3的user对象Mockito.when(userDao.getUserById(3)).thenReturn(new User(200, "Aritisan"));// 返回的会是名字为I'm mock 3的user对象User user = userService.getUserById(1);Assert.assertNotNull(user);Assert.assertEquals(user.getId(), new Integer(200));Assert.assertEquals(user.getName(), "Aritisan");}
}

Mockito 除了最基本的 Mockito.when( 对象.方法名() ).thenReturn( 自定义结果 ),还提供了其他用法让我们使用。


thenReturn

当使用任何整数值调用 userService 的 getUserById() 方法时,就回传一个名字为Aritisan的 User 对象。

Mockito.when(userService.getUserById(Mockito.anyInt())).thenReturn(new User(3, "Aritisan"));
User user1 = userService.getUserById(3); // 回传的user的名字为Aritisan
User user2 = userService.getUserById(200); // 回传的user的名字也为Aritisan

限制只有当参数的数字是 3 时,才会回传名字为 Aritisan 的 user 对象。

Mockito.when(userService.getUserById(3)).thenReturn(new User(3, "Aritisan"));
User user1 = userService.getUserById(3); // 回传的user的名字为Aritisan
User user2 = userService.getUserById(200); // 回传的user为null

当调用 userService 的 insertUser() 方法时,不管传进来的 user 是什么,都回传 100。

Mockito.when(userService.insertUser(Mockito.any(User.class))).thenReturn(100);
Integer i = userService.insertUser(new User()); //会返回100

thenThrow

当调用 userService 的 getUserById() 时的参数是 9 时,抛出一个 RuntimeException。

Mockito.when(userService.getUserById(9)).thenThrow(new RuntimeException("mock throw exception"));
User user = userService.getUserById(9); //会抛出一个RuntimeException

如果方法没有返回值的话(即是方法定义为 public void myMethod() {…}),要改用 doThrow() 抛出 Exception。

Mockito.doThrow(new RuntimeException("mock throw  exception")).when(userService).print();
userService.print(); //会抛出一个RuntimeException

verify

检查调用 userService 的 getUserById()、且参数为3的次数是否为1次。

Mockito.verify(userService, Mockito.times(1)).getUserById(Mockito.eq(3)) ;

验证调用顺序,验证 userService 是否先调用 getUserById() 两次,并且第一次的参数是 3、第二次的参数是 5,然后才调用insertUser() 方法。

InOrder inOrder = Mockito.inOrder(userService);
inOrder.verify(userService).getUserById(3);
inOrder.verify(userService).getUserById(5);
inOrder.verify(userService).insertUser(Mockito.any(User.class));

Mockito 注意事项

上述就是 Mockito 的 Mock 对象使用方法,不过当使用 Mockito 在 Mock 对象时,有一些限制需要遵守:

  • 不能 Mock 静态方法
  • 不能 Mock private 方法
  • 不能 Mock final class

因此在写代码时,需要做良好的功能拆分,才能够使用 Mockito 的 Mock 技术,帮助我们降低测试时 Bean 的耦合度。


SpringBoot - 单元测试利器Mockito入门相关推荐

  1. mockito mock void方法_用过举手!SpringBoot 单元测试利器Mockito

    Mockito 是一种 Java mock 框架,他主要是用来做 mock 测试的,他可以模拟任何 Spring 管理的 bean.模拟方法的返回值.模拟抛出异常...等,在了解 Mockito 的具 ...

  2. 单元测试利器——手把手教你使用Mockito

    作者:京东零售 秦浩然 从你成为开发人员的那一天起,写单元测试终究是你逃不开的宿命!那开发人员为什么不喜欢写单元测试呢?究其原因,无外乎是依赖.依赖其他的服务.依赖运行的环境.等等,各种依赖都成为了我 ...

  3. mockito入门_Mockito入门

    mockito入门 本文是我们名为" 用Mockito测试 "的学院课程的一部分. 在本课程中,您将深入了解Mockito的魔力. 您将了解有关"模拟",&qu ...

  4. 基于链路思想的SpringBoot单元测试快速写法

    简介:本文更偏向实践而非方法论,所提及的SpringBoot单元测试写法亦并非官方解,仅仅是笔者自身觉得比较方便.效率较高的一种写法.每个团队甚至团队内的每位开发可能都有自己的写法习惯和风格,只要能实 ...

  5. Springboot 单元测试结合Jacoco收集单元测试覆盖率

    目录 单元测试 Junit 简单例子 mockito Mock 的限制 Powermock maven 引入 注解使用 处理私有方法 mock构造函数 结合Springboot一起使用 各种runne ...

  6. Mockito 入门

    目录 1.什么是 Mock 测试? 2.Mockito简介 3.在 SpringBoot 单元测试中使用 Mockito 3.1 Maven依赖: 3.2 UserService.java 3.3 U ...

  7. springboot单元测试类

    springboot单元测试类,引入下方jia包 <!--version 依据当前springboot版本即可--> <dependency><groupId>or ...

  8. SpringBoot系列: RestTemplate 快速入门

    ==================================== 相关的文章 ==================================== SpringBoot系列: 与Sprin ...

  9. springboot环境搭建及入门必知

    springboot环境搭建 导入springboot父项目依赖,目的是统一当前整合技术版本 <!--继承springboot父项目--> <parent>     <g ...

最新文章

  1. php多级遍历,php jquery实现无限级目录遍历展示代码
  2. 如何移动SQL SERVER的系统数据库
  3. Qt 互斥锁 QMutex 的简单应用
  4. 前端公共reset.css模板
  5. 线性代数学的中国根源
  6. JavaScript | 声明数组并使用数组索引分配元素的代码
  7. Redis经典面试题
  8. 计算机应用基础10000字论文,计算机应用毕业设计论文一万字.docx
  9. jsp 页面实现增减行
  10. 序列每天从0开始_006 Python基础:通用序列操作
  11. 学好C++开发技术能从事哪些岗位?
  12. 浅拷贝直接赋值_Python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)?...
  13. P1048 采药 洛谷Oj
  14. 超级好用很少人知道的5款小众软件,建议收藏转发
  15. HTML课程导航作业,北大青年课程导航.html
  16. android自定义相机取景框模仿微信抓取录像实现活体认证
  17. fn键台式计算机在哪,fn键在哪?小鱼教您fn键使用方法
  18. c++编写乘法口诀表
  19. texture packer 处理图片空白的问题
  20. 【算法思想】数学归纳法在算法题中的应用(含例题举例)

热门文章

  1. Swift获取当前连接WIFI名称,IOS获取当前连接WIFI名称
  2. 学习正则表达式 - 用 HTML 标记文本
  3. UE4资源————Pak
  4. JS在VS coder界面写promt和alter语句无法在浏览器页面显示
  5. 7-6 分支结构——大小写字母判断 (15 分)
  6. 微信编辑器——构思编辑器教你如何学好图文排版
  7. 基于JAVA控制台版本银行自动取款机(修改版)
  8. 我用Python+PySide6做了个图形化番茄钟,这下可以提醒自己放松一下了。
  9. 天玥系列微型计算机,【简讯】AMD正式发布RX 6000系列显卡;OPPO K7x宣布…
  10. HTML和CSS实现京东首页(html和css详解)