mockito使用教程

article/2025/10/8 21:14:32

一、什么是 Mock 测试

Mock 测试就是在测试过程中,对于某些不容易构造(如 HttpServletRequest 必须在Servlet 容器中才能构造出来)或者不容易获取比较复杂的对象(如 JDBC 中的ResultSet 对象),用一个虚拟的对象(Mock 对象)来创建以便测试的测试方法。Mock 最大的功能是帮你把单元测试的耦合分解开,如果你的代码对另一个类或者接口有依赖,它能够帮你模拟这些依赖,并帮你验证所调用的依赖的行为。
先来看看下面这个示例:

 


从上图可以看出如果我们要对A进行测试,那么就要先把整个依赖树构建出来,也就是BCDE的实例。
一种替代方案就是使用mocks

 


从图中可以清晰的看出
mock对象就是在调试期间用来作为真实对象的替代品。
mock测试就是在测试过程中,对那些不容易构建的对象用一个虚拟对象来代替测试的方法就叫mock测试。

二、Mockito是什么

Mockito 是一个流行 mock 框架,可以和JUnit结合起来使用。Mockito 允许你创建和配置 mock 对象。使用Mockito可以明显的简化对外部依赖的测试类的开发。

I notice that Mockito was voted "the best mock framework for Java" on Stackoverflow.

 

三、使用方法

1、添加Maven依赖

<!-- mockito -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.8.5</version>
<scope>test</scope>
</dependency>

 

如果使用springboot的话,有自带可以不用引入

 

2、建议静态导入会使代码更简洁

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

3、例子

3.1 创建一个mock对象,并校验

@Test
public void Demo1() {
// mock creation 创建mock对象
List mockedList = mock(List.class);//using mock object 使用mock对象
mockedList.add("one");
mockedList.clear();//verification 验证
verify(mockedList).add("one");
verify(mockedList).clear();
}

 

3.2 使用测试桩
默认情况下,所有的函数都有返回值。mock函数默认返回的是null,一个空的集合或者一个被对象类型包装的内置类型,例如0、false对应的对象类型为Integer、Boolean;
测试桩函数可以被覆写 : 例如常见的测试桩函数可以用于初始化夹具,但是测试函数能够覆写它。请注意,覆写测试桩函数是一种可能存在潜在问题的做法;
一旦测试桩函数被调用,该函数将会一致返回固定的值;
上一次调用测试桩函数有时候极为重要-当你调用一个函数很多次时,最后一次调用可能是你所感兴趣的。

@Test
public void Demo2() {
// 你可以mock具体的类型,不仅只是接口
LinkedList mockedList = mock(LinkedList.class);// 测试桩(可以使用连续调用)
when(mockedList.get(0)).thenReturn("first");
//when(mockedList.get(0)).thenReturn("first").thenReturn("second");
when(mockedList.get(1)).thenThrow(new RuntimeException());// 输出“first”
System.out.println(mockedList.get(0));
// 连续调用则输出“second”
//System.out.println(mockedList.get(0));// 抛出异常
System.out.println(mockedList.get(1));// 因为get(999) 没有打桩,因此输出null
System.out.println(mockedList.get(999));// 验证get(0)被调用的次数
verify(mockedList).get(0);
}

 

3.3 验证函数的确切、最少、从未调用次数

@Test
public void Demo3() {
// 你可以mock具体的类型,不仅只是接口
LinkedList mockedList = mock(LinkedList.class);
//using mock
mockedList.add("once");mockedList.add("twice");
mockedList.add("twice");mockedList.add("three times");
mockedList.add("three times");
mockedList.add("three times");// 下面的两个验证函数效果一样,因为verify默认验证的就是times(1)
verify(mockedList).add("once");
verify(mockedList, times(1)).add("once");// 验证具体的执行次数
verify(mockedList, times(2)).add("twice");
verify(mockedList, times(3)).add("three times");// 使用never()进行验证,never相当于times(0)
verify(mockedList, never()).add("never happened");// 使用atLeast()/atMost()
verify(mockedList, atLeastOnce()).add("three times");// mockedList.add("five times");
// mockedList.add("five times");
// mockedList.add("five times");
// mockedList.add("three times");
// mockedList.add("three times");
// mockedList.add("three times");
//最少or最多
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");}

 

3.4 模拟异常

@Test
public void Demo4() {LinkedList mockedList = mock(LinkedList.class);
doThrow(new RuntimeException()).when(mockedList).clear();// 调用这句代码会抛出异常
mockedList.clear();
}

 

3.5 验证执行执行顺序

@Test
public void Demo5() {
// A. 验证mock一个对象的函数执行顺序
List singleMock = mock(List.class);singleMock.add("was added first");
singleMock.add("was added second");
singleMock.contains("111");
singleMock.isEmpty();
singleMock.remove(0);
singleMock.get(0);// 为该mock对象创建一个inOrder对象
InOrder inOrder = inOrder(singleMock);// 确保add函数首先执行的是add("was added first"),然后才是add("was added second")
inOrder.verify(singleMock).add("was added first");
inOrder.verify(singleMock).add("was added second");
inOrder.verify(singleMock).contains("111");
inOrder.verify(singleMock).isEmpty();
inOrder.verify(singleMock).remove(0);
inOrder.verify(singleMock).get(0);// // B .验证多个mock对象的函数执行顺序
// List firstMock = mock(List.class);
// List secondMock = mock(List.class);
//
// firstMock.add("was called first");
// secondMock.add("was called second");
//
// // 为这两个Mock对象创建inOrder对象
// InOrder inOrder = inOrder(firstMock, secondMock);
//
// // 验证它们的执行顺序
// inOrder.verify(firstMock).add("was called first");
// inOrder.verify(secondMock).add("was called second");// Oh, and A + B can be mixed together at will
}

 

3.6 spy
然而很多时候,你希望达到这样的效果:除非指定,否者调用这个对象的默认实现,同时又能拥有验证方法调用的功能。这正好是spy对象所能实现的效果。创建一个spy对象,以及spy对象的用法介绍如下:

@Test
public void Demo6() {List list = new LinkedList();
List spy = spy(list);// 你可以为某些函数打桩
when(spy.size()).thenReturn(100);// 通过spy对象调用真实对象的函数
spy.add("one");
spy.add("two");// 输出第一个元素
System.out.println(spy.get(0));// 因为size()函数被打桩了,因此这里返回的是100
System.out.println(spy.size());// 交互验证
verify(spy).add("one");
verify(spy).add("two");
}

 

3.7 在监控对象上使用when(Object)来进行打桩是不可能或者不切实际的。
因此,当使用监控对象时请考虑doReturn|Answer|Throw()函数族来进行打桩。

@Test
public void Demo7(){
List list = new LinkedList();
List spy = spy(list);// 不可能 : 因为当调用spy.get(0)时会调用真实对象的get(0)函数,此时会发生IndexOutOfBoundsException异常,因为真实List对象是空的
//when(spy.get(0)).thenReturn("foo");// 你需要使用doReturn()来打桩
doReturn("foo").when(spy).get(anyInt());System.out.println(spy.get(0));
// doThrow(new RuntimeException()).when(spy).get(anyInt());
// System.out.println(spy.get(0));
}

 

3.8使用注解形式来模拟测试对象,必须在初始化fields (领域),有2种方式初始化:

@RunWith(@MockitoJUnitRunner.class) 标注 JUnit 测试类
@Before 之前调用 MockitoAnnotations.initMocks(Object)
@Before
public void init(){
MockitoAnnotations.initMocks(this);
}

 

或者

@RunWith(MockitoJUnitRunner.class)

 

这里补充一下几个注解的作用

一般项目测试是用@RunWith(SpringRunner.class)

这个运行器来启动的,有些教程使用的是SpringJUnit4ClassRunner这个运行器,我们可以查看源码,其实是同一个东西,

public final class SpringRunner extends SpringJUnit4ClassRunner {public SpringRunner(Class<?> clazz) throws InitializationError {super(clazz);}
}

 

3.9 参数捕获

ArgumentCaptor类允许我们在verification期间访问方法的参数。得到方法的参数后我们可以使用它进行测试。
ArgumentCaptor是一个能够捕获参数值的特殊参数匹配器。捕获一个 Mock 对象的方法调用所传递的参数

@Test
public void testCaptureArgument() {List<String> list = Arrays.asList("1", "2");List mockedList = mock(List.class);ArgumentCaptor<List> argument = ArgumentCaptor.forClass(List.class);mockedList.addAll(list);verify(mockedList).addAll(argument.capture());assertEquals(2, argument.getValue().size());assertEquals(list, argument.getValue());
}

 

3.10 RETURNS_SMART_NULLS 和 RETURNS_DEEP_STUBS

RETURNS_SMART_NULLS

(返回默认值-查看源码: ReturnsMoreEmptyValues)
RETURNS_SMART_NULLS
在创建mock对象时,有的方法我们没有进行stubbing,所以在调用的时候有时会返回Null这样在进行处理时就很可能抛出NullPointerException。如果通过RETURNS_SMART_NULLS参数来创建的mock对象在调用没有stubbed的方法时他将返回SmartNull。例如:返回类型是String它将返回空字符串””;是int,它将返回0;如果是List,它会返回一个空的List。另外,在堆栈中可以看到SmartNull的友好提示。 


由于使用了RETURNS_SMART_NULLS参数来创建mock对象,所以在执行下面的操作时将不会抛出NullPointerException异常,另外堆栈也提示了相关的信息“SmartNull returned by unstubbed get() method on mock”。 

@Test
public void returnsSmartNullsTest() {//List mock = mock(List.class);List mock = mock(List.class, RETURNS_SMART_NULLS);System.out.println(mock.get(0));// 使用RETURNS_SMART_NULLS参数创建的mock对象,不会抛出NullPointerException异常。// 另外控制台窗口会提示信息“SmartNull returned by unstubbed get() method on mock”
    System.out.println(mock.toArray().length);
}

 

RETURNS_DEEP_STUBS

(判断是否需要返回默认值,否则创建mock对象 ReturnsDeepStubs)
RETURNS_DEEP_STUBS参数程序会自动进行mock所需的对象,方法deepstubsTest和deepstubsTest2是等价的

public class FakeEntity {private UserFakeEntity userFakeEntity;public UserFakeEntity getUserFakeEntity() {return userFakeEntity;}public void setUserFakeEntity(UserFakeEntity userFakeEntity) {this.userFakeEntity = userFakeEntity;}
}@Test
public void deepstubsTest() {//FakeEntity fakeEntity = mock(FakeEntity.class);//这样会NullPointerExceptionFakeEntity fakeEntity = mock(FakeEntity.class, RETURNS_DEEP_STUBS);when(fakeEntity.getUserFakeEntity().getName()).thenReturn("Beijing");System.out.println(fakeEntity.getUserFakeEntity().getName());assertEquals("Beijing", fakeEntity.getUserFakeEntity().getName());
}@Test
public void deepstubsTest2() {FakeEntity fakeEntity = mock(FakeEntity.class);UserFakeEntity userFakeEntity = mock(UserFakeEntity.class);when(fakeEntity.getUserFakeEntity()).thenReturn(userFakeEntity);when(userFakeEntity.getName()).thenReturn("Beijing");System.out.println(fakeEntity.getUserFakeEntity().getName());assertEquals("Beijing", fakeEntity.getUserFakeEntity().getName());
}

 

四、实战使用

4.1登录的例子

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.boot.test.context.SpringBootTest;import static org.mockito.Mockito.*;//基于MockitoJUnitRunner的运行器
@RunWith(MockitoJUnitRunner.class)
//@RunWith(SpringRunner.class)
@SpringBootTest
public class MockLoginTest {//自动将模拟对象或侦查域注入到被测试对象中。
//对被测类中@Autowired的对象,用@Mocks标注;对被测类自己,用@InjectMocks标注
@InjectMocks
private UserServiceImpl userService;@Mock
private UserRepository userDao;@Mock
private BargainBlackListService bargainBlackListService;@Mock
private DistributionUserService distributionUserService;@Mock
private AuthorityService authorityService;@Before
public void init(){
MockitoAnnotations.initMocks(this);
}@Test
public void loginTest() {
//模拟方法动作
//spyUserService在调用getUserEntity方法的时候,指定返回事先定义好的userEntity
UserService spyUserService = spy(userService);
UserEntity userEntity = new UserEntity();
userEntity.setUserName("ppp");
doReturn(userEntity).when(spyUserService).getUserEntity(anyString());
when(bargainBlackListService.checkBlackList(anyString())).thenReturn(true);
UserInfoDTO userInfoDTO = new UserInfoDTO();
userInfoDTO.setUserName("ppp");
userInfoDTO.setId("2c95808a644ade6801644ae37f730000");
spyUserService.updateUserInfo("0520b1d9-9806-4ec1-a095-dfcd8bea8fd6", userInfoDTO);
}}

 

转载于:https://www.cnblogs.com/oldboyooxx/p/11147474.html


http://chatgpt.dhexx.cn/article/mmVBRXYd.shtml

相关文章

Mockito教程

目录 1 Mockito 介绍 1.1 Mockito是什么&#xff1f; 1.2 为什么需要Mock 1.3 Stub和Mock异同 1.4 Mockito资源 1.5 使用场景 2 使用Mockito 2.1 验证行为 2.2 模拟我们所期望的结果 2.3 RETURNS_SMART_NULLS和RETURNS_DEEP_STUBS 2.4 模拟方法体抛出异常 …

python的取整函数:向上取整,向下取整,四舍五入取整

#encoding:utf-8 import math#向上取整 print "math.ceil---" print "math.ceil(2.3) > ", math.ceil(2.3) print "math.ceil(2.6) > ", math.ceil(2.6)#向下取整 print "\nmath.floor---" print "math.floor(2.3) > &q…

[Python] Python数值取整

美图欣赏2022/06/22 1.向上取整math.ceil() 不论正负,所有小数都是向着数值更大的方向取整 import math math.ceil(-0.5) # 0 math.ceil(-0.9) # 0 math.ceil(0) # 0 math.ceil(0.5) # 1 math.ceil(1.2) # 2 2.向下取整math.floor() 不论正负,所有小数都是向着数值更小的方…

python的 取整 及 四舍五入方法(包含list元素取整)

目录 1、向下取整int()2、四舍五入round()2.1 表达式&#xff1a;2.2 注意&#xff1a;尽量不用round&#xff01;&#xff0c;原因如下 3、向上取整math.ceil()4、分别取整数部分和小数部分5、list元素取整 1、向下取整int() >>> a 3.75 >>> int(a) 32、四…

python中取整数操作

python中取整数操作 ★向靠近零的方向取整 int(x)内置函数【https://docs.python.org/zh-cn/3/library/functions.html#int 】&#xff0c;向靠近零的方向取整&#xff0c;x是数字表达式&#xff0c;如 int(4.4) #得到4 int(-4.4) #得到-4 int(4.5) #得到4 int(-4.5) …

python取整(不同方法的取整)

1. 向下取整 int是截断取整 举个例子 4.x等于4 2.四舍五入 round( )函数简介 菜鸟教程中介绍到&#xff0c;round() 函数作用就是&#xff0c;返回浮点数x的四舍五入值。 x round(5.76543, 2) print(x) >>> x5.773、向上取整 向上取整需要用到 math 模块中的 ce…

【Java之网络】网络基本概念总结

网络相关概念 一. 局域网和广域网1. 局域网&#xff08;LAN&#xff09;&#xff08;1&#xff09;定义&#xff08;2&#xff09;特点 2. 广域网&#xff08;WAN&#xff09;&#xff08;1&#xff09;定义&#xff08;2&#xff09;特点 二. IP地址和端口号1. IP地址2. 端口号…

java网络编程学习基础篇

一、基础背景 时代背景 自2000年左右&#xff0c;Web的快速发展以及2010左右的云原生和云计算的提出&#xff0c;网络通信的重要性越来越凸显出来&#xff1b; 对于用户来说&#xff1a;软件的响应速度和体验是越来越重要的&#xff0c;而网络通信是决定响应速度关键因素之一…

神经网络和CNN的一些基础概念,基础知识的梳理

&#xff08;好吧&#xff0c;这又是一篇软文&#xff0c;适合初学者&#xff09; 一、通用概念&#xff1a; 1. 有监督学习方法与非监督学习方法&#xff1a; 必须要有训练集与测试样本&#xff0c;模型在训练集中寻找规律&#xff0c;训练结束对测试样本使用这种规律进行…

一些神经网络基础知识归纳

神经网络&#xff08;NN&#xff09;复杂度 NN复杂度&#xff0c;多用NN层数和NN参数个数表示 如上图示 空间复杂度 层数隐藏层的层数1个输出层 上图为2层NN 总参数 3*44 4*2226 时间复杂度 乘加运算次数 3*44*220 指数衰减学习率 可以先用较大学习率&#xff0c;快速得…

Java网络编程(一)网络的基本认知

前言 这是一个信息化的时代&#xff0c;在生活中&#xff0c;网络通信无处不在。比如发送短信&#xff0c;邮件&#xff0c;视频通话等。 以邮件为例子&#xff1a; ① 收件人&#xff1a; 相当于网络编程的ip地址端口号&#xff0c;定位到某一个具体的地方&#xff01;只有找…

第四章 使用JAVA构建神经网络

• 构建一个神经网络 •激活函数 • Encog持久化 •在代码里使用Encog Analyst 这章将展示用Encog怎样构造前馈与简单递归神经网络,以及在最后部分怎样保存这些神经网络。创建神经网络类型使用BasicNetwork和BasicLayer这两个类&#xff0c;除了这两个类&#xff0c;还使用…

深入浅出讲解神经网络的种类及举例说明

本文收录于《深入浅出讲解自然语言处理》专栏&#xff0c;此专栏聚焦于自然语言处理领域的各大经典算法&#xff0c;将持续更新&#xff0c;欢迎大家订阅&#xff01;个人主页&#xff1a;有梦想的程序星空个人介绍&#xff1a;小编是人工智能领域硕士&#xff0c;全栈工程师&a…

Java网络基础知识

目录 一&#xff0c;计算机网络 1&#xff0c;概念 2&#xff0c;计算机网络的主要功能 3&#xff0c;计算机网络分类 二&#xff0c;网络通信协议及接口 1&#xff0c;网络通信协议 2&#xff0c;网络通信接口 3&#xff0c;通信协议分层思想 4&#xff0c;协议分类 …

神经网络可以用来分类吗,神经网络如何实现分类

怎么用spss神经网络来分类数据 。 用spss神经网络分类数据方法如下&#xff1a;神经网络算法能够通过大量的历史数据&#xff0c;逐步建立和完善输入变量到输出结果之间的发展路径&#xff0c;也就是神经网络&#xff0c;在这个神经网络中&#xff0c;每条神经的建立以及神经…

BP神经网络JAVA实现详解

注&#xff1a;本文手动搬家自我的新浪博客点击打开链接 从2016年3月份左右&#xff0c;我的毕业设计开题答辩时间正好是AlphaGo大战李世石之日。还记得当时答辩PPT最末引用的图片还是这张&#xff1a; 李世石大战Google的AlphaGo 不过当时答辩情况并不理想&#xff0c;答辩组老…

Java网络编程--网络基础

文章目录 网络协议常用网络协议族&#xff08;簇&#xff09;(protocol)端口&#xff08;port&#xff09;常见知名端口动态端口 IP地址IP地址分类IPv4的分类IPv6子网掩码 网络协议 是为计算机网络中进行数据交换而建立的规则、标准或约定的集合。为了使不同计算机厂家生产的计…

神经网络如何实现分类,神经网络基本概念

人工神经网络分类方法 从20世纪80年代末期&#xff0c;人工神经网络方法开始应用于遥感图像的自动分类。 目前&#xff0c;在遥感图像的自动分类方面&#xff0c;应用和研究比较多的人工神经网络方法主要有以下几种&#xff1a;&#xff08;1&#xff09;BP&#xff08;BackP…

神经网络如何进行分类

1.首先搞清楚什么是感知机 如上图所示&#xff0c;输入为向量&#xff0c;经线性变换&#xff0c;再通过激活函数得到输出&#xff0c;这样一个完整的结构成为感知机。感知机是人工神经网络的最小单元&#xff0c;本质上由一个仿射变换接一个非线性变换组成。 上图wxb属于仿射变…

Java基础学习(17)网络编程

Java基础学习 一、 网络编程1.1 什么是网络编程1.2 常见的软件架构&#xff1a;1.3 网络编程的三要素1.4 IP1.4.1 InetAddress用法 1.5 端口号1.6 协议1.6.1 UDP协议1.6.1.1 UDP的三种通信方式 1.6.2 TCP协议1.6.2.1 TCP底层原理 一、 网络编程 1.1 什么是网络编程 解释&…