Mockito

小王学习录

  • 依赖
  • 注解
    • Mock
    • @Spy
    • 静态方法单元测试
    • @InjectMocks 注解
    • @Captor 注解
    • @BeforeAll 和 BeforeEach的区别
    • @ParameterizedTest
      • @ValueSource
      • @EnumSource
      • @CsvSource
      • @MethodSource
  • 打桩
    • 打桩方式
    • 打桩参数匹配方式

在这里插入图片描述

依赖

       <!-- https://mvnrepository.com/artifact/org.mockito/mockito-inline --><dependency><groupId>org.mockito</groupId><artifactId>mockito-inline</artifactId><version>5.2.0</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/org.junit.jupiter/junit-jupiter-api --><dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter-api</artifactId><version>5.10.2</version><scope>test</scope></dependency>

注解

Mock

class MockTestTest {@Mockprivate MockTest demo;@BeforeEachvoid setup(){MockitoAnnotations.openMocks(this);}@Testvoid add() {Mockito.when(demo.add(1, 2)).thenReturn(3);System.out.println(demo.add(1, 2));Assertions.assertEquals(3, demo.add(1, 2));Mockito.verify(demo, Mockito.times(2)).add(1, 2);}@AfterEachvoid after(){System.out.println("测试完毕 ");}
}

@Spy

class SpyTestTest {@Spyprivate SpyTest spyTest;@BeforeEachvoid setUp(){MockitoAnnotations.openMocks(this);}@Testvoid add() {Mockito.when(spyTest.add(1, 2)).thenReturn(4);System.out.println(spyTest.add(1, 2));Mockito.verify(spyTest).add(1,2);Assertions.assertEquals(4, spyTest.add(1, 2));//Mockito.verify(spyTest, Mockito.times(2)).add(1, 2);Mockito.when(spyTest.add(1, 2)).thenCallRealMethod();System.out.println(spyTest.add(1, 2));}
}

静态方法单元测试

class StaticTestTest {@Testvoid add() {MockedStatic<StaticTest> test1 = Mockito.mockStatic(StaticTest.class);test1.when(()->StaticTest.add(1, 2)).thenReturn(4);System.out.println(StaticTest.add(1, 2));Assertions.assertEquals(4, StaticTest.add(1, 2));}
}

@InjectMocks 注解

@Captor 注解

@Captor 是 Mockito 框架中的一个注解,用于创建 ArgumentCaptor 实例。ArgumentCaptor 在单元测试中扮演着重要角色,它允许你在测试过程中捕获(capture)被测方法调用时传入的实际参数值,以便对这些参数进行详细的断言验证。

假设有一个 EmailService 类,它有一个方法 sendEmail(Recipient recipient, EmailMessage message),我们想要测试这个方法是否正确地将邮件发送给了预期的收件人。可以编写如下使用 @Captor 注解的单元测试:

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;import static org.mockito.Mockito.verify;public class EmailServiceTest {@Mockprivate EmailGateway emailGateway; // Mocked dependency for sending emailsprivate EmailService emailService;@Captorprivate ArgumentCaptor<Recipient> recipientCaptor;@Captorprivate ArgumentCaptor<EmailMessage> messageCaptor;@BeforeEachvoid setUp() {MockitoAnnotations.initMocks(this);emailService = new EmailService(emailGateway);}@Testpublic void testSendEmail() {Recipient expectedRecipient = new Recipient("john.doe@example.com");EmailMessage expectedMessage = new EmailMessage("Subject", "Body");emailService.sendEmail(expectedRecipient, expectedMessage);// 使用 captors 捕获实际传递给 sendEmail 方法的参数verify(emailGateway).sendEmail(recipientCaptor.capture(), messageCaptor.capture());// 使用 captured 参数进行断言Recipient actualRecipient = recipientCaptor.getValue();EmailMessage actualMessage = messageCaptor.getValue();assertEquals(expectedRecipient.getEmail(), actualRecipient.getEmail());assertEquals(expectedMessage.getSubject(), actualMessage.getSubject());assertEquals(expectedMessage.getBody(), actualMessage.getBody());}
}
  1. 使用 @Mock 注解创建了 EmailGateway 的 mock 对象。
  2. 使用 @Captor 注解声明了两个 ArgumentCaptor 实例,分别对应 sendEmail 方法的 Recipient 和 EmailMessage 参数。
  3. 在 setUp 方法中初始化 mock 和被测试的 EmailService。
  4. 在 testSendEmail 测试方法中,调用 emailService.sendEmail() 方法,传入期望的参数。
  5. 使用 verify 方法验证 emailGateway.sendEmail() 是否被调用,并且使用 captors 捕获实际传递的参数。
  6. 最后,通过 captors 获取捕获的参数值,并进行详细的断言验证,确保它们与预期值相匹配。
  7. 通过 @Captor 注解和 ArgumentCaptor,我们能够有效地验证 sendEmail 方法是否正确地将预期的收件人和邮件内容传递给了依赖的 EmailGateway。

@BeforeAll 和 BeforeEach的区别

@BeforeAll 和 @BeforeEach 是 JUnit 5 中用于在测试执行前进行初始化工作的两个注解,它们的主要区别在于执行时机和适用场景:

@BeforeAll

执行时机:
@BeforeAll 注解的方法将在当前测试类中所有测试方法执行之前只执行一次。

适用场景:

  • 一次性昂贵资源的初始化:当测试类中的所有测试方法都需要共享一个昂贵的资源(如数据库连接、网络连接、第三方服务客户端等),并且创建或连接这个资源的成本较高时,使用 @BeforeAll 来初始化一次,避免在每个测试方法前重复执行。
  • 全局数据加载:如果有一组测试数据需要从文件、数据库或其他外部源加载,且所有测试方法都会使用同一份数据,那么可以使用 @BeforeAll 来提前加载数据,避免多次加载带来的性能开销。
  • 长时间运行的预设条件:当有一些耗时较长但对所有测试方法通用的预设条件(如模拟复杂环境、配置全局系统状态等),应放在 @BeforeAll 注解的方法中执行。
  • 静态环境配置:如果需要对静态变量、系统属性或全局配置进行一次性设定,适用于 @BeforeAll。
    注意事项:

@BeforeAll 注解的方法必须是静态方法,因为它们在测试类实例化之前执行。
如果这些方法抛出异常,所有测试方法都将跳过执行。

@BeforeEach
执行时机:
@BeforeEach 注解的方法将在每个测试方法执行之前单独执行一次。

适用场景:
测试数据的独立准备:每个测试方法可能需要不同的测试数据或对象状态,使用 @BeforeEach 可以为每个测试方法单独准备所需的测试数据或对象实例。
对象重置:如果被测试对象具有状态,且每次测试方法执行后需要将其状态重置为初始状态,@BeforeEach 方法可以负责这项清理和重置工作。
局部依赖注入:对于那些仅在一个测试方法执行期间有效的依赖项,可以在 @BeforeEach 方法中注入。
重复性环境配置:对于每次测试开始时都需要重新配置的环境设置(如清除缓存、重置模拟对象状态等),应在 @BeforeEach 注解的方法中进行。
注意事项:

@BeforeEach 注解的方法不能是静态的,因为它们与每个测试方法的执行紧密相关,通常需要访问非静态的成员变量或方法。
如果某个 @BeforeEach 方法执行失败(抛出异常),仅影响紧随其后的那个测试方法,其他测试方法仍会尝试执行各自的 @BeforeEach 方法。

总结来说,@BeforeAll 用于执行一次即可满足整个测试类需求的、成本较高的初始化操作,适用于共享资源的设置和全局数据的加载;而 @BeforeEach 则是在每个测试方法执行前进行针对性的、可能因测试方法不同而有所差异的准备工作,确保每个测试方法在独立、一致的环境中运行。选择使用哪一个注解取决于测试场景的具体需求和资源管理策略。

@ParameterizedTest

@ParameterizedTest 是 JUnit 5 提供的一种用于执行参数化测试的注解。参数化测试允许同一个测试方法使用不同的输入数据集(参数)多次执行,从而提高测试覆盖率和代码复用性。通过这种方式,可以轻松地验证被测代码在多种不同情况下的行为,确保其正确性和一致性。

通常需要配合@ValueSource、@EnumSource、@CsvSource、@MethodSource一起使用。

@ValueSource

用途:@ValueSource 用于为参数化测试提供一组固定的值。这些值可以是基本类型(如 int、double、String 等)或其对应的包装类型。

使用场景:
测试某个方法或函数在一系列特定值上的表现,如验证数学函数在不同整数、浮点数上的计算结果。
验证类的构造函数或方法对各种边界值(如最大值、最小值、零值、正负值等)的处理是否正确。

@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void testSquareRoot(int input, int expectedOutput) {double result = Math.sqrt(input);assertEquals(expectedOutput, result, 0.01, "Square root of " + input + " should be close to " + expectedOutput);
}

@EnumSource

用途:@EnumSource 专门用于为参数化测试提供枚举类型的值。它可以指定要使用的枚举类,并可以选择性地提供筛选条件(如包含特定名称或值的枚举常量)。

使用场景:
对枚举类型的类进行全面测试,确保其每个枚举常量在特定场景下的行为正确。
当测试方法需要验证针对枚举类型的逻辑时,如序列化、反序列化、字符串转换等。

enum Color { RED, GREEN, BLUE }@ParameterizedTest
@EnumSource(Color.class)
void testColorToString(Color color, String expectedString) {String result = color.toString();assertEquals(expectedString, result, "toString() should return the correct string for " + color);
}

@CsvSource

用途:@CsvSource 用于提供以逗号分隔值(CSV)格式的数据集。每一行代表一组参数,各参数间以逗号分隔。这对于多参数的测试方法非常方便,可以直接在注解中列出多行数据。

使用场景:
当测试需要多组不同参数组合时,如验证数学运算、字符串处理函数、日期格式转换等。
当测试数据以表格形式存储或展示时,可以直接复制粘贴成 CSV 格式。

@ParameterizedTest
@CsvSource({"1, 2, 3","10, 5, 15","-1, .jpg, .png","abc, def, abcdef"
})
void testConcatenate(String part1, String part2, String expectedConcatenation) {String result = concatenate(part1, part2);assertEquals(expectedConcatenation, result, "Concatenation of " + part1 + " and " + part2 + " should be " + expectedConcatenation);
}

@MethodSource

用途:@MethodSource 允许参数化测试的数据来源于测试类中的一个静态方法。这个方法返回一个 Stream,其中每个 Arguments 对象封装了一组参数。这种方法提供了最大的灵活性,可以生成动态数据、读取外部资源、甚至执行复杂的逻辑来提供测试参数。

使用场景:
数据集较大或需要动态生成时,可以编写一个方法来按需生成或读取数据。
测试需要依赖外部配置文件、数据库查询结果、随机数据生成器等复杂数据源。
需要根据测试环境动态调整测试参数。

static Stream<Arguments> additionTestData() {return Stream.of(Arguments.of(1, 2, 3),Arguments.of(-1, 3, 2),Arguments.of(0, 0, 0),Arguments.of(100, -50, 50),Arguments.of(1.5, 2.75, 4.25));
}@ParameterizedTest
@MethodSource("additionTestData")
void testAdd(double num1, double num2, double expectedSum) {double result = calculator.add(num1, num2);assertEquals(expectedSum, result, "The sum should be correct for inputs: " + num1 + ", " + num2);
}

总结起来,@ValueSource、@EnumSource、@CsvSource 和 @MethodSource 分别提供了不同类型和来源的参数数据集

打桩

打桩方式

1、when().thenReturn()

2、doReturn().when()

以上两种是有返回值的方法打桩,通常使用。

3、doNothing().when()…

void方法打桩;

4、when().thenThrow()

5、doThrow().when()

以上两种是抛异常打桩;

6、when().thenAnswer()

7、doAnswer().when()

以上两种是复杂参数打桩,可以根据传参自定义返回结果。

8、@InjectMocks+@Spy,打桩被测类的某个方法

正常被单测对象使用@InjectMocks注解,被测业务逻辑复杂,比如被测方法A()→B()→C()。如果当前单元测试用例不打算测试到C()方法,就需要结合@Spy和具体打桩方式跳过C()方法。

打桩参数匹配方式

打桩时,如果被测方法有输入参数,有以下方式传参:

any()、anyList()、anyByte()、anyBoolean()、anyChar()、anyCollection()、anyDouble()、anyFloat()、anyInt()、anyIterable()、anyLong()、anyMap()、anySet()、anyShort()、anyString()

通常仅需要any(),如果被打桩的测试方法有重载,则需要指定具体的参数类型。

这些传参方法是Mockito框架中用于创建“任意匹配器”的工具,它们在编写单元测试时非常有用,特别是当我们要验证方法被调用时的参数类型和数量,而不关心具体的参数值时。简单举几个例子

  1. any():

用途:匹配任何类型的对象。当被测方法接受的对象类型不确定或不关心其具体值时使用。

import static org.mockito.Mockito.*;class Service {void process(Object input) {// ...}
}@Test
void testProcessMethod() {Service service = mock(Service.class);service.process(any()); // 匹配任何类型的对象作为输入参数verify(service).process(any()); // 验证process方法被调用时,传入了任意对象
}
  1. anyList():

用途:匹配任何类型的列表(实现 List 接口的对象)。当被测方法接受一个列表作为参数,但不关心列表的具体元素时使用。

import static org.mockito.Mockito.*;class Service {void handleList(List<String> items) {// ...}
}@Test
void testHandleListMethod() {Service service = mock(Service.class);service.handleList(anyList()); // 匹配任何类型的列表作为输入参数verify(service).handleList(anyList()); // 验证handleList方法被调用时,传入了任意列表
}
  1. anyCollection():

用途:匹配任何类型的 Collection 对象(实现了 Collection 接口的对象)。当被测方法接受一个集合作为参数,但不关心集合的具体元素时使用。

import static org.mockito.Mockito.*;class Service {void handleCollection(Collection<String> items) {// ...}
}@Test
void testHandleCollectionMethod() {Service service = mock(Service.class);service.handleCollection(anyCollection()); // 匹配任何类型的 Collection 对象作为输入参数verify(service).handleCollection(anyCollection()); // 验证handleCollection方法被调用时,传入了任意 Collection 对象
}
  1. anyIterable():

用途:匹配任何实现了 Iterable 接口的对象。当被测方法接受一个可迭代对象作为参数,但不关心其具体元素时使用。

import static org.mockito.Mockito.*;class Service {void processIterable(Iterable<String> items) {// ...}
}@Test
void testProcessIterableMethod() {Service service = mock(Service.class);service.processIterable(anyIterable()); // 匹配任何 Iterable 对象作为输入参数verify(service).processIterable(anyIterable()); // 验证processIterable方法被调用时,传入了任意 Iterable 对象
}
  1. anyMap():

用途:匹配任何类型的 Map 对象(实现了 Map 接口的对象)。当被测方法接受一个映射作为参数,但不关心其具体键值对时使用。

import static org.mockito.Mockito.*;class Service {void updateData(Map<String, Integer> data) {// ...}
}@Test
void testUpdateDataMethod() {Service service = mock(Service.class);service.updateData(anyMap()); // 匹配任何 Map 对象作为输入参数verify(service).updateData(anyMap()); // 验证updateData方法被调用时,传入了任意 Map 对象
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/313613.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Armpro脱壳软件搭建教程附源代码

PHP8.0版本&#xff0c;数据库8.0版本 1.配置注册机文件&#xff0c;打开将arm.zip/res目录下&#xff0c;mt管理器搜索将其全部修改为你自己的域名或者是服务器IP 2.然后建立数据库 数据库账号arm 数据库用户名arm 数据库密码EsZfXY4tD3h2NNA4 3.导入数据库 4.配置Redi…

03-JAVA设计模式-备忘录模式

备忘录模式 什么是备忘录模式 Java中的备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;它允许在不破坏封装性的前提下捕获一个对象的内部状态&#xff0c;并在该对象之外保存这个状态&#xff0c;以便以后可以将对象恢复到原先保存的状态…

配置有效的防爬虫技术保护网站

本文主要介绍了防爬虫的概念、目的以及一些有效的防爬虫手段。防爬虫是指网站采取各种技术手段阻止爬虫程序对其数据进行抓取的过程。为了保护网站的数据和内容的安全性&#xff0c;防止经济损失和恶意竞争&#xff0c;以及减轻服务器负载&#xff0c;网站需要采取防爬虫机制。…

统一所有 LLM API:支持预算与速率限制 | 开源日报 No.229

BerriAI/litellm Stars: 6.7k License: NOASSERTION litellm 是一个使用 OpenAI 格式调用所有 LLM API 的工具。它支持 Bedrock、Azure、OpenAI、Cohere、Anthropic 等 100 多种 LLMs&#xff0c;提供企业级代理服务器和稳定版本 v1.30.2。 主要功能和优势包括&#xff1a; 将…

探索大型语言模型(LLM)在人类性格个性评估(MBTI)中的前景与应用

1.概述 大型语言模型&#xff08;LLM&#xff09;如ChatGPT在各个领域的应用确实越来越广泛&#xff0c;它们利用庞大的数据集进行训练&#xff0c;以模拟人类的语言理解和生成能力。这些模型在提供信息、解答问题、辅助决策等方面表现出了强大的能力&#xff0c;但它们并不具…

[集群聊天项目] muduo网络库

目录 网络服务器编程常用模型什么是muduo网络库什么是epoll muduo网络库服务器编程 网络服务器编程常用模型 【方案1】 &#xff1a; accept read/write 不是并发服务器 【方案2】 &#xff1a; accept fork - process-pre-connection 适合并发连接数不大&#xff0c;计算任…

Yolov5 export.py实现onnx模型的导出

查了很多资料&#xff0c;很多用python代码写的&#xff0c;只需要这个库那个库的&#xff0c;最后都没成功。 不如直接使用Yolov5里面的 export.py实现模型的转换。 一&#xff1a;安装依赖 因为yolov5里面的requirments.txt是将这些转换模型的都注释掉了 所以需要解除注释…

人工智能论文GPT-3(2):2020.5 Language Models are Few-Shot Learners;微调;少样本Few-Shot (FS)

2 方法Approach 我们的基本预训练方法&#xff0c;包括模型、数据和训练&#xff0c;与GPT-2中描述的过程相似&#xff0c;只是模型规模、数据集规模和多样性&#xff0c;以及训练时长有所扩大&#xff0c;相对简单直接。 我们使用的上下文学习也与GPT-2相似&#xff0c;但在…

Kafka 3.x.x 入门到精通(03)——对标尚硅谷Kafka教程

Kafka 3.x.x 入门到精通&#xff08;03&#xff09;——对标尚硅谷Kafka教程 2. Kafka基础2.1 集群部署2.2 集群启动2.3 创建主题2.4 生产消息2.4.1 生产消息的基本步骤2.4.2 生产消息的基本代码2.4.3 发送消息2.4.3.1 拦截器2.4.3.1.1 增加拦截器类2.4.3.1.2 配置拦截器 2.4.3…

.NET 邮件发送 SMTP邮件发送

SMTP&#xff08;Simple Mail Transfer Protocol&#xff09;是用于电子邮件传输的规则集&#xff0c;可以从邮件客户端向接收电子邮件服务器发送、中继或转发邮件。发件人可使用SMTP 服务器来执行发送电子邮件的过程。SMTP服务器则是按照这些规则中转电子邮件的服务器。 IMAP…

【Qt QML】TabBar的用法

Qt Quick中的TabBar提供了一个基于选项卡的导航模型。TabBar由TabButton控件填充&#xff0c;并且可以与任何提供currentIndex属性的布局或容器控件一起使用&#xff0c;例如StackLayout或SwipeView。 import QtQuick import QtQuick.Controls import QtQuick.LayoutsWindow …

企业微信hook接口协议,ipad协议http,发送大视频文件

发送大视频文件 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信send_userid是long要发送的人或群idisRoom是bool是否是群消息 请求示例 {"uuid":"1688853790xxx", //uuid 默认随机生成如果初始化传了id则用初始…

潜藏10年的恶意软件被发现;利用漏洞在K8S上挖矿;AWS、Google和Azure 出现信息泄露危机 | 安全周报0419

关键词&#xff1a;OfflRouter、恶意软件、VBA宏病毒、机密文件、可执行文件、iOS间谍软件、LightSpy、F_Warehouse、Azure CLI、AWS CLI、Google Cloud CLI 1. 近十年来&#xff0c;OfflRouter恶意软件在乌克兰一直未被发现 自2015年以来&#xff0c;部分乌克兰政府网络一直…

【学习】如何高效地进行集成测试

在软件开发的过程中&#xff0c;测试环节至关重要。而在这其中&#xff0c;集成测试更是保证软件质量的关键步骤之一。本文将探讨如何高效地进行集成测试&#xff0c;以确保软件的稳定性和可靠性。 一、什么是集成测试 集成测试是指在单元测试的基础上&#xff0c;将模块按照设…

力扣刷题学习(跟随视频学着刷)

使用入门 视频链接 【手把手带你刷Leetcode力扣&#xff5c;各个击破数据结构和算法&#xff5c;大厂面试必备技能【已完结】-哔哩哔哩】 https://b23.tv/vIcRT61 时空复杂度 时间&#xff1a; 空间&#xff1a;主要有O(1)和O(n)两种&#xff0c;只用计算开辟的内存&#xff…

cdp集群Hbase组件HRegionServer服务停止原因以及排查

前言&#xff1a;重启集群后某一节点HRegionServer服务停止&#xff0c;重启前所有服务均正常 去查看日志&#xff1a; 日志报错 ERROR HRegionServer Master rejected startup because clock is out of sync org.apache.hadoop.hbase.ClockOutOfSyncException: org.apache.h…

【Python】异常、模块与包

目录 捕获异常 异常的传递 Python中的模块 模块的导入方式 as定义别名 自定义模块 Python包 第三方包 综合案例 当我们的程序遇到了BUG, 那么接下来有两种情况: ① 整个程序因为一个BUG停止运行 ② 对BUG进行提醒, 整个程序继续运行 但是在真实工作中, 我们肯定不能…

第十五届蓝桥杯省赛第二场C/C++B组D题【前缀总分】题解(AC)

暴力解法 O ( 26 n 5 ) O(26n^5) O(26n5) 枚举将第 i i i 个字符串的第 j j j 个字符改为 c c c 的所有方案&#xff0c;时间复杂度 O ( 26 n 2 ) O(26n^2) O(26n2)&#xff0c;修改并计算总分&#xff0c; O ( n 3 ) O(n^3) O(n3)。 暴力优化 O ( 26 n 3 log ⁡ n ) O…

【Pytorch】(十四)C++ 加载TorchScript 模型

文章目录 &#xff08;十四&#xff09;C 加载TorchScript 模型Step 1: 将PyTorch模型转换为TorchScriptStep 2: 将TorchScript序列化为文件Step 3: C程序中加载TorchScript模型Step 4: C程序中运行TorchScript模型 【Pytorch】&#xff08;十三&#xff09;PyTorch模型部署: T…

什么是langchain

概念 LangChain 是一个用于开发由语言模型驱动的应用程序的框架。他主要拥有 2 个能力&#xff1a; -可以将 LLM 模型&#xff08;大规模语言模型&#xff09;与外部数据源进行连接 -允许与 LLM 模型进行交互基础功能 支持多种模型接口&#xff0c;比如 OpenAI、Hugging Fac…