用 Microsoft Fakes 隔离测试代码

Microsoft Fakes 通过将应用程序的其余部分替换为存根 或填充码 来帮助隔离正在测试的代码。 这些是受你的测试控制的小段代码。 通过隔离接受测试的代码,你将会知道,如果测试失败,原因就在这里而不是其他地方。 即使应用程序的其他部分不起作用,存根和填充码也能让你测试代码。

Fakes 有两种风格:

  • 存根将一个类替换为一个小的、实现同一接口的替代项。 若要使用存根,你在设计应用程序时必须让每个组件仅依赖接口,而不依赖其他组件。 ("组件"是指一个类或一起开发和更新的一组类,通常包含在一个程序集中。)
  • 填充码在运行时修改应用程序的已编译代码,以便让它运行你的测试提供的填充代码,而不是进行指定的方法调用。 填充码可用于替换对你无法修改的程序集(如 .NET 程序集)的调用。

要求

  • Visual Studio 旗舰版或高级专业版

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

通常,你将 Visual Studio 项目视为一个组件,这是因为你同时开发和更新这些类。 对于该项目对你的解决方案中的其他项目所作的调用或对该项目引用的其他程序集所作的调用,应考虑使用存根和填充码。

一般原则是,为在 Visual Studio 解决方案中进行的调用使用存根,并为对其他引用的程序集的调用使用填充码。 这是因为在你自己的解决方案中,通过按照存根要求的方式定义接口来分离组件是一个很好的做法。 但是,外部程序集(如 System.dll)通常没有单独的接口定义,因此你必须改用填充码。

其他需要注意的事项还有:

性能。填充码运行较慢,因为它们在运行时会重新编写你的代码。 存根没有这项性能开销,与虚方法运行的速度一样快。

静态方法,密封类型。你只能使用存根实现接口。 因此,存根类型不能用于静态方法、非虚方法、密封虚方法、密封类型中的方法,等等。

内部类型。存根和填充码都可用于可通过程序集特性 InternalsVisibleToAttribute 访问的内部类型。

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

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

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

开始使用存根

(有关更多详细说明,请参见使用存根针对单元测试隔离应用程序的各个部分。)

  1. 注入接口

    若要使用存根,你在编写要测试的代码时不应明确提及应用程序的其他组件中的类。 "组件"是指一个类或一起开发和更新的多个类,通常包含在一个 Visual Studio 项目中。 应使用接口来声明变量和参数,并且应使用工厂来传入或创建其他组件的实例。 例如,如果 StockFeed 是应用程序的另一个组件中的类,则可以认为以下内容是错误的:

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

    相反,应该定义可由另一个组件实现的接口以及可由存根出于测试目实现的接口:

    1 public int GetContosoPrice(IStockFeed feed)
    2 {
    3     return feed.GetSharePrice("COOO");
    4 } 
  2. 添加 Fakes 程序集
    1. 在"解决方案资源管理器"中,展开测试项目的引用列表。 如果你正在使用 Visual Basic,则必须选择"显示所有文件"才能看到引用列表。
    2. 选择对其中定义了接口(例如 IStockFeed)的程序集的引用。 在此引用的快捷菜单上,选择"添加 Fakes 程序集"。
    3. 重新生成解决方案。
  3. 在测试中,构建存根的实例并为存根的方法提供代码:
     1 [TestClass]
     2 class TestStockAnalyzer
     3 {
     4 [TestMethod]
     5 public void TestContosoStockPrice()
     6 {
     7     // Arrange:
     8     // Create the fake stockFeed:
     9     IStockFeed stockFeed =
    10     new StockAnalysis.Fakes.StubIStockFeed() // Generated by Fakes.
    11     {
    12         // Define each method:
    13         // Name is original name + parameter types:
    14         GetSharePriceString = (company) => { return 1234; }
    15     };
    16     // In the completed application, stockFeed would be a real one:
    17     var componentUnderTest = new StockAnalyzer(stockFeed);
    18     // Act:
    19     int actualValue = componentUnderTest.GetContosoPrice();
    20     // Assert:
    21     Assert.AreEqual(1234, actualValue);
    22 }
    23 ...
    

    此处最为神奇的就是类 StubIStockFeed。 对于所引用程序集中的每个接口,Microsoft Fakes 机制将生成一个存根类。 存根类的名称派生自接口的名称,前缀为"Fakes.Stub",并且在名称后面追加了参数类型名称。

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

开始使用填充

(有关更多详细说明,请参见使用填充码针对单元测试将应用程序与程序集隔离。)

假定你的组件包含对 DateTime.Now 的调用:

1 // Code under test:
2 public int GetTheCurrentYear()
3 {
4     return DateTime.Now.Year;
5 } 

在测试过程中,你希望填充 Now 属性,因为每次调用时实际版本都会返回不同的值,从而造成了不便。

若要使用填充码,你不必修改应用程序代码或以特定方式来编写代码。

  1. 添加 Fakes 程序集

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

    选择"添加 Fakes 程序集"。

  2. 在 ShimsContext 中插入填充码
     1 [TestClass]
     2 public class TestClass1
     3 {
     4     [TestMethod]
     5     public void TestCurrentYear()
     6     {
     7         int fixedYear = 2000;
     8         // Shims can be used only in a ShimsContext:
     9         using (ShimsContext.Create())
    10         {
    11             // Arrange:
    12            // Shim DateTime.Now to return a fixed date:
    13             System.Fakes.ShimDateTime.NowGet =() =>
    15             { return new DateTime(fixedYear, 1, 1); };
    16             // Instantiate the component under test:
    17             var componentUnderTest = new MyComponent();
    18             // Act:
    19             int year = componentUnderTest.GetTheCurrentYear();
    20             // Assert:
    21             // This will always be true if the component is working:
    22             ssert.AreEqual(fixedYear, year);
    23         }
    24     }
    25 }
    26
    27              

    填充码类名称是通过在原始类型名称前加上 Fakes.Shim 前缀构成的。 在方法名称后面将会追加参数名称。 (您不需要添加对 System.Fakes 的任何项目引用)

前面的示例对一个静态方法使用了填充码。 若要将填充码用于实例方法,请在类型名称和方法名称之间写入 AllInstances:

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

您不必引用关于 System.IO.Fakes 的任何内容: 它由填充程序的生成过程创建。

你还可以为特定实例、构造函数和属性创建填充码。 有关详细信息,请参阅使用填充码针对单元测试将应用程序与程序集隔离

本节内容

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

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

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

时间: 2024-10-06 20:09:01

用 Microsoft Fakes 隔离测试代码的相关文章

使用Microsoft Fakes隔离测试代码

在单元测试(Unit Test)中我们遇到的问题之一是:假如被测试组件(类或项目)为A,组件A依赖于组件B,那么在组件A的单元测试ATest中测试A时,也需要依赖于B,在B发生改动后,就可能影响到A的测试结果.为了在测试A时隔离B对A的影响,这就是Microsoft Fakes要解决的问题. 解决上面的问题,Microsoft Fakes采用的方法是用将组件B用stubs或shims替换. 参看:http://msdn.microsoft.com/library/vstudio/hh549175

.NET单元测试的艺术-3.测试代码

开篇:上一篇我们学习单元测试和核心技术:存根.模拟对象和隔离框架,它们是我们进行高质量单元测试的技术基础.本篇会集中在管理和组织单元测试的技术,以及如何确保在真实项目中进行高质量的单元测试. 系列目录: 1.入门 2.核心技术 3.测试代码 一.测试层次和组织 1.1 测试项目的两种目录结构 (1)集成测试和单元测试在同一个项目里,但放在不同的目录和命名空间里.基础类放在单独的文件夹里. (2)集成测试和单元测试位于不同的项目中,有不同的命名空间. 实践中推荐使用第二种目录结构,因为如果我们不把

SQL SERVER 2008 数据库隔离级别代码演示

SQL SERVER 2008 数据库隔离级别代码演示 ? 在各种SQL 的教程上一直都强调SQL SERVER 的4个隔离级别(其实这是SQL 工业标) 未提交读 ReadUncommited? 已提交读 ReadCommited? 不可重复读 RepeatableRead? 序列化 Serializable (为什么叫这个么名字?) 这4种隔离级别,本身没有优劣之分,完全取决于应用的场景. 本质上,他们是在 隔离性(紊乱程度) 和 灵活性(并发性) 之间博弈.简单的说,灵活性越高,隔离性越差

测试代码

   编写函数或类时,还可以为其编写测试.通过测试,可确定代码面对各种输入都能够按照要求那样工作. 单元测试和测试用例:   单元测试用于核实蛮熟的某个方面没有问题:测试用例是一组单元测试,这些单元测试一起核实函数在各种情形下的行为都符合要求. 良好的测试用例考虑到了函数可能收到的各种输入,包含针对这些所有情形的测试. 全覆盖测试用例包含一整套单元测试,涵盖了各种可能的函数使用方式.对于大型项目,要实现覆盖可能很难.所以通常,最初只要针对 代码的重要行为编写测试即可,等项目被广泛使用率再考虑全覆

第4次作业类测试代码+105032014166+张珍珍

第4次作业:准备类测试代码 类测试代码的具体要求如下: (1)设计三角形完整程序 已经完成的方法是:  String triangle(int a,int b,int c) 现在要求继续增加新的功能: 建立界面,至少包含以下元素,但不限于此: 完成面积的方法:float triangleArea(int a,int b,int c) ,完成周长的方法:int perimeter(int a,int b,int c) 要求: 1.        画出类图: 2.        完成界面和相应的功能

Android网络传输中必用的两个加密算法:MD5 和 RSA (附java完成测试代码)

MD5和RSA是网络传输中最常用的两个算法,了解这两个算法原理后就能大致知道加密是怎么一回事了.但这两种算法使用环境有差异,刚好互补. 一.MD5算法 首先MD5是不可逆的,只能加密而不能解密.比如明文是yanzi1225627,得到MD5加密后的字符串是:14F2AE15259E2C276A095E7394DA0CA9  但不能由后面一大串倒推出yanzi1225627.因此可以用来存储用户输入的密码在服务器上.现在下载文件校验文件是否中途被篡改也是用的它,原理参见:http://blog.c

MyPython-->进阶篇-->测试代码

测试函数 要学习测试,得要有测试的代码.下面是一个简单的函数,接受名和姓并返回整洁的姓名 name_function.py def get_allname(x,m): allname = ('%s %s'%(x,m)).title() return allname 编写测试代码 from name_function import get_allname print(get_allname('cc','leo')) import unittest class NameTestCase(unitte

x264测试代码

建立一个工程,将头文件,库文件加载到工程,测试代码如下:#include <iostream>#include <string>#include "stdint.h"  //如果没有,下载地址为:http://download.csdn.net/detail/evsqiezi/7014021extern "C"{#include "x264.h"#include "x264_config.h"};usi

Maven配置插件跳过测试代码的编译和运行

Maven配置插件跳过测试代码的编译和运行: <!-- 编译插件 --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</targe