【问题标题】:how to mock/unit test downloads from amazon s3?如何从 amazon s3 模拟/单元测试下载?
【发布时间】:2021-09-29 03:28:02
【问题描述】:

我是单元测试/起订量的新手,想知道如何做到这一点。我有一个将文件从 s3 下载到本地的功能。我如何模拟它,使其实际上不使用 transferUtility 从 s3 下载任何内容?

bool downloadFileFromS3(string localPathToSave, string filenameToDownloadAs, string bucketName, string objectKey)
{
    try
    {
        string accessKey = "xxx";
        string secretKey = "xxx";
        // do stuff before
        TransferUtility transferUtility = new TransferUtility(accessKey, secretKey);
        transferUtility.Download( Path.Combine(localPathToSave, filenameToDownloadAs), bucketName, objectKey );
        // do stuff after
        return true;
    }

    catch (Exception e)
    {
        // stuff
    }
}

我已经创建了模拟,但我不知道如何使用它来测试我编写的函数。

[Test]
public void testDownloadFromS3()
{
    string filePath = null;
    string bucketName = null;
    string key = null;

    Mock<Amazon.S3.Transfer.TransferUtility> mock = new Mock<Amazon.S3.Transfer.TransferUtility>();
    //mock.Setup(x => x.Download(filePath, bucketName, key)).Verifiable();
    //Mock.Verify();
}

【问题讨论】:

    标签: c# unit-testing amazon-s3 moq awss3transferutility


    【解决方案1】:

    根据documentationTransferUtility类实现ITransferUtility接口。

    如果您需要测试您的downloadFileFromS3,那么您的代码应该依赖于抽象,而不是像SOLID's DIP 所说的具体化。

    private readonly ITransferUtility transferUtility; //should be set via constructor injection
    
    bool downloadFileFromS3(string localPathToSave, string filenameToDownloadAs, string bucketName, string objectKey)
    {
        try
        {
            // do stuff before
    
            transferUtility.Download( Path.Combine(localPathToSave, filenameToDownloadAs), bucketName, objectKey );
    
            // do stuff after
            return true;
        }
    
        catch (Exception e)
        {
            // stuff
        }
    }
    

    因为Download method 不会返回任何内容,您只需设置可验证性,以防出现快乐路径

    [Test]
    public void testDownloadFromS3_HappyPath()
    {
        //Arrange
        const string localPathToSave = "C:/tmp/";
        const string filenameToDownloadAs = "test.txt";
        const string bucketName = "x";
        const string objectKey = "y";
    
        Mock<Amazon.S3.Transfer.ITransferUtility> transferUtilMock = new Mock<Amazon.S3.Transfer.ITransferUtility>();
        transferUtilMock
            .Setup(util => util.Download(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
            .Verifiable();
    
        var sut = new ClassThatContainsTheDownloadFileFromS3(transferUtilMock.Object);
    
        //Act
        var result = sut.downloadFileFromS3(localPathToSave, filenameToDownloadAs, bucketName, objectKey);
    
        //Assert
        Assert.IsTrue(result);
        transferUtilMock.Verify(util => util.Download(
                It.Is<string>(filePath => string.Equals(filePath, localPathToSave +filenameToDownloadAs, StringComparison.InvariantCultureIgnoreCase)),
                It.Is<string>(bucket => string.Equals(bucket, bucketName, StringComparison.InvariantCultureIgnoreCase)),
                It.Is<string>(key => string.Equals(key, objectKey, StringComparison.InvariantCultureIgnoreCase)),
            Times.Once);
    }
    
    • 我们已将模拟设置为接受任何参数 (It.IsAny)
    • 我们已将模拟实例的Object 属性传递给包含downloadFileFromS3 的类
    • 我使用了一个名字sut,它指的是System Under Test
    • 我们使用It.Is 来验证Download 方法是否已按我们预期的方式调用
    • 我们还将pass 和Times.Once 发送到Verify,以确保Download 已被准确调用一次。

    这是您可以测试不愉快路径的方法:

    [Test]
    public void testDownloadFromS3_UnhappyPath()
    {
        //Arrange
        const string localPathToSave = "C:/tmp/";
        const string filenameToDownloadAs = "test.txt";
        const string bucketName = "x";
        const string objectKey = "y";
    
        Mock<Amazon.S3.Transfer.ITransferUtility> transferUtilMock = new Mock<Amazon.S3.Transfer.ITransferUtility>();
        transferUtilMock
            .Setup(util => util.Download(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>()))
            .Throws<System.IO.IOException>();;
    
        var sut = new ClassThatContainsTheDownloadFileFromS3(transferUtilMock.Object);
    
        //Act
        var result = sut.downloadFileFromS3(localPathToSave, filenameToDownloadAs, bucketName, objectKey);
    
        //Assert
        Assert.IsFalse(result);
        transferUtilMock.Verify(util => util.Download(
                It.Is<string>(filePath => string.Equals(filePath, localPathToSave +filenameToDownloadAs, StringComparison.InvariantCultureIgnoreCase)),
                It.Is<string>(bucket => string.Equals(bucket, bucketName, StringComparison.InvariantCultureIgnoreCase)),
                It.Is<string>(key => string.Equals(key, objectKey, StringComparison.InvariantCultureIgnoreCase)),
            Times.Once);
    }
    
    • 如您所见,我们已将 Verifiable 调用替换为 Throws,以便在调用时抛出异常
    • 我还将Assert.IsTrue 替换为Assert.IsFalse
      • 我假设在异常情况下// stuff 返回false

    【讨论】:

    • 只是好奇,注入 IAmazonS3 是否也注入了 ITransferUtility 还是必须在配置服务时显式添加?
    • @NickCipollina 我认为如果你需要两个都应该注入
    猜你喜欢
    • 2018-09-07
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2015-06-19
    • 2018-11-24
    相关资源
    最近更新 更多