如何模拟Amazon S3 Client进行.NET单元测试

Chr*_*oll 4 .net c# unit-testing moq amazon-s3

我注意到重要成员AmazonS3Client虚拟的,所以Mock<AmazonS3Client>应该很容易.但

new Mock<AmazonS3Client>()
Run Code Online (Sandbox Code Playgroud)

使用Moq,给我一个错误,说没有效果RegionEndpoint.

显然需要更多一点.

Nko*_*osi 9

不要将代码紧密地耦合到实现问题,而是根据引用的AWS SDK for .NET文档注意AmazonS3Client类实现IAmazonS3(v2,v3)或AmazonS3(v1)接口.

public class AmazonS3Client : IAmazonS3, IDisposable {
    //...
}
Run Code Online (Sandbox Code Playgroud)

我建议你的代码依赖于抽象(接口)而不是实现().

public class MyClass {
    private readonly IAmazonS3 client;

    public MyClass(IAmazonS3 client) {
        this.client = client;
    }

    //...
}
Run Code Online (Sandbox Code Playgroud)

在隔离测试时,这样可以在与mocks交换依赖关系时提供更大的灵活性.

您已经体验过,AmazonS3Client如果将接口用作依赖项,则可以避免模拟实现所需的附加依赖项.

s3ClientMock = new Mock<IAmazonS3>();
Run Code Online (Sandbox Code Playgroud)

模拟Setup界面可以像你通常在答案中所说的那样完成.

在生产中,可以将正确配置的实现注入到依赖类中.

  • @ChrisFCarroll这是一个有效的观点.它允许您的API不易受亚马逊对其SDK所做的更改的影响.正如更新所证明的那样,您必须考虑我的答案才能考虑新的SDK版本. (2认同)

Chr*_*oll 5

使用Moq,添加这些构造函数args似乎可以:

s3ClientMock= new Mock<AmazonS3Client>(
    FallbackCredentialsFactory.GetCredentials(true), 
    new AmazonS3Config{RegionEndpoint = RegionEndpoint.EUWest1});
Run Code Online (Sandbox Code Playgroud)

然后我可以正常设置

Stream GivenDocInS3Bucket(string pathToTestDoc)
{
  var docStream = new FileInfo(pathToTestDoc).OpenRead();

  s3ClientMock
    .Setup(x => x.GetObjectAsync(
       It.IsAny<string>(), 
       It.IsAny<string>(), 
       It.IsAny<CancellationToken>()))
    .ReturnsAsync(
       (string bucket, string key, CancellationToken ct) =>
         new GetObjectResponse
         {
           BucketName = bucket,
           Key = key,
           HttpStatusCode = HttpStatusCode.OK,
           ResponseStream = docStream,
         });

  return docStream;
}
Run Code Online (Sandbox Code Playgroud)