用 Microsoft Fakes 隔离测试代码
Microsoft 伪造品帮助您隔离通过替换应用程序的其他部分测试通过 存根 或 填充的代码。这些是受您的控件测试代码的小部分。通过隔离正在测试的代码,您知道,如果测试失败,原因代码并不其他位置。存根和填充还允许测试代码,即使应用程序的其他部分不起作用。
伪造品包括分为两个相似:
存根 包含实现同一接口的小的备用项替换选件类。若要使用存根,则必须设计您的应用程序,以便每个元素仅依赖于接口,而未在其他元素。(通过“元素”我们是指设计和一起更新和在该程序集通常包含。) 选件类的选件类或组
上述 修改应用程序的编译代码运行时,以便而不是让一个指定的方法调用,它运行测试提供的填充代码。填充可用于替换对您无法修改的程序集,以致 .NET 程序集。
要求
- Visual Studio 旗舰版
选择在存根和填充类型之间
通常,因为您同时,开发和更新这些选件类将视为一个 Visual Studio 项目元素。应考虑使用存根,并填充对该项目对您的解决方案中的其他项目,或者到项目引用的其他程序集。
作为泛型教程,请使用存根为您的 Visual Studio 解决方案中调用,并且,填充为调入其他引用的程序集。这是因为,在您的解决方案中最好通过定义接口组件分离方式与碰需要的。但是,外部程序集 (如 System.dll 通常不提供单独的接口定义,因此,您必须使用填充。
其他注意事项是:
**性能。**因为它们重写代码运行时,上述运行更慢。存根没有此性能开销并尽可能快,象虚方法可以是。
**静态方法,密封类型。**只能使用存根实现接口。因此,存根类型不能为静态方法,非虚方法,密封虚方法,在密封类型上的方法,依此类推。
**内部类型。**存根和填充可用于使访问使用程序集特性 InternalsVisibleToAttribute的内部类型。
**私有方法。**如果方法签名的所有类型都是可见的,填充码会替换调用私有方法。存根只能替换可见方法。
**接口和抽象方法。**存根提供可用于测试接口和抽象方法的实现。因为它们没有方法体,填充码无法检测接口和抽象方法。
通常,我们建议您使用存根类型与您的基本代码中的依赖项隔离。可以通过隐藏接口后的元素执行此操作。填充类型都可用于与不提供可测试的 API 的第三方组件隔离。
开始使用存根
插入接口
若要使用存根,必须编写要测试的代码,因此它不显式指定在应用程序另一个元素的选件类。由“元素”我们意味着选件类或选件类一起开发和更新和在 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
添加 Fakes 程序集
在解决方案资源管理器中,展开测试项目的引用列表。如果使用的是 Visual Basic,必须选择 显示所有文件 才能看到引用列表中。
选择对接口的程序集 (例如 IStockFeed) 中定义。在快捷菜单的引用,选择 添加 Fakes 程序集。
重新生成解决方案。
在测试,构造一个实例存根并为其方法提供代码:
[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 属性。
若要使用填充,您不必修改应用程序代码或编写为特定方法。
添加 Fakes 程序集
在解决方案资源管理器中,打开您的单元测试项目的引用并选择对包含方法要集的程序集。在此示例中,DateTime 选件类在 System.dll。若要查看 Visual Basic 项目引用,选择 显示所有文件。
选择 添加 Fakes 程序集。
插入 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 = ...
还可以创建填充特定实例,则构造函数的和属性。有关更多信息,请参见使用填充码针对单元测试将应用程序与程序集隔离。