代码之家  ›  专栏  ›  技术社区  ›  Chris F Carroll

如何模拟Amazon S3客户端。净单元测试

  •  9
  • Chris F Carroll  · 技术社区  · 6 年前

    我注意到 AmazonS3Client 事实上的 ,所以 Mock<AmazonS3Client> 应该很容易。但是

    new Mock<AmazonS3Client>()
    

    使用Moq时,我发现一个错误,说没有有效的 RegionEndpoint

    因此,显然还需要一点。

    2 回复  |  直到 6 年前
        1
  •  21
  •   Chris F Carroll    6 年前

    与其将代码与实现问题紧密耦合,不如注意 AmazonS3Client 类实现 IAmazonS3 (v2、v3)或 AmazonS3 (v1)接口符合参考的AWS SDK。NET文档。

    public class AmazonS3Client : IAmazonS3, IDisposable {
        //...
    }
    

    我建议您让您的代码依赖于抽象( 界面 )而不是在实施上( )。

    public class MyClass {
        private readonly IAmazonS3 client;
    
        public MyClass(IAmazonS3 client) {
            this.client = client;
        }
    
        //...
    }
    

    这样,在隔离测试时,在用mock交换依赖关系时,就可以有更大的灵活性。

    您已经体验到需要添加依赖项来模拟 亚马逊3客户 如果将接口用作依赖项,则可以避免这种情况。

    s3ClientMock = new Mock<IAmazonS3>();
    

    这个 Setup 可以像您在回答中所演示的那样,正常地完成模拟界面的操作。

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

        2
  •  12
  •   Chris F Carroll    3 年前

    使用 Moq ,添加这些构造函数参数似乎可以正常工作:

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

    然后我可以正常设置:

    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;
    }
    

    但作为 Nkosi 指出,我不需要构造函数;我只是忽视了 IAmazonS3 界面