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

Guava Cache异常未被捕获?Mockito测试报错求助

Guava Cache异常未捕获问题排查

问题场景

使用Guava Cache时,预期缓存加载失败时抛出自定义DependencyException,但测试触发了Mockito异常,自定义异常完全未被捕获,即使尝试捕获Throwable也无效。

代码片段

缓存设置

CacheLoader<String, Set<String>> loader = new CacheLoader<>() {
    public Set<String> load(String s) {
        return privateFunction(s);
    }
};

this.cache = CacheBuilder.newBuilder().maximumSize(1000).expireAfterWrite(5, TimeUnit.MINUTES)
        .build(loader);

业务实现

public Set<String> getTeamIdsForEmployee(String employeeAlias) {
    try {
        return this.cache.get(employeeAlias);
    } catch (ExecutionException e) {
        throw new DependencyException(
                "message",
                e);
    }
}

测试代码

@Test(expectedExceptions = DependencyException.class)
public void testGetTeamIdsForEmployeeCacheException() {
    doThrow(new ExecutionException("Test exception", new Exception()))
            .when(thing).privateFunction(eq("SAMPLE"));

    myClass.callCache("SAMPLE");
}

测试报错信息

[testng] 期望捕获类型为com.amazon.ampspermissionsservice.exceptions.DependencyException的异常,但实际得到org.mockito.exceptions.base.MockitoException: 
[testng] 该方法不能抛出受检异常!
[testng] 无效异常:java.util.concurrent.ExecutionException

问题原因

核心是Mockito的受检异常限制:

  • privateFunction方法未声明抛出ExecutionException(受检异常),Mockito不允许强制给未声明受检异常的方法抛出受检异常;
  • 测试代码尝试让privateFunction抛出ExecutionException时,Mockito直接抛出MockitoException打断流程,程序根本没走到cache.get()的try-catch逻辑,自然不会触发DependencyException。

解决方案

方案1:模拟非受检异常

如果privateFunction本身不声明抛出受检异常,改为模拟抛出RuntimeException子类,Guava Cache会自动将其包装为ExecutionException,进入catch块后转换为自定义异常:

@Test(expectedExceptions = DependencyException.class)
public void testGetTeamIdsForEmployeeCacheException() {
    // 模拟抛出非受检异常
    doThrow(new RuntimeException("Test exception"))
            .when(thing).privateFunction(eq("SAMPLE"));

    myClass.callCache("SAMPLE");
}

方案2:修改方法签名并模拟合法受检异常

如果privateFunction实际可能抛出受检异常,先修改其方法签名声明抛出对应异常,再模拟抛出该异常:

// 修改privateFunction的方法签名
private Set<String> privateFunction(String s) throws Exception {
    // 原有业务逻辑
}

// 测试代码调整
@Test(expectedExceptions = DependencyException.class)
public void testGetTeamIdsForEmployeeCacheException() {
    doThrow(new Exception("Test exception"))
            .when(thing).privateFunction(eq("SAMPLE"));

    myClass.callCache("SAMPLE");
}

核心逻辑说明

ExecutionException是Guava Cache用来包装CacheLoader.load()方法抛出异常的容器,不应由业务方法直接抛出。正确流程是:业务方法抛出异常 → Guava Cache包装为ExecutionException → 业务代码捕获并转换为自定义异常。

内容的提问来源于stack exchange,提问作者alex.weavers

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 18:15:40