2.2 参数匹配器实战


参数匹配器实战

参数匹配器(Argument Matchers)是Mockito实现灵活测试的核心工具,允许开发者通过模糊匹配或自定义条件验证方法参数。本章通过典型场景解析匹配器的使用技巧和常见陷阱。


1. 内置匹配器使用场景

Mockito提供丰富的内置匹配器,覆盖常见参数类型:

1.1 基础类型匹配
// 匹配任意字符串
when(userDao.findByUsername(anyString())).thenReturn(user);

// 匹配非空对象
when(orderService.createOrder(isNotNull())).thenReturn("ORDER_123");

// 匹配特定类型(忽略子类)
when(apiClient.send(any(JsonRequest.class))).thenReturn(response);
1.2 集合与复杂对象
// 匹配非空集合
verify(reportGenerator).generate(argThat(list -> !list.isEmpty()));

// 匹配Map包含特定键
when(configService.getConfig(argThat(map -> map.containsKey("timeout"))))
   .thenReturn(defaultConfig);
1.3 混合精确与模糊匹配
// 第一个参数精确匹配,第二个参数任意整型
when(paymentService.charge(eq("user_001"), anyInt()))
   .thenReturn(true);

// 注意:若方法有多个参数,使用匹配器时所有参数必须用匹配器!

2. 自定义参数匹配器

通过实现ArgumentMatcher接口或使用Lambda表达式创建高级匹配逻辑。

2.1 实现ArgumentMatcher接口
// 定义匹配年龄大于18岁的用户
public class AdultUserMatcher implements ArgumentMatcher<User> {
    @Override
    public boolean matches(User user) {
        return user != null && user.getAge() > 18;
    }
}

// 使用自定义匹配器
verify(userDao).save(argThat(new AdultUserMatcher()));
2.2 Lambda表达式简化
// 验证订单金额超过100且状态为PAID
verify(orderService).processOrder(argThat(order -> 
    order.getAmount() > 100 && order.getStatus() == OrderStatus.PAID
));
2.3 复用匹配器(提升可读性)
// 定义可重用的匹配器
public static ArgumentMatcher<User> hasValidEmail() {
    return user -> user.getEmail().matches("^\\S+@\\S+\\.\\S+$");
}

// 在测试中使用
verify(emailService).sendWelcomeEmail(argThat(hasValidEmail()));

3. 匹配器组合技巧
3.1 集合元素验证
// 验证列表包含特定元素
verify(analyticsService).trackEvents(argThat(list ->
    list.contains("purchase") && list.size() == 2
));
3.2 异步回调参数捕获
// 验证回调参数在异步操作后被修改
verify(asyncProcessor).setCompletionCallback(argThat(callback -> {
    callback.onComplete(); // 触发回调逻辑
    return true; // 始终匹配,实际测试中需结合状态验证
}));
3.3 忽略不重要的参数
// 只关心第一个参数,忽略时间戳
when(logService.write(eq("ERROR"), anyLong(), anyString()))
   .thenReturn(true);

4. 常见错误与解决方案
错误场景解决方案
混合精确值和匹配器所有参数必须使用匹配器:eq("fixed")替代直接写值
过度使用any()导致测试不严谨关键参数使用精确匹配或条件约束
自定义匹配器中修改参数状态保持匹配器无副作用,仅用于验证
匹配null值混淆明确使用isNull()nullable()(Mockito 2.1+)

5. 匹配器性能优化
  1. 缓存复杂匹配器
    频繁使用的自定义匹配器应定义为静态常量。
  2. 避免深层嵌套对象匹配
    对复杂对象提取关键字段验证,而非全对象匹配。
  3. 优先使用内置匹配器
    例如anyList()argThat(list -> true)更高效。

6. 实战案例:电商优惠券验证
@Test
void applyCoupon_ShouldVerifyComplexConditions() {
    // 模拟优惠券服务
    CouponService mockCouponService = mock(CouponService.class);
    OrderService orderService = new OrderService(mockCouponService);

    // 执行测试:应用优惠券
    orderService.applyCoupon("USER_1001", "SUMMER2023");

    // 验证:优惠券服务被调用,且参数满足:
    // - 用户ID以"USER_"开头
    // - 优惠券代码全大写
    // - 使用时间为当天
    verify(mockCouponService).validateCoupon(
        argThat(userId -> userId.startsWith("USER_")),
        argThat(code -> code.equals(code.toUpperCase())),
        argThat(useTime -> useTime.toLocalDate().equals(LocalDate.now()))
    );
}

总结

  • 匹配器选择原则
    • 关键参数 → 精确匹配(eq()
    • 非关键参数 → 模糊匹配(any()
    • 复杂条件 → 自定义argThat()
  • 保持测试可读性
    • 为自定义匹配器定义有意义的名称
    • 在验证失败时输出清晰的错误信息

通过合理使用参数匹配器,可以显著提升测试代码的适应性和可维护性,同时避免过度指定带来的脆弱性。接下来可学习Spy对象与部分Mock 进一步掌握精准控制技巧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

防火墙用户认证实验

1、创建vlan10和vlan20 2、将接口划分到对应的vlan中 [FW]interface GigabitEthernet 1/0/1.1 [FW-GigabitEthernet1/0/1.1]ip address 172.16.1.254 24 [FW-GigabitEthernet1/0/1.1]vlan-type dot1q 10 [FW]interface GigabitEthernet 1/0/1.2 [FW-GigabitEthernet1/0/1.1]ip …

VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现

VUE项目中实现权限控制&#xff0c;菜单权限&#xff0c;按钮权限&#xff0c;接口权限&#xff0c;路由权限&#xff0c;操作权限&#xff0c;数据权限实现 权限系统分类&#xff08;RBAC&#xff09;引言菜单权限按钮权限接口权限路由权限 菜单权限方案方案一&#xff1a;菜单…

ESXi Host Client创建ubuntu虚拟机教程及NVIDIA显卡驱动安装

参考文章 VMware虚拟机显卡直通记录 AIGC 实战&#xff08;环境篇&#xff09; - EXSI 8.0 Debian安装RTX3060显卡驱动 重点介绍 client版本是7.0.3 注意&#xff1a;下图中不要选择BIOS 按照两个链接中的方法进行操作&#xff0c;以及本章节的上面几个图片的配置之后&a…

DeepSeek帮助做【真】软件需求-而不是批量刷废话

尝试给DeepSeek一份系统用例规约&#xff0c;让它帮判断哪些地方还没有覆盖涉众利益。结果见以下 需求工作的重点可以放在建模精细的真实现状流程和精细的真实涉众利益上&#xff0c;AI帮助推演系统需求。

apache-poi导出excel数据

excel导出 自动设置宽度&#xff0c;设置标题框&#xff0c;设置数据边框。 excel导出 添加依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.2</version></dependency>…

10 FastAPI 的自动文档

FastAPI 是一个功能强大且易于使用的 Web 框架&#xff0c;它的最大亮点之一就是内置的 自动文档生成 功能。通过集成 Swagger UI 和 ReDoc&#xff0c;FastAPI 可以自动为我们的 API 生成交互式文档。这不仅使得开发者能够更快速地了解和测试 API&#xff0c;还能够为前端开发…

微软AI研究团队推出LLaVA-Rad:轻量级开源基础模型,助力先进临床放射学报告生成

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

mysql8.0使用MHA实现高可用

一、MHA 介绍 MHA&#xff08;Master HA&#xff09;是一款开源的 MySQL 的高可用程序&#xff0c;它为 MySQL 主从复制架构提供了 automating master failover 功能。MHA 在监控到 master 节点故障时&#xff0c;会提升其中拥有最新数据的 slave 节点成为新的master 节点&…

D3实现站点路线图demo分享

分享通过D3实现的站点路线分布图demo&#xff0c;后续会继续更新其他功能。 功能点 点位弹窗 效果图如下&#xff1a; 轨迹高亮 效果图如下&#xff1a; 添加路线箭头 箭头展示逻辑&#xff1a;根据高速路线最后两个点位&#xff0c;计算得出箭头的点位 效果图如下&#x…

【系统架构设计师】操作系统 ③ ( 存储管理 | 页式存储弊端 - 段式存储引入 | 段式存储 | 段表 | 段表结构 | 逻辑地址 的 合法段地址判断 )

文章目录 一、页式存储弊端 - 段式存储引入1、页式存储弊端 - 内存碎片2、页式存储弊端 - 逻辑结构不匹配3、段式存储引入 二、段式存储 简介1、段式存储2、段表3、段表 结构4、段内地址 / 段内偏移5、段式存储 优缺点6、段式存储 与 页式存储 对比 三、逻辑地址 的 合法段地址…

物联网软件开发与应用方向应该怎样学习,学习哪些内容,就业方向是怎样?(文末领取整套学习视频,课件)物联网硬件开发与嵌入式系统

随着物联网技术的飞速发展&#xff0c;物联网软件开发与应用方向成为了众多开发者关注的焦点。那么&#xff0c;如何在这个领域中脱颖而出呢&#xff1f;本文将为你提供一份详细的学习指南&#xff0c;帮助你从零开始&#xff0c;逐步掌握物联网软件开发与应用的核心技能。 一…

Linux——基础命令1

$&#xff1a;普通用户 #&#xff1a;超级用户 cd 切换目录 cd 目录 &#xff08;进入目录&#xff09; cd ../ &#xff08;返回上一级目录&#xff09; cd ~ &#xff08;切换到当前用户的家目录&#xff09; cd - &#xff08;返回上次目录&#xff09; pwd 输出当前目录…

OpenFeign远程调用返回的是List<T>类型的数据

在使用 OpenFeign 进行远程调用时&#xff0c;如果接口返回的是 List 类型的数据&#xff0c;可以通过以下方式处理&#xff1a; 直接定义返回类型为List Feign 默认支持 JSON 序列化/反序列化&#xff0c;如果服务端返回的是 List的JSON格式数据&#xff0c;可以直接在 Feig…

向量数据库简单对比

文章目录 一、Chroma二、Pinecone/腾讯云VectorDB/VikingDB三、redis四、Elasticsearch五、Milvus六、Qdrant七、Weaviate八、Faiss 一、Chroma 官方地址&#xff1a; https://www.trychroma.com/优点 ①简单&#xff0c;非常简单构建服务。 ②此外&#xff0c;Chroma还具有自…

字符指针、数组指针和函数指针

1. 字符指针变量 1.1 简单例子 字符指针 char* 在C语言中主要由两种用法&#xff1a; 1.用于存放一个字符变量的地址。 2.用字符指针接收一个字符串。 这里并不是将整个字符串的地址存入 pstr 指针&#xff0c;指针变量 pstr 中存放的是常量字符串的首字符 h 的地址。 以一个…

【Linux网络编程】之守护进程

【Linux网络编程】之守护进程 进程组进程组的概念组长进程 会话会话的概念会话ID 控制终端控制终端的概念控制终端的作用会话、终端、bash三者的关系 前台进程与后台进程概念特点查看当前终端的后台进程前台进程与后台进程的切换 作业控制相关概念作业状态&#xff08;一般指后…

JS宏进阶:XMLHttpRequest对象

一、概述 XMLHttpRequest简称XHR&#xff0c;它是一个可以在JavaScript中使用的对象&#xff0c;用于在后台与服务器交换数据&#xff0c;实现页面的局部更新&#xff0c;而无需重新加载整个页面&#xff0c;也是Ajax&#xff08;Asynchronous JavaScript and XML&#xff09;…

怎么查看电脑显存大小(查看电脑配置)

这里提供一个简单的方法查看 winr打开cmd 终端输入dxdiag进入DirectX 点击显示查看设备的显示内存&#xff08;VRAM&#xff09; 用这个方法查看电脑配置和显存是比较方便的 dxdiag功能 Dxdiag是Windows的DirectX诊断工具&#xff0c;其主要作用包括但不限于以下几点&#…

优惠券平台(一):基于责任链模式创建优惠券模板

前景概要 系统的主要实现是优惠券的相关业务&#xff0c;所以对于用户管理的实现我们简单用拦截器在触发接口前创建一个单一用户。 // 用户属于非核心功能&#xff0c;这里先通过模拟的形式代替。后续如果需要后管展示&#xff0c;会重构该代码 UserInfoDTO userInfoDTO new…

【机器学习】数据预处理之scikit-learn的Scaler与自定义Scaler类进行数据归一化

scikit-learn的Scaler数据归一化 一、摘要二、训练数据集和测试数据集的归一化处理原则三、scikit-learn中的Scalar类及示例四、自定义StandardScaler类进行数据归一化处理五、小结 一、摘要 本文主要介绍了scikit-learn中Scaler的使用方法&#xff0c;特别强调了数据归一化在…