java单元测试模拟分布式锁的核心是用mockito隔离外部依赖,通过mock trylock返回true/false/异常及unlock的donothing/dothrow,结合依赖注入和verify验证调用次数与参数,避免使用embedded redis等重量级方案。

Java 单元测试中模拟分布式锁的加锁/解锁行为,核心思路是不真正依赖 Redis 或 ZooKeeper 等外部组件,而是通过Mock 工具隔离依赖、控制返回值与副作用,验证业务逻辑在“锁成功”“锁失败”“锁超时”“解锁异常”等关键路径下的正确性。
用 Mockito Mock 分布式锁客户端
大多数分布式锁实现(如 Redisson、Lettuce、自研基于 Redis 的锁)都封装了加锁(tryLock)、解锁(unlock)等方法。只要这些方法定义在接口或可 mock 的类上,就能用 Mockito 替换其行为:
- Mock
tryLock()返回true(模拟抢锁成功),验证主流程执行 - Mock 返回
false(锁已被占用),验证降级逻辑或重试机制 - Mock 抛出异常(如
RedisConnectionException),验证异常处理是否健壮 - 对
unlock()做doNothing()或doThrow(),检查解锁失败时是否影响后续流程
避免直接 new 实例,改用依赖注入
如果锁对象是 new 出来的(如 new RedisDistributedLock(...)),Mockito 默认无法拦截。必须重构为可注入依赖:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 将锁实例声明为成员变量,并通过构造函数或 setter 注入
- 测试时传入 Mock 对象,而非真实客户端
- 例如:业务类构造器接收
DistributedLock lock接口,测试中@Mock DistributedLock mockLock
验证锁的调用次数与参数(关键!)
仅检查结果不够,还需确认锁是否按预期被调用:
- 用
verify(mockLock).tryLock("order:123", 30, TimeUnit.SECONDS)核实锁 key 和超时时间是否正确 - 用
verify(mockLock, times(1)).unlock()确保只解锁一次(防止重复 unlock 导致异常) - 若业务含重试逻辑,可验证
tryLock()被调用多次(如times(3))
慎用嵌入式 Redis(如 Embedded Redis)
虽然 embedded-redis 能启动本地 Redis 实例做“集成测试”,但它不属于单元测试范畴,存在启动慢、端口冲突、状态残留等问题:
- 适合少量关键场景的冒烟测试或本地调试,不要放进常规单元测试套件
- CI 环境中更易失败,增加构建不稳定性
- 真正需要测锁的并发行为(如两个线程争同一把锁),应使用多线程集成测试,而非单元测试
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










