Mockito 实战总结笔记
其他 mock 框架:powermock、easymock、jmock
mockito 官网:https://site.mockito.org
mockito 是一个单元测试框架。
Mockito 快速入门
下面来演示 Mockito 的入门案例。
包结构如下:
代码如下:
实体类 Account.java:
public class Account {}
dao 层 AccountDao.java,该类中有一个接口,并且模拟数据库宕机的情况:
public class AccountDao {public Account findAccount(String username, String password) {throw new UnsupportedOperationException(); // 模拟数据库宕机情况}}
controller 层 AccountLoginController.java,该类中有一个接口:
public class AccountLoginController {private final AccountDao accountDao;public AccountLoginController(AccountDao accountDao) {this.accountDao = accountDao;}public String login(HttpServletRequest request) {final String userName = request.getParameter("username");final String password = request.getParameter("password");try {Account account = accountDao.findAccount(userName, password);if (account == null) {return "/login"; // 模拟返回登录页面} else {return "/index"; // 模拟登录成功}} catch (Exception e) {return "/505"; // 模拟出错情况}}}
此时 controller 层的接口 login() 已经定义好了,现在要对其进行单元测试,但没有此时这个程序的环境中没有 servlet 容器,也没有数据库,如何进行测试?用 mockito !
AccountLoginControllerTest.java:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;import javax.servlet.http.HttpServletRequest;import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.when;@RunWith(MockitoJUnitRunner.class) // 使用mockito进行单元测试,记得加上这个注解
public class AccountLoginControllerTest {private AccountDao accountDao;private HttpServletRequest request;private AccountLoginController accountLoginController;// 每次测试开始前都会调用该方法,初始化上面定义的变量@Beforepublic void setUp() {this.accountDao = Mockito.mock(AccountDao.class); // 创建一个AccountDao的“替身”this.request = Mockito.mock(HttpServletRequest.class); // 创建一个HttpServletRequest的“替身”this.accountLoginController = new AccountLoginController(accountDao);}// 测试返回"/index"的情况@Testpublic void testLoginSuccess() {Account account = new Account();// 意思是:当调用request.getParameter("username")时,让request.getParameter("username")返回"john"when(request.getParameter("username")).thenReturn("john"); when(request.getParameter("password")).thenReturn("123456");// anyString():任意字符串when(accountDao.findAccount(anyString(), anyString())).thenReturn(account);// 通过断言来验证结果assertThat(accountLoginController.login(request), equalTo("/index"));}// 测试返回"/login"的情况@Testpublic void testLoginFailure() {when(request.getParameter("username")).thenReturn("john");when(request.getParameter("password")).thenReturn("123456");when(accountDao.findAccount(anyString(), anyString())).thenReturn(null);assertThat(accountLoginController.login(request), equalTo("/login"));}// 测试返回"/505"的情况@Testpublic void testLogin505() {when(request.getParameter("username")).thenReturn("john");when(request.getParameter("password")).thenReturn("123456");when(accountDao.findAccount(anyString(), anyString())).thenThrow(UnsupportedOperationException.class); // 注意这调的是thenThrow()assertThat(accountLoginController.login(request), equalTo("/505"));}}
三种不同的 mock 方式
方式一:使用 @RunWith 注解
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;import static org.mockito.Mockito.mock;@RunWith(MockitoJUnitRunner.class)
public class MockByRunnerTest {@Testpublic void testMock() {AccountDao accountDao = mock(AccountDao.class);Account account = accountDao.findAccount("x", "x");System.out.println(account);}}
打印结果:
null
如果不希望 account 为 null,可以将代码修改如下:
@Test
public void testMock() {AccountDao accountDao = mock(AccountDao.class, Mockito.RETURNS_SMART_NULLS);Account account = accountDao.findAccount("x", "x");System.out.println(account);
}
此时打印结果:
SmartNull returned by this unstubbed method call on a mock:
accountDao.findAccount("x", "x");
方式二:@Mock 注解
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;public class MockByAnnotationTest {@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Mockprivate AccountDao accountDao;@Testpublic void testMock() {Account account = accountDao.findAccount("x", "x");System.out.println(account);}}
打印结果:
null
同样,若不想 account 为 null,可按如下编码:
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;public class MockByAnnotationTest {@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Mock(answer = Answers.RETURNS_SMART_NULLS)private AccountDao accountDao;@Testpublic void testMock() {Account account = accountDao.findAccount("x", "x");System.out.println(account);}}
打印结果:
SmartNull returned by this unstubbed method call on a mock:
accountDao.findAccount("x", "x");
方式三:@Rule 注解
import org.junit.Rule;
import org.junit.Test;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;import static org.mockito.Mockito.mock;public class MockByRuleTest {@Rulepublic MockitoRule mockitoRule = MockitoJUnit.rule();@Testpublic void testMock() {AccountDao accountDao = mock(AccountDao.class);Account account = accountDao.findAccount("x", "x");System.out.println(account);}}
打印结果:
null
深度 Mock(Deep Mock)
下面的例子中使用 @Mock 注解来进行单元测试:
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.when;public class DeepMockTest {@Mockprivate PersonService personService;@Mockprivate Person person;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {Person person = personService.get();person.foo(); // 此时会报空指针异常}}
此时 testDeepMock() 测试无法通过,会报空指针异常,因为 person 为 null。
为了改进这个问题,将单元测试定义如下:
@Test
public void testDeepMock2() {when(personService.get()).thenReturn(person);Person person = personService.get();person.foo();
}
此时可以通过测试,完整代码如下:
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.when;public class DeepMockTest {@Mockprivate PersonService personService;@Mockprivate Person person;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {Person person = personService.get();person.foo(); // 此时会报空指针异常}@Testpublic void testDeepMock2() {when(personService.get()).thenReturn(person);Person person = personService.get();person.foo();}}
对于上面代码,可以通过 Deep Mock 方式进行代码简化。简化后的代码如下:
import org.junit.Before;
import org.junit.Test;
import org.mockito.Answers;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;public class DeepMockTest {@Mock(answer = Answers.RETURNS_DEEP_STUBS) // 指定为Deep Mockprivate PersonService personService;@Beforepublic void init() {MockitoAnnotations.initMocks(this);}@Testpublic void testDeepMock() {personService.get().foo();}}
Mockito Stubbing 语法详解
#未完待续
参考教程:汪文君Mockito实战视频
Mockito 实战总结笔记相关推荐
- Linux实战教学笔记16:磁盘原理
第十五节 磁盘原理 标签(空格分隔): Linux实战教学笔记 1,知识扩展 非脚本方式的一条命令搞定批量创建用户并设置随机10位字母数字组合密码. 1.1 sed的高级用法 [root@chensi ...
- Mock工具之Mockito实战
在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖,这些依赖项又会有依赖,导致在单元测试代码里几乎无法完成构建,尤其是当依赖项尚未构建完成时会导致单元测试无法进行.为了解决这类问题我们引入 ...
- Go语言实战读书笔记
2019独角兽企业重金招聘Python工程师标准>>> Go语言实战读书笔记 第二章 通道(channel).映射(map)和切片(slice)是引用类型.引用类型的对象需要使用ma ...
- Linux实战教学笔记02:计算机系统硬件核心知识
标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...
- Linux实战教学笔记12:linux三剑客之sed命令精讲
第十二节 linux三剑客之sed命令精讲 标签(空格分隔): Linux实战教学笔记-陈思齐 ---更多资料点我查看 1,前言 我们都知道,在Linux中一切皆文件,比如配置文件,日志文件,启动文件 ...
- 《Java8实战》笔记汇总
<Java8实战>笔记(01):为什么要关心Java8 <Java8实战>笔记(02):通过行为参数传递代码 <Java8实战>笔记(03):Lambda表达式 & ...
- Linux实战教学笔记13:定时任务补充
第十三节 定时任务补充 标签(空格分隔): Linux实战教学笔记 ---[更多资料点我查看][1] 1,生产环境常用Crontab专业实例 1.1书写crontab定时任务多个基本要领 1.1.1 ...
- Java 8 实战学习笔记
Java 8 实战学习笔记 @(JAVASE)[java8, 实战, lambda] 文章目录 Java 8 实战学习笔记 参考内容 Lambda表达式 Lambda环绕执行模式(抽离步骤) 原始代码 ...
- Linux实战教学笔记22:企业级NFS网络文件共享服务
第二十二节 企业级NFS网络文件共享服务 标签(空格分隔): Linux实战教学笔记-陈思齐 ---本教学笔记是本人学习和工作生涯中的摘记整理而成,此为初稿(尚有诸多不完善之处),为原创作品,允许转载 ...
- UCSD COGS108 数据科学实战中文笔记·翻译完成
原文:COGS108/Tutorials 译者:飞龙 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. ApacheCN 机器学习交流群 62 ...
最新文章
- python运行文件后缀_Python程序存储成以.py为扩展名的程序文件用Python解释器执行。(4.5分)_学小易找答案...
- nohup不输出日志信息的方法,及linux重定向学习
- 知识库问答中的关系识别研究回顾
- 201712-1最小差值
- 分享几个vscode的插件
- Marketing Cloud里如何创建新的query视图并设置为默认显示界面
- 【转】ABP源码分析十八:UI Inputs
- 总结了12个Numpy高级函数,完美解决数据处理,拿来即用!
- access游戏库不显示 ea_全球游戏公司营收一览:腾讯连续第六年霸榜
- [XHTML Tutorial] 走向XHTML标准 (4)(XHTML Syntax)
- tcl 查询与设置编码格式
- Protobuf 判断某个值是否在一个枚举值中
- 航天生物计算机作文,科幻遨游太空作文(精选6篇)
- VMware ESX/ESXi 主机上的 VMFS 卷被锁定
- 求函数:x的n次方(函数递归)
- 一分钟了解“副词、系动词、情态动词、实意动词的先后位置关系”
- Eigen的介绍、安装
- 重构不是阳春白雪的高端玩意,而是码农编程利器
- 今日头条有意向收购锤子科技;原金立总裁加入小米;苹果应用商店出现查开房记录app|雷锋早报...
- Android多语言翻译国际化语言代码与中文对照整理