Java Reactor+Caffeine缓存+Mockito严格存根参数不匹配问题
解决Mockito Strict Stubbing参数不匹配问题(Spring Boot 3 + Reactor + Caffeine场景)
针对你在Spring Boot 3、Java 17、JUnit5环境下,使用Reactor和Caffeine异步缓存时遇到的Mockito Strict Stubbing参数不匹配问题,以下是常见原因及对应解决方案:
1. Lambda/Supplier参数的引用不匹配
CachingService.ofMono通常会接收Supplier<Mono<Resource>>类型的加载器参数,Mockito默认按对象引用比较参数。如果测试存根时使用的Lambda和业务代码中的Lambda是不同实例,即使逻辑一致,也会触发参数不匹配错误。
解决方案:
- 使用通配符匹配参数,替代硬编码的Lambda实例:
when(cachingService.ofMono(eq("target-cache-key"), any(Supplier.class))) .thenReturn(Mono.just(mockResource)); - 如需验证加载器逻辑,用
ArgumentCaptor捕获Supplier并手动校验:ArgumentCaptor<Supplier<Mono<Resource>>> loaderCaptor = ArgumentCaptor.forClass(Supplier.class); verify(cachingService).ofMono(eq("target-cache-key"), loaderCaptor.capture()); // 触发加载器并验证结果 Mono<Resource> loadedResource = loaderCaptor.getValue().get(); StepVerifier.create(loadedResource) .expectNext(mockResource) .verifyComplete();
2. 缓存Key的隐性不匹配
看似相同的缓存Key,可能存在以下隐性差异:
- 字符串字面量与
new String()实例的引用差异 - 大小写、空格等字符细节差异
- 自定义Key对象未重写
equals()/hashCode()
解决方案:
- 统一使用同一个Key变量,或用
eq()匹配值而非引用:String TEST_KEY = "user-resource-1001"; when(cachingService.ofMono(eq(TEST_KEY), any())).thenReturn(Mono.just(mockResource)); // 业务代码调用时复用TEST_KEY变量,避免硬写字符串 - 自定义Key对象必须重写
equals()和hashCode(),确保Mockito能按值比较。
3. 重载方法混淆
如果CachingService.ofMono存在多个重载版本(例如带过期时间参数的重载),存根时可能误匹配到错误的方法签名,导致参数不匹配。
解决方案:
- 核对
ofMono的方法签名,确保存根与业务调用的参数数量、类型完全一致。例如:// 假设存在重载:ofMono(String key, Duration expire, Supplier<Mono<T>> loader) when(cachingService.ofMono(eq(TEST_KEY), eq(Duration.ofMinutes(5)), any())) .thenReturn(Mono.just(mockResource));
4. Strict Stubbing模式的严格校验
Mockito 3+默认启用Strict Stubbing模式,会对未存根的调用、参数不匹配的调用直接报错。如果测试中存在未预期的调用,也会触发该错误。
解决方案:
- 临时开启宽松模式排查问题(不推荐长期使用,建议修复参数匹配逻辑):
// 在测试类上全局设置宽松模式 @MockitoSettings(strictness = Strictness.LENIENT) class BusinessServiceTest { /* ... */ } // 或针对单个存根设置宽松模式 lenient().when(cachingService.ofMono(anyString(), any())).thenReturn(Mono.just(mockResource));
5. Reactor Mono实例的引用差异
如果ofMono直接接收Mono类型参数,Mockito会按实例引用比较,即使两个Mono的发布内容一致,实例不同也会报错。
解决方案:
- 使用
any(Mono.class)匹配,或用argThat()校验Mono的实际内容:when(cachingService.ofMono(eq(TEST_KEY), argThat(mono -> { StepVerifier.create(mono).expectNext(mockResource).verifyComplete(); return true; }))).thenReturn(Mono.just(mockResource));
内容的提问来源于stack exchange,提问作者Melih
相关产品推荐
相关产品推荐

