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

Java单元测试无法Mock AmazonS3实例 调用真实方法报403错误

单元测试Mock AmazonS3仍发起真实请求报403的解决方法

问题表现

业务代码中通过内部方法构建AmazonS3客户端调用listObjectsV2接口,测试时已编写Mock配置,但执行到S3调用逻辑时抛出真实请求的权限错误:

Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied;

涉及的业务代码(Processor类):

AmazonS3 s3 = getS3Build();
final List<String> flagFiles = s3.listObjectsV2(dataBucket, flagFolder);

public AmazonS3 getS3Build() {
    return AmazonS3ClientBuilder.standard().withRegion(US_EAST_1).build();
}

原有测试Mock配置:

Mockito.when(processor.getS3Build()).thenReturn(s3);
Mockito.when(s3.listObjectsV2(anyString(), anyString())).thenReturn(listObjectsV2Result);

根因分析

出现这个问题基本是两个原因导致:

  • 被测试的processor是普通真实实例,没有声明为Spy对象,执行Mockito.when(processor.getS3Build())时会先真实调用getS3Build()方法,生成可发起真实请求的S3客户端,后续业务逻辑拿到真实客户端就会发起实际S3请求。
  • 打桩Spy对象方法时用了when().thenReturn()语法,该语法会先执行一次真实方法,同样会生成真实S3客户端导致Mock失效。部分低版本AWS SDK的S3客户端实现类带final修饰,默认Mockito配置无法Mock final类/方法,会直接走真实实现。

正确实现方案

方案1:修正现有Mock配置(最小改动)

  1. 测试类先开启Mockito注解支持:JUnit4环境在测试类上加@RunWith(MockitoJUnitRunner.class),JUnit5环境加@ExtendWith(MockitoExtension.class)。
  2. 把被测试的processor声明为@Spy+@InjectMocks,AmazonS3实例声明为@Mock。
  3. 打桩getS3Build()方法时改用doReturn().when()语法,避免触发真实方法调用。
    完整测试代码示例:
@ExtendWith(MockitoExtension.class) // JUnit4换@RunWith(MockitoJUnitRunner.class)
public class ProcessorTest {
    @Mock
    private AmazonS3 s3;
    @Mock
    private ListObjectsV2Result listObjectsV2Result;
    @Spy
    @InjectMocks
    private Processor processor;

    @Test
    public void testS3ListLogic() {
        // 注意这里必须用doReturn打桩spy的方法,不要用when().thenReturn
        doReturn(s3).when(processor).getS3Build();
        when(s3.listObjectsV2(anyString(), anyString())).thenReturn(listObjectsV2Result);

        // 执行业务测试逻辑
        processor.executeYourBusinessMethod();

        // 验证交互、断言结果
        verify(s3, times(1)).listObjectsV2(anyString(), anyString());
    }
}

如果是SDK版本导致final类无法Mock,升级Mockito到3.4.0以上版本,在src/test/resources/mockito-extensions路径下创建名为org.mockito.plugins.MockMaker的文件,文件内容填写mock-maker-inline,即可开启final类/方法的Mock支持。

方案2:重构代码优化可测试性(推荐)

不要在业务类内部直接通过Builder构建S3客户端,改为构造器注入AmazonS3实例,从根源上避免Mock内部构建方法的问题,更符合依赖注入规范:
重构后的Processor类:

private final AmazonS3 s3;

// 构造器注入S3客户端,生产环境传入真实客户端,测试时传入Mock对象
public Processor(AmazonS3 s3) {
    this.s3 = s3;
}

public void executeYourBusinessMethod() {
    // 直接使用注入的s3实例,不需要单独的getS3Build方法
    final List<String> flagFiles = s3.listObjectsV2(dataBucket, flagFolder);
    // 后续业务逻辑
}

重构后测试时直接把Mock好的AmazonS3实例传入Processor构造器即可,不需要额外打桩内部构建方法,稳定性更高。


内容的提问来源于stack exchange,提问作者Vishal Sain

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 12:45:31