用 Microsoft Fakes 隔离测试代码

Microsoft 伪造品帮助您隔离通过替换应用程序的其他部分测试通过 存根 或 填充的代码。这些是受您的控件测试代码的小部分。通过隔离正在测试的代码,您知道,如果测试失败,原因代码并不其他位置。存根和填充还允许测试代码,即使应用程序的其他部分不起作用。

伪造品包括分为两个相似:

  • 存根 包含实现同一接口的小的备用项替换选件类。若要使用存根,则必须设计您的应用程序,以便每个元素仅依赖于接口,而未在其他元素。(通过“元素”我们是指设计和一起更新和在该程序集通常包含。) 选件类的选件类或组

  • 上述 修改应用程序的编译代码运行时,以便而不是让一个指定的方法调用,它运行测试提供的填充代码。填充可用于替换对您无法修改的程序集,以致 .NET 程序集。

Fakes 将替换其他组件

要求

  • Visual Studio 旗舰版

选择在存根和填充类型之间

通常,因为您同时,开发和更新这些选件类将视为一个 Visual Studio 项目元素。应考虑使用存根,并填充对该项目对您的解决方案中的其他项目,或者到项目引用的其他程序集。

作为泛型教程,请使用存根为您的 Visual Studio 解决方案中调用,并且,填充为调入其他引用的程序集。这是因为,在您的解决方案中最好通过定义接口组件分离方式与碰需要的。但是,外部程序集 (如 System.dll 通常不提供单独的接口定义,因此,您必须使用填充。

其他注意事项是:

**性能。**因为它们重写代码运行时,上述运行更慢。存根没有此性能开销并尽可能快,象虚方法可以是。

**静态方法,密封类型。**只能使用存根实现接口。因此,存根类型不能为静态方法,非虚方法,密封虚方法,在密封类型上的方法,依此类推。

**内部类型。**存根和填充可用于使访问使用程序集特性 InternalsVisibleToAttribute的内部类型。

**私有方法。**如果方法签名的所有类型都是可见的,填充码会替换调用私有方法。存根只能替换可见方法。

**接口和抽象方法。**存根提供可用于测试接口和抽象方法的实现。因为它们没有方法体,填充码无法检测接口和抽象方法。

通常,我们建议您使用存根类型与您的基本代码中的依赖项隔离。可以通过隐藏接口后的元素执行此操作。填充类型都可用于与不提供可测试的 API 的第三方组件隔离。

开始使用存根

  1. 插入接口

    若要使用存根,必须编写要测试的代码,因此它不显式指定在应用程序另一个元素的选件类。由“元素”我们意味着选件类或选件类一起开发和更新和在 Visual Studio 项目通常包含。应声明变量和参数使用接口使用工厂,并且,应通过或创建实例。例如,因此,如果 StockFeed 是在应用程序的另一个元素的选件类,则要视为错误:

    return (new StockFeed()).GetSharePrice("COOO"); // Bad

    相反,请定义可由另一个组件实现,这样,并且可以通过存根仅为测试目的还实现的接口:

    public int GetContosoPrice(IStockFeed feed)
    { return feed.GetSharePrice("COOO"); }
    
    Public Function GetContosoPrice(feed As IStockFeed) As Integer
     Return feed.GetSharePrice("COOO")
    End Function
    
  2. 添加 Fakes 程序集

    1. 在解决方案资源管理器中,展开测试项目的引用列表。如果使用的是 Visual Basic,必须选择 显示所有文件 才能看到引用列表中。

    2. 选择对接口的程序集 (例如 IStockFeed) 中定义。在快捷菜单的引用,选择 添加 Fakes 程序集

    3. 重新生成解决方案。

  3. 在测试,构造一个实例存根并为其方法提供代码:

    [TestClass]
    class TestStockAnalyzer
    {
        [TestMethod]
        public void TestContosoStockPrice()
        {
          // Arrange:
    
            // Create the fake stockFeed:
            IStockFeed stockFeed = 
                 new StockAnalysis.Fakes.StubIStockFeed() // Generated by Fakes.
                     {
                         // Define each method:
                         // Name is original name + parameter types:
                         GetSharePriceString = (company) => { return 1234; }
                     };
    
            // In the completed application, stockFeed would be a real one:
            var componentUnderTest = new StockAnalyzer(stockFeed);
    
          // Act:
            int actualValue = componentUnderTest.GetContosoPrice();
    
          // Assert:
            Assert.AreEqual(1234, actualValue);
        }
        ...
    }
    
    <TestClass()> _
    Class TestStockAnalyzer
    
        <TestMethod()> _
        Public Sub TestContosoStockPrice()
            ' Arrange:
            ' Create the fake stockFeed:
            Dim stockFeed As New StockAnalysis.Fakes.StubIStockFeed
            With stockFeed
                .GetSharePriceString = Function(company)
                                           Return 1234
                                       End Function
            End With
            ' In the completed application, stockFeed would be a real one:
            Dim componentUnderTest As New StockAnalyzer(stockFeed)
            ' Act:
            Dim actualValue As Integer = componentUnderTest.GetContosoPrice
            ' Assert:
            Assert.AreEqual(1234, actualValue)
        End Sub
    End Class
    

    此处魔术特定部分是选件类 StubIStockFeed。对所引用的程序集中的每个接口,Microsoft 伪造品 framework 生成存根选件类。存根选件类的名称是从派生接口的名称,与“Fakes.Stub”作为标题和参数类型追加的名称。

    存根还会生成用于属性的 getter 和 setter,为事件和对泛型方法。有关更多信息,请参见使用存根针对单元测试隔离应用程序的各个部分

以填充

假定您的组件包含对的 DateTime.Now:

// Code under test:
    public int GetTheCurrentYear()
    {
       return DateTime.Now.Year;
    }

在测试过程中,因为实际版本不方便地返回一个值在每次调用,您希望填 Now 属性。

若要使用填充,您不必修改应用程序代码或编写为特定方法。

  1. 添加 Fakes 程序集

    在解决方案资源管理器中,打开您的单元测试项目的引用并选择对包含方法要集的程序集。在此示例中,DateTime 选件类在 System.dll。若要查看 Visual Basic 项目引用,选择 显示所有文件

    选择 添加 Fakes 程序集

  2. 插入 shim 在 ShimsContext

    [TestClass]
    public class TestClass1
    { 
            [TestMethod]
            public void TestCurrentYear()
            {
                int fixedYear = 2000;
    
                // Shims can be used only in a ShimsContext:
                using (ShimsContext.Create())
                {
                  // Arrange:
                    // Shim DateTime.Now to return a fixed date:
                    System.Fakes.ShimDateTime.NowGet = 
                    () =>
                    { return new DateTime(fixedYear, 1, 1); };
    
                    // Instantiate the component under test:
                    var componentUnderTest = new MyComponent();
    
                  // Act:
                    int year = componentUnderTest.GetTheCurrentYear();
    
                  // Assert: 
                    // This will always be true if the component is working:
                    Assert.AreEqual(fixedYear, year);
                }
            }
    }
    
    <TestClass()> _
    Public Class TestClass1
        <TestMethod()> _
        Public Sub TestCurrentYear()
            Using s = Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()
                Dim fixedYear As Integer = 2000
                ' Arrange:
                ' Detour DateTime.Now to return a fixed date:
                System.Fakes.ShimDateTime.NowGet = _
                    Function() As DateTime
                        Return New DateTime(fixedYear, 1, 1)
                    End Function
    
                ' Instantiate the component under test:
                Dim componentUnderTest = New MyComponent()
                ' Act:
                Dim year As Integer = componentUnderTest.GetTheCurrentYear
                ' Assert: 
                ' This will always be true if the component is working:
                Assert.AreEqual(fixedYear, year)
            End Using
        End Sub
    End Class
    

    上述类名通过对基元类型名称的 Fakes.Shim 前缀组成。参数名追加到方法的名称。

前面的示例为静态方法使用一个填充。为实例方法使用在类型名称之间的填充,编写 AllInstances 和方法名称:

System.IO.Fakes.ShimFile.AllInstances.ReadToEnd = ...

还可以创建填充特定实例,则构造函数的和属性。有关更多信息,请参见使用填充码针对单元测试将应用程序与程序集隔离

本节内容

使用存根针对单元测试隔离应用程序的各个部分

使用填充码针对单元测试将应用程序与程序集隔离

Microsoft Fakes 中的代码生成、编译和命名约定