如何编写单元测试以将目录上传到S3?

huangapple go评论72阅读模式
英文:

How to write unit test upload directory to S3?

问题

我有一个将目录上传到S3的方法。
我想为它编写一个单元测试,我一直在搜索,但大多数测试都是集成测试。
也许我不应该为这种类型的流程编写单元测试?
我没有使用集成测试的特权,所以无法使用testcontainers。

以下是我的代码:

public void uploadDir(final Path path, final String key) throws InternalServerError {
    final TransferManager transferManager = TransferManagerBuilder.standard()
                                                                  .withS3Client(s3Client)
                                                                  .build();

    final ProgressListener progressListener = progressEvent -> {
        if (progressEvent.getBytesTransferred() > 0) {
            double percentTransferred = progressEvent.getBytesTransferred() * 100.0 / progressEvent.getBytes();
            log.info("Transferred " + percentTransferred + "%");
        }
    };

    final MultipleFileUpload xfer = transferManager.uploadDirectory("mybucket", key, path.toFile(), true);
    xfer.addProgressListener(progressListener);
    xfer.waitForCompletion();

    log.info("Upload has been completed.");
    } catch (final AmazonServiceException | InterruptedException exception) {
    
        ... 在此处执行某些操作
    } finally {
        transferManager.shutdownNow();
    }
}
英文:

I have a method to upload directory to s3.
I would like to write a unit test for it and I've been searching, but most test are integration tests.
Maybe I'm not supposed to do a unit test for this kind of process?
I don't have a privileges to use testcontainers for integration test, so I can’t use testcontainers.

Here is my code

public void uploadDir(final Path path, final String key) throws InternalServerError {
        final TransferManager transferManager = TransferManagerBuilder.standard()
                                                                      .withS3Client(s3Client)
                                                                      .build();
       

            final ProgressListener progressListener = progressEvent -> {
                if (progressEvent.getBytesTransferred() > 0) {
                    double percentTransferred = progressEvent.getBytesTransferred() * 100.0 / progressEvent.getBytes();
                    log.info("Transferred " + percentTransferred + "%");
                }
            };

            final MultipleFileUpload xfer = transferManager.uploadDirectory("mybucket", key, path.toFile(), true);
            xfer.addProgressListener(progressListener);
            xfer.waitForCompletion();
            
           log.info("Upload has been completed.");
        } catch (final AmazonServiceException | InterruptedException exception) {
            
            ... do something here
        } finally {
            transferManager.shutdownNow();
        }
    } 

答案1

得分: 2

以下是翻译好的内容:

似乎方法中没有太多单元测试的内容,只涉及参数和交互。

模拟TransferManager并不是一个真正的解决方案,因为你需要模拟MultipleFileUpload,而且调用ProgressListener的代码也需要添加。最终你会模拟所有东西,这使得单元测试失去了意义。对于一个广泛使用的库进行测试对你来说也没有太多价值。

我会测试异常情况,这是在集成测试中不太可能发生的情况(即不可重复的)。大致上是这样的(假设使用Mockito):

@Test
void uploadDirFailsTest() {
  TransferManager mockTM = mock(TransferManager.class);

  doThrow(new AmazonServiceException(...)) // 希望它有一个公共构造函数
       .when(mockTM)
       .uploadDirectory(eq("mybucket"), any(), any(), eq(true)); // 如果需要更多匹配的话
  
  YourClassName instance = new YourClassName(mockTM);

  instance.uploadDir(path, key);
  
  /*
  在这里验证正确的异常处理,或者如果重新抛出异常,则在调用周围包装为 assertThrows()
  */
}
public class YourClassName {
final TransferManager transferManager;

public YourClassName(TransferManager transferManager) {
  this.transferManager = transferManager;
}

public void uploadDir(final Path path, final String key) throws InternalServerError {
            final ProgressListener progressListener = progressEvent -> {
                if (progressEvent.getBytesTransferred() > 0) {
                    double percentTransferred = progressEvent.getBytesTransferred() * 100.0 / progressEvent.getBytes();
                    log.info("已传输 " + percentTransferred + "%");
                }
            };

            final MultipleFileUpload xfer = transferManager.uploadDirectory("mybucket", key, path.toFile(), true);
            xfer.addProgressListener(progressListener);
            xfer.waitForCompletion();
            
            log.info("上传已完成。");
        } catch (final AmazonServiceException | InterruptedException exception) {
            
            ... 在这里进行处理
        } finally {
            transferManager.shutdownNow();
        }
    } 
// 实际使用
new YourClassName(
    TransferManagerBuilder.standard() 
        .withS3Client(s3Client)
        .build()
);
英文:

It seems there's not much to unit test in the method but arguments and interactions.
Mocking TransferManager isn't really a solution because you'd need to mock MultipleFileUpload, and also the code that calls ProgressListener needs to be added. You'd end up mocking everything which makes it useless. Testing a widely used library also has not much value for you.

I'd test the exception case which is an unlikely case to happen (aka not repeatable) during integration testing.
Roughly something like this (assuming mockito):

@Test
void uploadDirFailsTest() {
  TransferManager mockTM = mock(TransferManager.class);

  doThrow(new AmazonServiceException(...)) // hopefully it has a public constructor
       .when(mockTM)
       .uploadDirectory(eq("mybucket"), any(), any(), eq(true)); //more matching if needed
  
  YourClassName instance = new YourClassName(mockTM);

  instance.uploadDir(path, key);
  
/*
verify correct exception handling here or
if you rethrow the exception wrap the call with
assertThrows()
*/

}


public class YourClassName {
final TransferManager transferManager;

public YourClassName(TransferManager transferManager) {
  this.transferManager = transferManager;
}

public void uploadDir(final Path path, final String key) throws InternalServerError {
            final ProgressListener progressListener = progressEvent -> {
                if (progressEvent.getBytesTransferred() > 0) {
                    double percentTransferred = progressEvent.getBytesTransferred() * 100.0 / progressEvent.getBytes();
                    log.info("Transferred " + percentTransferred + "%");
                }
            };

            final MultipleFileUpload xfer = transferManager.uploadDirectory("mybucket", key, path.toFile(), true);
            xfer.addProgressListener(progressListener);
            xfer.waitForCompletion();
            
           log.info("Upload has been completed.");
        } catch (final AmazonServiceException | InterruptedException exception) {
            
            ... do something here
        } finally {
            transferManager.shutdownNow();
        }
    } 
//real use
new YourClassName(
    TransferManagerBuilder.standard() 
        .withS3Client(s3Client)
        .build()
);

huangapple
  • 本文由 发表于 2020年8月27日 06:57:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/63606832.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定