Mockito简介

  Mockito是一个单元测试框架,需要Junit的支持。在我们的项目中,都存在相当多的依赖关系,当我们在测试某一个业务相关的接口或则方法时,绝大多数时候是没有办法或则很难去添加所有的依赖,因为这中间肯定会涉及到别的业务逻辑。而在开发过程中,可能这个模块根本都还没有。那可咋怎啊?这个时候一种叫做mock测试的方式就顺势崛起。通过模拟出依赖对象,并对涉及到的方法设置预期值。这样你就可以只关心依赖方法的结果,从而完成对本模块的单元测试。这种方法还细化了测试粒度。棒棒的。想做更多了解就自行解决了。

Mockito的使用

  1. 首先来一个最基本的Junit测试
@Test
public void stringUtilTest(){ boolean b = StringUtil.isEmpty("good");
Assert.assertTrue("must true",b);//断言 }

  像这种对工具类的测试,一般很少依赖别的类,所以直接断言之。当然断言的类型还有很多,这里就试用一下对boolean的断言。

  2.  mockito对依赖的模拟,并设置预期返回值。针对依赖的方法有返回值。在单元测试时,我们不想也最好不要直接调用依赖的方法的具体实现,因为所依赖的方法可能本来就没有经过测试,还存在bug,难道这时候又要为依赖的方法再写一个test case?或则这个方法由别人开发,但是目前还没有实现,难道要自己去实现?you`d better say NO!看看下面怎么做的。

  

import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Date;
import java.util.List; /**
* @auther guozg
*/ public class MockTest {
@Test
public void mockReturnTest(){
// mock creation 创建模拟对象
UserDao mockeDao = Mockito.mock(UserDao.class);
UserService s = new UserService();//创建被测试类
s.setDao(mockeDao);//为被测试类添加依赖
Mockito.when(mockeDao.getData(Mockito.anyString())).thenReturn(4).thenReturn(1);//为模拟对象方法设置预期返回值,
boolean b = s.checkDate(); //多个thenReturn表示多次调用时,依次返回
boolean b1 = s.checkDate(); //如果设置的预期个数少于调用次数,超过的调用都返回最后一个。
boolean b2 = s.checkDate(); //如果设置的预期个数多于调用次数,任然依次返回相应值
Mockito.verify(mockeDao, Mockito.times(1)).getData(Mockito.anyString());
Assert.assertTrue("must true",b);
Assert.assertFalse("must true",b1);
Assert.assertFalse("must true",b2);
}
} class UserService{
UserDao dao ;
public boolean checkDate(){
     String id = "123";
if(dao.getData(id)>3){
return true;
}
return false;
} public UserDao getDao() {
return dao;
} public void setDao(UserDao dao) {
this.dao = dao;
} } class UserDao{
public Integer getData(String id){ return 0; }
}

  这里随便举的简单例子,我需要对UserService.checkDate()做一个单元测试。而这时候UserService对UserDao存在依赖关系。所以这时候为了隔离UserDao的实现,通过Mockito.mock模拟出UserDao对象。并为掉用的getData()设置了预期返回值。然后调用要测试的方法、验证设置预期的方法是否被调用,最后对测试方法的返回值断言。这里指的一说的是Mockito.anyString()这个方法,他的主要目的是表示在模拟状态下,getData()的参数可以是任意字符串。当然也可以直接给定一些参数,如果模拟对象指定的参数和实际逻辑给的参数不一致,这时候不会返回实际UserDao中getData()的值也不会返回设置的预期值,而是返回的返回类型的默认值,比如int就返回0,boolean返回false等。Mockito还有很多类似的方法,比如anyInt(),anyBoolen(),anyCollection()等等。

  还有就是看到thenReturn()方法,这是在为依赖方法设置预期返回值,这个就可以有自己控制了。然后看到可以连续多次设置,这个在代码里面有注释了,由于对语言表达能力的不自信,来个表格展示一下。

                

  然后还有一个验证方法是否被调用Mockito.verify()这个方法的参数是模拟的对象、VerificationMode。这个VerificationMode就是一个验证模型,可以是代表调用次数、是否调用、超时验证,等等(有些我也不知道干啥的,要进一步研究)。verify()可以理解为断言。

  3.  对于有返回值的方法,我们可以通过设置预期来控制,并且隔离掉具体的实现。但是对于没有返回值得方法呢?不着急,Mockti为我们提供了另一种方式可以控制模拟对象的方法的行为,包括逻辑处理、抛异常、返回值、执行原方法逻辑以及什么都不做。doReturn()|doThrow()| doAnswer()|doNothing()|doCallRealMethod();下面先来测试一下doAnswer();首先,我们会在UserDao 中加一个setUser(User u)方法,为user设置年龄,然后通过UserService的checkData中调用。然后我们通过doAnwser去控制setUser的逻辑。

package com.centnet.train.user.controller;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer; import java.util.ArrayList;
import java.util.Date;
import java.util.List; /**
* @auther guozg
*/ public class MockTest { @Test
public void doAnwserTest(){
// mock creation 创建模拟对象
UserDao mockeDao = Mockito.mock(UserDao.class);
UserService s = new UserService();//创建被测试类
User u = new User();
s.setDao(mockeDao);//为被测试类添加依赖
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
User u = invocationOnMock.getArgument(0);
u.setName("ggg");
return null;
}
}).when(mockeDao).setUser(u);
Mockito.when(mockeDao.getData()).thenReturn(4);
boolean b = s.checkDate(u); Mockito.verify(mockeDao, Mockito.times(1)).getData();
Mockito.verify(mockeDao, Mockito.times(1)).setUser(u);
Assert.assertTrue("must true",b);
Assert.assertNotNull("控制不成功",u.getName());
Assert.assertNull("原逻辑被执行",u.getAge());
}
} class UserService{
UserDao dao ;
public boolean checkDate(User u){
dao.setUser(u);
if(dao.getData()>3){
return true;
}
return false;
} public UserDao getDao() {
return dao;
} public void setDao(UserDao dao) {
this.dao = dao;
} public void setUser(User user){
user.setAge(12); } } class UserDao{
public Integer getData(){
return 0;
} public void setUser(User user){
user.setAge(12);
}
} class User{ String name;
Integer age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

  我们在UserDao中只设置了age,但是对age为空的断言却成功了。这表示原逻辑没有执行。再看看对Name的不为空断言,也通过了。这表示对setUser的行为被doAnwser()控制了。doAnwser()需要传入对一个Anwser对象,这个对象有点和代理对象类似。如果调用方法有返回值,则anwer()的返回值就是它。invocationOnMock.getArgument(0)获取参数,然后就可以对参数操作啦啦啦啦。其他几个也可以试试,比如改成调用原逻辑,Mockito.doCallRealMethod().when(mockeDao).setUser(u)。哎呀呀,这时候user的age就有了而且还是18.重点:对于在测试;类中的方法不用设置预期,会调用原逻辑,但是对于依赖类的方法就要设置预期了,否则会对有返回值的仅返回类型默认值、无返回值的直接啥都不做走人。

  好了,下班了,先到这里,以后有新的接触,在添加进来,以上例子略显粗犷,如不慎入坑,请包涵!(说得好像有人会看似的!!!要真有人看,基于以上例子可灵活处理。)

Mockito单元测试的更多相关文章

  1. JUnit + Mockito 单元测试

    原 JUnit + Mockito 单元测试(二) 2015年01月05日 17:26:02 sp42a 阅读数:60755 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...

  2. JUnit + Mockito 单元测试(二)

    摘自: http://blog.csdn.net/zhangxin09/article/details/42422643 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 入门 ...

  3. 使用 Mockito 单元测试 – 教程

    tanyuanji@126.com 版本历史 - - - - 使用 Mockito 进行测试 该教程主要讲解 Mockito 框架在Eclipse IDE 中的使用   目录 tanyuanji@12 ...

  4. JUnit + Mockito 单元测试(二)(good)

    import org.junit.Test; import org.mockito.Matchers; import org.mockito.Mockito; import java.util.Lis ...

  5. 基于spring与mockito单元测试Mock对象注入

    转载:http://www.blogjava.net/qileilove/archive/2014/03/07/410713.html 1.关键词 单元测试.spring.mockito 2.概述 单 ...

  6. 一文让你快速上手 Mockito 单元测试框架

    前言 在计算机编程中,单元测试是一种软件测试方法,通过该方法可以测试源代码的各个单元功能是否适合使用.为代码编写单元测试有很多好处,包括可以及早的发现代码错误,促进更改,简化集成,方便代码重构以及许多 ...

  7. Mockito单元测试实战

    最近使用Mockito完成了几个简单的测试,写个博客mark一下: 第一种模拟web请求 @SpringBootTest @RunWith(SpringRunner.class) @WebAppCon ...

  8. Junit Hamcrest Mockito单元测试

    pom.xml配置 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="h ...

  9. Mockito单元测试框架学习

    基本使用方法: http://zhongl.iteye.com/blog/296136 一.问题:如何将mock的类自动注入到待测类,特别是在没有setter方法的情况下. 解答: 前提:待测的ser ...

随机推荐

  1. 『Two 树的直径求解及其运用』

    树的直径 我们先来认识一下树的直径. 树是连通无环图,树上任意两点之间的路径是唯一的.定义树上任意两点\(u, v\)的距离为\(u\)到\(v\)路径上边权的和.树的直径\(MN\)为树上最长路径, ...

  2. 『数组的最大代价 贪心优化DP』

    数组的最大代价(51nod 1270) Description 数组A包含N个元素A1, A2......AN.数组B包含N个元素B1, B2......BN.并且数组A中的每一个元素Ai,都满足1 ...

  3. Python爬虫入门教程 19-100 51CTO学院IT技术课程抓取

    写在前面 从今天开始的几篇文章,我将就国内目前比较主流的一些在线学习平台数据进行抓取,如果时间充足的情况下,会对他们进行一些简单的分析,好了,平台大概有51CTO学院,CSDN学院,网易云课堂,慕课网 ...

  4. 【朝花夕拾】Android性能篇之(三)Java内存回收

    在上一篇日志([朝花夕拾]Android性能篇之(二)Java内存分配)中有讲到,JVM内存由程序计数器.虚拟机栈.本地方法栈.GC堆,方法区五个部分组成.其中GC堆是一块多线程的共享区域,它存在的作 ...

  5. Android客户端与服务器交互方式-小结

    最近的Android项目开发过程中一个问题困扰自己很长时间,Android客户端与服务器交互有几种方式,最常见的就是webservices和json.要在Android手机客户端与pc服务器交互,需要 ...

  6. TCP/IP 三次握手

    网络连接状态 网络连接状态(11种)非常重要这里既包含三次握手中的也包括四次断开中的,所以要熟悉. LISTEN 被动打开,首先服务器需要打开一个socket进行监听,监听来自远方TCP端口的连接请求 ...

  7. 前端笔记之JavaScript(七)深入函数&DOM那点事

    一.函数补充 1.1 arguments类数组对象 arguments 是一个对应于传递给函数的参数的类数组对象. 在函数中,使用特殊对象 arguments,开发者无需明确指出参数名,就能访问它们. ...

  8. JavaScript面向对象--封装

    一.封装的概念 面向对象的类包括两大成员,一种是暴露给外部的接口,另一种是只在类内部才能访问的私有属性.在这个类被实例化成对象后,用户只能通过操作给定的接口来访问该类内部的私有属性,这就被称为面向对象 ...

  9. Oracle学习笔记二

    多表查询: 笛卡尔积: 实际上是两张表的乘积,但是在实际开发中没有太大意义 格式: select * from 表1,表2 select * from emp; select * from dept; ...

  10. 线程的私有领地 ThreadLocal

    从名字上看,『ThreadLocal』可能会给你一种本地线程的概念印象,可能会让你联想到它是一个特殊的线程. 但实际上,『ThreadLocal』却营造了一种「线程本地变量」的概念,也就是说,同一个变 ...