如何为从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
相关产品推荐
相关产品推荐

