单元测试使用外部dll的方法

shl*_*chz 3 c# unit-testing moq mocking azure-storage-blobs

我有一个名为A的项目,它有一个名为ClassA的类. ClassA有一个名为ReadBlock()的方法,它创建一个CloudBlockBlob对象并调用其中一个方法.

CloudBlockBlob是一个位于Microsoft.WindowsAzure.Szrage.Blob命名空间的类,该命名空间位于Microsoft.WindowsAzure.Storage.dll中.

我的项目A有一个名为A.Tests的单元测试项目.现在,我想测试方法ReadBlock().为了测试它,我需要模拟CloudBlockBlob对象并拦截对其方法的调用,返回自定义值并验证方法是否被调用.

  • 如何模拟在方法内完全创建的对象?
  • 我可以以某种方式更改项目A的DLL引用并将其引用到创建模拟对象而不是真实对象的模拟dll吗?
  • 我可以在A.Tests类中使用我自己的实现覆盖项目AMicrosoft.WindowsAzure.Storage.Blob中的类的调用吗?

更新: 问题是我是否可以在不修改项目A的代码的情况下完成此操作.

谢谢!

Old*_*Fox 5

如果不修改类A代码,您将无法ReadBlock使用Moq 来修改该方法.您将能够使用代码编织工具(MsFakes,Typemock隔离器等)来使用此方法.

例如(MsFakes):

[TestMethod]
public void TestMethod1()
{
    using (ShimsContext.Create())
    {
        ShimCloudBlockBlob.AllInstances.<the method you want to override>  = (<the method arguments>) => {};
    }
}
Run Code Online (Sandbox Code Playgroud)

using范围内,您将能够通过属性覆盖CloudBlockBlob具有的任何方法AllInstances.

在下一节中,我将讨论您拥有的所有其他选项......

选项1:

    public class A
    {
        private IBlockBlob _blockBlob;

        public A(IBlockBlob blockBlob)
        {
            _blockBlob = blockBlob;
        }

        public void ReadBlock()
        {
            _blockBlob.DoSomething();
        }
    }
Run Code Online (Sandbox Code Playgroud)

由于您每次调用时创建一个新实例ReadBlock(您的方法的当前行为),您最好注入工厂而不是包装器,DoSomething应该是create; 选项2:

    public class A
    {
        private readonly IFactoryBlockBlob _blobFctory;

        public A(IFactoryBlockBlob blobFctory)
        {
            _blobFctory = blobFctory;
        }

        public void ReadBlock()
        {
           var blob =  _blobFctory.Create();
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是,根据您的问题和您的评论,您的班级似乎"有依赖"而不是"需要依赖".

在此输入图像描述

(马克西门子写了一本关于DI的好书,这张图取自他的书)

有了这条新信息,您的方法应该是这样的; 选项3:

    public class A
    {
        public void ReadBlock(ICloudBlob blob)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

但是你不想改变方法的签名:

    public class A
    {

        public void ReadBlock()
        {
            ReadBlock(new CloudBlockBlob(<the params bla bla...>));
        }

        internal void ReadBlock(ICloudBlob blob)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)

单击添加InternalsVisibleToAttribute,然后验证内部方法的行为.

通过阅读这些内容,我觉得您的课程是一种"遗留代码",意味着它可以完成工作,不会改变,并且验证其行为可能是浪费时间.在过去,我发布了一个图表(在这个答案中),可以帮助您决定处理此案例的方法.