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

如何为从AWS S3获取响应的方法编写JUnit 5测试用例

如何为S3读取方法编写JUnit 5测试用例(Mock S3客户端)

需求说明

我有一个服务类中的方法,需要Mock s3Client.getObject(getObjectRequest) 方法,使其返回可用于断言的数据,请求指导编写JUnit 5测试用例。

目标方法代码

public String getResponseFromS3(String applicationId, S3FileDirectoryEnum directory) {

    try {

        String key = getKey(applicationId, directory);
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                                                            .bucket(bucketName)
                                                            .key(key)
                                                            .build();


        ResponseInputStream<GetObjectResponse> s3ClientObject = s3Client.getObject(getObjectRequest);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(s3ClientObject));

        return bufferedReader.lines().collect(Collectors.joining());

    } catch (AmazonClientException exception) {
        logger.error("action", "awsError_failedToGetResponse",
                "class", exception.getClass()
                          .getSimpleName(),
                "errorMessage", exception.getMessage());
        throw exception;
    }
}
 private String getKey(String applicationId, S3FileDirectoryEnum directory) {
        return directory != null ? directory.getValue() + "/" + applicationId : applicationId;
    }

测试用例实现步骤

1. 依赖准备

确保项目引入以下核心依赖(以Maven为例):

  • JUnit 5核心依赖:junit-jupiter-api、junit-jupiter-engine
  • Mockito依赖:mockito-core、mockito-junit-jupiter
  • AWS SDK基础依赖(对应你使用的版本)

2. 完整测试类实现

使用Mockito扩展支持JUnit 5,Mock S3客户端并注入到被测试服务类中:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.GetObjectResponse;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class)
class YourServiceClassTest {

    // Mock S3客户端实例
    @Mock
    private S3Client s3Client;

    // 注入被测试的服务类(自动将Mock的s3Client注入到服务类中)
    @InjectMocks
    private YourServiceClass yourService;

    // 测试用的Bucket名称,需和服务类中配置一致
    private final String TEST_BUCKET = "test-bucket";

    @Test
    void getResponseFromS3_WithDirectory_ReturnsCorrectContent() {
        // 1. 准备测试数据
        String testAppId = "app-001";
        S3FileDirectoryEnum testDir = S3FileDirectoryEnum.CONFIG; // 假设枚举值对应路径"config"
        String expectedKey = testDir.getValue() + "/" + testAppId;
        String expectedContent = "这是从S3读取的测试内容";

        // 2. 构造Mock的S3返回流
        InputStream mockInputStream = new ByteArrayInputStream(expectedContent.getBytes(StandardCharsets.UTF_8));
        ResponseInputStream<GetObjectResponse> mockS3Response = new ResponseInputStream<>(
                GetObjectResponse.builder().build(), mockInputStream);

        // 3. Mock S3客户端的getObject方法
        when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(mockS3Response);

        // 4. 调用被测试方法
        String actualContent = yourService.getResponseFromS3(testAppId, testDir);

        // 5. 断言结果匹配
        assertEquals(expectedContent, actualContent);
    }

    @Test
    void getResponseFromS3_WithoutDirectory_ReturnsCorrectContent() {
        // 测试不传directory的场景
        String testAppId = "app-002";
        String expectedKey = testAppId;
        String expectedContent = "无目录的测试内容";

        InputStream mockInputStream = new ByteArrayInputStream(expectedContent.getBytes(StandardCharsets.UTF_8));
        ResponseInputStream<GetObjectResponse> mockS3Response = new ResponseInputStream<>(
                GetObjectResponse.builder().build(), mockInputStream);

        when(s3Client.getObject(any(GetObjectRequest.class))).thenReturn(mockS3Response);

        String actualContent = yourService.getResponseFromS3(testAppId, null);

        assertEquals(expectedContent, actualContent);
    }

    @Test
    void getResponseFromS3_S3Error_ThrowsException() {
        // 测试S3客户端抛出异常的场景
        String testAppId = "app-003";
        AmazonClientException testException = new AmazonClientException("S3访问失败:权限不足");

        when(s3Client.getObject(any(GetObjectRequest.class))).thenThrow(testException);

        // 断言方法正确抛出异常
        AmazonClientException thrownException = assertThrows(AmazonClientException.class,
                () -> yourService.getResponseFromS3(testAppId, null));

        assertEquals(testException.getMessage(), thrownException.getMessage());
    }
}

3. 关键细节说明

  • Mock返回流:用ByteArrayInputStream构造模拟的S3文件内容,再包装成AWS要求的ResponseInputStream类型,确保和方法返回类型匹配。
  • 参数验证(可选):如果需要确认生成的GetObjectRequest中的bucket和key是否符合预期,可以使用ArgumentCaptor捕获请求对象,再做断言:
    import org.mockito.ArgumentCaptor;
    // ...
    ArgumentCaptor<GetObjectRequest> requestCaptor = ArgumentCaptor.forClass(GetObjectRequest.class);
    when(s3Client.getObject(requestCaptor.capture())).thenReturn(mockS3Response);
    // 断言请求参数
    assertEquals(TEST_BUCKET, requestCaptor.getValue().bucket());
    assertEquals(expectedKey, requestCaptor.getValue().key());
    
  • 日志验证(可选):如果需要验证异常日志是否正确输出,可以Mock服务类中的Logger,然后验证logger.error的调用参数。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 23:27:08