You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 10:23:33