如何 mock/unit 测试来自 amazon s3 的下载?
how to mock/unit test downloads from amazon s3?
我是单元 testing/moq 的新手,想知道如何做到这一点。我有一个将文件从 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();
}
根据 documentation,TransferUtility
class 实现了 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 没有 return 任何你需要做的就是在快乐路径的情况下设置可验证性
[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
的 class
- 我用了一个名字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
returns false
我是单元 testing/moq 的新手,想知道如何做到这一点。我有一个将文件从 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();
}
根据 documentation,TransferUtility
class 实现了 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 没有 return 任何你需要做的就是在快乐路径的情况下设置可验证性
[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
的 class
- 我用了一个名字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
returnsfalse
- 我假设在异常情况下