如何在 Junit 中模拟 S3AsyncClient

发布于 2025-01-18 21:58:41 字数 2595 浏览 0 评论 0原文

我有一种将文件上传到 Amazon S3 的方法。我正在尝试为此方法编写 JUnit,但在 S3AsyncClient:

my class:

public class S3Client<T> {
    private static final Logger log = LoggerFactory.getLogger(S3Client.class);
    S3AsyncClient client;
    /**
     *
     * @param s3Configuration
     */
    public S3Client(AWSS3Configuration s3Configuration) {
        this.client = s3Configuration.getAsyncClient();
    }


    /**
     * Uploads a file s3 bucket and returns etag
     * @param uploadData
     * @return
     * @throws S3Exception
     */
    public CompletableFuture<String> uploadFile(S3UploadData<T> uploadData) throws S3Exception {
        int contentLength;
        AsyncRequestBody asyncRequestBody;

        if(uploadData.getContent() instanceof String) {
            String content = (String) uploadData.getContent();
            contentLength = content.length();
            asyncRequestBody = AsyncRequestBody.fromString(content);
        }
        else if(uploadData.getContent() instanceof byte[]){
            byte[] bytes = (byte[]) uploadData.getContent();
            contentLength = bytes.length;
            asyncRequestBody = AsyncRequestBody.fromBytes(bytes);
        }
        else{
            throw new IllegalArgumentException("Unsupported upload content type");
        }


        PutObjectRequest putObjRequest = PutObjectRequest.builder()
                .bucket(uploadData.getBucketName())
                .key(uploadData.getFileName())
                .metadata(uploadData.getMetaData())
                .contentLength((long) contentLength).build();


        CompletableFuture<String> response = client.putObject(putObjRequest, asyncRequestBody).thenApply(
                getPutObjectResponse -> {
                    log.info("Got response from S3 upload={}", getPutObjectResponse.eTag());
                    return getPutObjectResponse.eTag();
                });
        response.exceptionally(throwable -> {
            log.error("Exception occurred while uploading a file intuit_tid={} file={}",uploadData.getTransactionId(),uploadData.getFileName());
            throw new S3Exception(throwable.getMessage());
        });
        return response;
    }

input for this class object of S3UploadData: 上得到 NullPointerException: `
@盖特 @AllArgsConstructor

    public class InputData<T> {
        T content;
        String fileName;
        String bucketName;
        String transactionId;
        Map<String, String> metaData;
    }`

你可以帮忙为 uploadFile 方法编写 Junit 吗?

I have one method that uploads files to Amazon S3. I am trying to write JUnit for this method but get NullPointerException on the S3AsyncClient:

my class:

public class S3Client<T> {
    private static final Logger log = LoggerFactory.getLogger(S3Client.class);
    S3AsyncClient client;
    /**
     *
     * @param s3Configuration
     */
    public S3Client(AWSS3Configuration s3Configuration) {
        this.client = s3Configuration.getAsyncClient();
    }


    /**
     * Uploads a file s3 bucket and returns etag
     * @param uploadData
     * @return
     * @throws S3Exception
     */
    public CompletableFuture<String> uploadFile(S3UploadData<T> uploadData) throws S3Exception {
        int contentLength;
        AsyncRequestBody asyncRequestBody;

        if(uploadData.getContent() instanceof String) {
            String content = (String) uploadData.getContent();
            contentLength = content.length();
            asyncRequestBody = AsyncRequestBody.fromString(content);
        }
        else if(uploadData.getContent() instanceof byte[]){
            byte[] bytes = (byte[]) uploadData.getContent();
            contentLength = bytes.length;
            asyncRequestBody = AsyncRequestBody.fromBytes(bytes);
        }
        else{
            throw new IllegalArgumentException("Unsupported upload content type");
        }


        PutObjectRequest putObjRequest = PutObjectRequest.builder()
                .bucket(uploadData.getBucketName())
                .key(uploadData.getFileName())
                .metadata(uploadData.getMetaData())
                .contentLength((long) contentLength).build();


        CompletableFuture<String> response = client.putObject(putObjRequest, asyncRequestBody).thenApply(
                getPutObjectResponse -> {
                    log.info("Got response from S3 upload={}", getPutObjectResponse.eTag());
                    return getPutObjectResponse.eTag();
                });
        response.exceptionally(throwable -> {
            log.error("Exception occurred while uploading a file intuit_tid={} file={}",uploadData.getTransactionId(),uploadData.getFileName());
            throw new S3Exception(throwable.getMessage());
        });
        return response;
    }

input for this class object of S3UploadData:
`
@Getter
@AllArgsConstructor

    public class InputData<T> {
        T content;
        String fileName;
        String bucketName;
        String transactionId;
        Map<String, String> metaData;
    }`

can u help please with writing Junit for uploadFile method?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

茶底世界 2025-01-25 21:58:41

您没有 JUNIT 测试代码。您应该拥有使用 org.junit.jupiter.api 的代码。*

不要使用 MOCK,而是在 @TestInstanceS3 异步代码集成测试以确保其有效。例如,这是我在 IntelliJ 中的测试。

,我的测试通过了,并且我知道我的代码可以正常工作——这就是此 AWS 集成测试的重点。

如果我的代码因某种原因失败或引发异常,我的测试就会失败。例如,如果我传递了一个不存在的存储桶名称,我将得到:

在此处输入图像描述

这是我的 Java Amazon S3 异步代码:

package com.example.s3.async;

import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
// snippet-end:[s3.java2.async_ops.import]
// snippet-start:[s3.java2.async_ops.main]

/**
 * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials.
 *
 * For information, see this documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */

public class S3AsyncOps {

     public static void main(String[] args) {

         final String USAGE = "\n" +
                 "Usage:\n" +
                 "    S3AsyncOps <bucketName> <key> <path>\n\n" +
                 "Where:\n" +
                 "    bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" +
                 "    key - the name of the object (for example, book.pdf). \n" +
                 "    path - the local path to the file (for example, C:/AWS/book.pdf). \n";

         if (args.length != 3) {
             System.out.println(USAGE);
             System.exit(1);
         }

         String bucketName = args[0];
         String key = args[1];
         String path = args[2];

         Region region = Region.US_WEST_2;
         S3AsyncClient client = S3AsyncClient.builder()
                 .region(region)
                 .build();

         putObjectAsync(client, bucketName,  key, path);
     }

     public static void putObjectAsync(S3AsyncClient client,String bucketName,  String key, String path) {

        PutObjectRequest objectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        // Put the object into the bucket
        CompletableFuture<PutObjectResponse> future = client.putObject(objectRequest,
                AsyncRequestBody.fromFile(Paths.get(path))
        );
        future.whenComplete((resp, err) -> {
            try {
                if (resp != null) {
                    System.out.println("Object uploaded. Details: " + resp);
                } else {
                    // Handle error
                    err.printStackTrace();
                }
            } finally {
                // Only close the client when you are completely done with it
                client.close();
            }
        });

        future.join();
    }
}

现在进行测试,我想调用此代码,而不是模拟它。我在 IntelliJ 中设置了这样的测试,

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import software.amazon.awssdk.regions.Region;
import java.io.*;
import java.util.*;
import com.example.s3.async.*;
import software.amazon.awssdk.services.s3.S3AsyncClient;

@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AmazonS3AsyncTest {

    private static S3AsyncClient s3AsyncClient;

    // Define the data members required for the tests
    private static String bucketName = "";
    private static String objectKey = "";
    private static String objectPath = "";
    private static String toBucket = "";



    @BeforeAll
    public static void setUp() throws IOException {

        // Run tests on Real AWS Resources

        s3AsyncClient = S3AsyncClient.builder()
                .region(Region.US_EAST_1)
                .build();


        try (InputStream input = AmazonS3Test.class.getClassLoader().getResourceAsStream("config.properties")) {

            Properties prop = new Properties();

            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }

            //load a properties file from class path, inside static method
            prop.load(input);

            // Populate the data members required for all tests
            bucketName = prop.getProperty("bucketName");
            objectKey = prop.getProperty("objectKey");
            objectPath= prop.getProperty("objectPath");
            toBucket = prop.getProperty("toBucket");


        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Test
    @Order(1)
    public void whenInitializingAWSS3Service_thenNotNull() {
        assertNotNull(s3AsyncClient);
        System.out.println("Test 1 passed");
    }

    @Test
    @Order(2)
    public void putObject() {

        S3AsyncOps.putObjectAsync(s3AsyncClient, bucketName,  objectKey, objectPath);
        System.out.println("Test 2 passed");
    }

}

You have no JUNIT test code. You should have code that uses org.junit.jupiter.api.*

Instead of using a MOCK, call the actual S3 Async code in a @TestInstance integration test to make sure it works. For example, here is my test in IntelliJ.

enter image description here

As you can see, my test passed and I Know my code works -- which is the point of this AWS integration test.

If my code failed or threw an exception for some reason, my test would fail. For example, if I passed a bucket name that does not exist, I would get:

enter image description here

Here is my Java Amazon S3 Async code:

package com.example.s3.async;

import software.amazon.awssdk.core.async.AsyncRequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.services.s3.model.PutObjectResponse;
import java.nio.file.Paths;
import java.util.concurrent.CompletableFuture;
// snippet-end:[s3.java2.async_ops.import]
// snippet-start:[s3.java2.async_ops.main]

/**
 * To run this AWS code example, ensure that you have setup your development environment, including your AWS credentials.
 *
 * For information, see this documentation topic:
 *
 * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
 */

public class S3AsyncOps {

     public static void main(String[] args) {

         final String USAGE = "\n" +
                 "Usage:\n" +
                 "    S3AsyncOps <bucketName> <key> <path>\n\n" +
                 "Where:\n" +
                 "    bucketName - the name of the Amazon S3 bucket (for example, bucket1). \n\n" +
                 "    key - the name of the object (for example, book.pdf). \n" +
                 "    path - the local path to the file (for example, C:/AWS/book.pdf). \n";

         if (args.length != 3) {
             System.out.println(USAGE);
             System.exit(1);
         }

         String bucketName = args[0];
         String key = args[1];
         String path = args[2];

         Region region = Region.US_WEST_2;
         S3AsyncClient client = S3AsyncClient.builder()
                 .region(region)
                 .build();

         putObjectAsync(client, bucketName,  key, path);
     }

     public static void putObjectAsync(S3AsyncClient client,String bucketName,  String key, String path) {

        PutObjectRequest objectRequest = PutObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();

        // Put the object into the bucket
        CompletableFuture<PutObjectResponse> future = client.putObject(objectRequest,
                AsyncRequestBody.fromFile(Paths.get(path))
        );
        future.whenComplete((resp, err) -> {
            try {
                if (resp != null) {
                    System.out.println("Object uploaded. Details: " + resp);
                } else {
                    // Handle error
                    err.printStackTrace();
                }
            } finally {
                // Only close the client when you are completely done with it
                client.close();
            }
        });

        future.join();
    }
}

Now for my test, i want to call this code, not MOCK it. I have setup my test in IntelliJ like this,

import org.junit.jupiter.api.*;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import software.amazon.awssdk.regions.Region;
import java.io.*;
import java.util.*;
import com.example.s3.async.*;
import software.amazon.awssdk.services.s3.S3AsyncClient;

@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class AmazonS3AsyncTest {

    private static S3AsyncClient s3AsyncClient;

    // Define the data members required for the tests
    private static String bucketName = "";
    private static String objectKey = "";
    private static String objectPath = "";
    private static String toBucket = "";



    @BeforeAll
    public static void setUp() throws IOException {

        // Run tests on Real AWS Resources

        s3AsyncClient = S3AsyncClient.builder()
                .region(Region.US_EAST_1)
                .build();


        try (InputStream input = AmazonS3Test.class.getClassLoader().getResourceAsStream("config.properties")) {

            Properties prop = new Properties();

            if (input == null) {
                System.out.println("Sorry, unable to find config.properties");
                return;
            }

            //load a properties file from class path, inside static method
            prop.load(input);

            // Populate the data members required for all tests
            bucketName = prop.getProperty("bucketName");
            objectKey = prop.getProperty("objectKey");
            objectPath= prop.getProperty("objectPath");
            toBucket = prop.getProperty("toBucket");


        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

    @Test
    @Order(1)
    public void whenInitializingAWSS3Service_thenNotNull() {
        assertNotNull(s3AsyncClient);
        System.out.println("Test 1 passed");
    }

    @Test
    @Order(2)
    public void putObject() {

        S3AsyncOps.putObjectAsync(s3AsyncClient, bucketName,  objectKey, objectPath);
        System.out.println("Test 2 passed");
    }

}
那一片橙海, 2025-01-25 21:58:41

您可以使用Mockito模拟S3ASYNCCLIENT操作。

@Mock
private S3AsyncClient s3AsyncClient;

以下是我上传文件实现的单元测试用例。它肯定会给您洞悉它的完成方式,并且可以完成。

@Nested
  class UploadFile {
    @Captor
    ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor;
    @Captor
    ArgumentCaptor<AsyncRequestBody> requestBodyCaptor;

    @Test
    void testSuccessfulUpload() {
      Flux<ByteBuffer> body = Flux.just();
      var expectedResponse = PutObjectResponse.builder().build();
      when(s3AsyncClient.putObject(putObjectRequestCaptor.capture(), requestBodyCaptor.capture()))              .thenReturn(CompletableFuture.completedFuture(expectedResponse));

      fileUploadService.upload("TEST_PREFIX", "test.zip", body);
      assertThat(putObjectRequestCaptor.getValue().bucket()).isEqualTo(TEST_BUCKET);
      assertThat(putObjectRequestCaptor.getValue().key()).isEqualTo("TEST_PREFIX/test.zip");

      assertThat(requestBodyCaptor.getValue()).isNotNull();
    }
  } 

You could use Mockito to mock the S3AsyncClient operations.

@Mock
private S3AsyncClient s3AsyncClient;

Below is the unit test case for my upload file implementation. It will surely give you insights how it is done and it can be done.

@Nested
  class UploadFile {
    @Captor
    ArgumentCaptor<PutObjectRequest> putObjectRequestCaptor;
    @Captor
    ArgumentCaptor<AsyncRequestBody> requestBodyCaptor;

    @Test
    void testSuccessfulUpload() {
      Flux<ByteBuffer> body = Flux.just();
      var expectedResponse = PutObjectResponse.builder().build();
      when(s3AsyncClient.putObject(putObjectRequestCaptor.capture(), requestBodyCaptor.capture()))              .thenReturn(CompletableFuture.completedFuture(expectedResponse));

      fileUploadService.upload("TEST_PREFIX", "test.zip", body);
      assertThat(putObjectRequestCaptor.getValue().bucket()).isEqualTo(TEST_BUCKET);
      assertThat(putObjectRequestCaptor.getValue().key()).isEqualTo("TEST_PREFIX/test.zip");

      assertThat(requestBodyCaptor.getValue()).isNotNull();
    }
  } 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文