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

如何Mock读取S3文件?单元测试遇两类异常求解决

分析你的两个异常及解决方案

咱们一步步拆解你遇到的问题,然后给出修复方案:

第一个异常:Argument passed to when() is not a mock!

这个错误出在测试代码的这一行:

Mockito.doNothing().when(AmazonS3ClientBuilder.standard());

AmazonS3ClientBuilder.standard()返回的是真实的Builder实例,不是Mockito创建的mock对象。Mockito的when()方法只能用来 stub mock对象的方法调用,不能用在真实类的实例上,所以抛出这个异常。

更关键的是,你后面又调用了AmazonS3ClientBuilder.build()创建了真实的S3客户端,这就导致测试中实际使用的是真实客户端而非你mock的client变量,后面的stub逻辑完全没生效,还会触发真实的AWS请求,进而引发第二个异常。

第二个异常:profile file cannot be null

这个错误是因为真实的ProfileCredentialsProvider需要读取本地的AWS凭证文件(通常在~/.aws/credentials),而你的测试环境中没有这个文件,所以抛出了参数为空的异常。而且测试场景下,我们根本不应该使用真实的凭证提供者——测试应该和外部服务(比如AWS S3)解耦。


核心修复思路:依赖注入

解决问题的关键是把S3客户端从方法内部创建改成外部注入,这样测试时可以传入mock的客户端,完全避免创建真实客户端和触发真实请求。

第一步:重构业务代码

把AmazonS3客户端作为类的依赖,通过构造函数注入,而不是在amazonS3Read方法内部创建:

public class S3JsonProcessor {
    private final AmazonS3 s3Client;
    private String jsonContent;

    // 构造函数注入S3客户端,方便测试时传入mock
    public S3JsonProcessor(AmazonS3 s3Client) {
        this.s3Client = s3Client;
    }

    public void readJsonFromS3() {
        String bucketName = "version";
        String key = "version.txt";
        
        // 使用try-with-resources自动关闭流,避免手动关闭的遗漏
        try (S3Object fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key));
             S3ObjectInputStream s3is = fullObject.getObjectContent()) {
            
            jsonContent = convertInputStreamToString(s3is);
            // 这里处理JSON数据的逻辑
        } catch (AmazonServiceException e) {
            e.printStackTrace();
        } catch (SdkClientException | IOException e) {
            e.printStackTrace();
        }
    }

    // 工具方法:InputStream转String
    private String convertInputStreamToString(InputStream is) throws IOException {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
            String line;
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
        }
        return sb.toString();
    }

    // 提供getter方便测试验证结果
    public String getJsonContent() {
        return jsonContent;
    }
}

第二步:修改测试代码

现在可以完全用Mockito来mock S3客户端和相关对象,模拟S3文件的内容,不需要依赖真实的AWS服务:

import org.junit.Test;
import org.mockito.Mockito;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.GetObjectRequest;
import com.amazonaws.services.s3.model.S3Object;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.Assert.assertEquals;

public class S3JsonProcessorTest {

    @Test
    public void testReadJsonFromS3() throws Exception {
        // 1. 创建所有需要的mock对象
        AmazonS3 mockS3Client = Mockito.mock(AmazonS3.class);
        S3Object mockS3Object = Mockito.mock(S3Object.class);

        // 2. 准备测试用的JSON数据,转成InputStream模拟S3文件内容
        String testJson = "{\"appVersion\": \"2.1.0\"}";
        InputStream mockInputStream = new ByteArrayInputStream(testJson.getBytes());

        // 3. Stub方法调用:当调用mockS3Client.getObject时返回mockS3Object
        GetObjectRequest request = new GetObjectRequest("version", "version.txt");
        Mockito.when(mockS3Client.getObject(request)).thenReturn(mockS3Object);

        // 4. Stub mockS3Object的getObjectContent方法,返回我们的测试流
        Mockito.when(mockS3Object.getObjectContent()).thenReturn(mockInputStream);

        // 5. 创建业务类实例,传入mock的S3客户端
        S3JsonProcessor processor = new S3JsonProcessor(mockS3Client);

        // 6. 执行测试方法
        processor.readJsonFromS3();

        // 7. 验证结果和方法调用
        assertEquals(testJson, processor.getJsonContent());
        // 验证mock对象的方法是否按预期被调用
        Mockito.verify(mockS3Client).getObject(request);
        Mockito.verify(mockS3Object).getObjectContent();
    }
}

为什么这样修复有效?

  1. 解耦外部依赖:通过依赖注入,业务代码不再直接创建S3客户端,测试时可以完全控制客户端的行为,不需要连接真实的AWS服务。
  2. 正确使用Mockito:所有的when()调用都作用在Mockito创建的mock对象上,符合框架的使用规则,不会再出现"Argument passed to when() is not a mock!"异常。
  3. 避免凭证问题:测试中使用mock客户端,根本不会触发真实的AWS请求,也就不需要AWS凭证文件,解决了profile file cannot be null的问题。
  4. 更稳定的测试:测试不依赖外部服务和网络,执行速度更快,结果更可靠。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:48:51