使用 Microsoft Fakes 隔离被测代码

代码隔离是一种测试策略,通常使用 Microsoft Fakes 等工具实现,在其中测试的代码与应用程序的其余部分分离。 这种分离是通过将应用程序中与受测代码交互的部分替换为桩或垫片来实现的。 这些是由测试控制的小段代码,用于模拟它们所替代的真实组件的行为。

此方法的优点是,它允许你专注于隔离测试代码的特定功能。 如果测试失败,则你知道原因位于独立代码中,而不是在其他位置。 此外,使用 Microsoft Fakes 提供的存根和垫片,即使应用程序的其他部分尚无法正常运行,你也能测试你的代码。

要求

Note

使用 Visual Studio 进行分析不适用于使用 Microsoft Fakes 的测试。

Microsoft Fakes 在代码隔离中的作用

Microsoft Fakes 通过提供两种机制(存根和填充码)在代码隔离中扮演关键角色。

  • 存根:这些用于使用一个实现相同接口的小型替代对象来替换某个类。 这要求设计应用程序,使每个组件仅依赖于接口,而不是依赖于其他组件。

  • 填充码:这些代码用于在运行时修改应用程序的已编译代码。 应用程序不是调用指定的方法,而是运行由测试提供的垫片代码。 Shim 可以替换对无法修改的程序集的调用,例如 .NET 程序集。

通常,存根用于 Visual Studio 解决方案内部的调用,而填充程序用于对其他被引用程序集的调用。 这是因为在你的解决方案中,按照桩替换所需的方式通过定义接口来将组件解耦,是一种良好的做法。 但是,外部程序集通常不附带单独的接口定义,因此通常会改为使用适配层来代替。

展示伪对象如何替换其他组件的示意图。

关于何时使用桩的建议

存根通常用于你的 Visual Studio 解决方案内部的调用,因为按照存根机制所要求的方式,通过定义接口将组件解耦是一种良好的做法。 但是,外部程序集(如 System.dll)通常不会单独提供接口定义,因此在这些情况下则会改用 shim。

使用存根涉及设计应用程序,以便不同的组件不相互依赖,而只依赖于接口定义。 这种分离使应用程序更加可靠且灵活,并允许将测试中的组件连接到接口的存根实现,以便进行测试。

在实践中,可以从Visual Studio中的接口定义生成存根类型,然后将实际组件替换为测试中的存根。

何时使用垫片的建议

尽管存根用于Visual Studio解决方案中的调用,但填充码通常用于调用其他引用的程序集。 这是因为外部程序集(如 System.dll)通常不提供单独的接口定义,因此必须使用填充。

不过,使用 shim(垫片)时,有一些因素需要考虑:

性能:垫片运行较慢,因为它们会在运行时重写你的代码。 存根没有这种性能开销,并且速度与虚拟方法可以运行的速度一样快。

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

内部类型:存根和填充码都可以与使用程序集属性 InternalsVisibleToAttribute可访问的内部类型一起使用。

私有方法:如果方法签名中的所有类型均可见,Shims 可以替换对私有方法的调用。 存根只能替换可见的方法。

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


将 .NET Framework 中的 Microsoft Fakes 转换为 SDK-Style 项目

将使用 Microsoft Fakes 的 .NET Framework 测试项目迁移到 SDK 风格的 .NET Framework、.NET Core 或 .NET 5 及更高版本项目。

要将 Microsoft Fakes 从 .NET Framework 迁移到 .NET Core 或 .NET 5.0,您只需对现有设置做少量更改。 必须考虑的情况如下:

  • 如果您使用自定义项目模板,则需要确保它采用 SDK 风格,并面向兼容的目标框架进行构建。

  • 某些类型在 .NET Framework 与 .NET Core/.NET 5.0 中分别位于不同的程序集中(例如,System.DateTime 在 .NET Framework 中位于 System/mscorlib,而在 .NET Core 和 .NET 5.0 中位于 System.Runtime),在这种情况下,您需要更改要伪造的程序集。

  • 如果你同时引用了 Fakes 程序集和测试项目,则可能会看到一条有关缺少引用的构建警告,类似如下:

    (ResolveAssemblyReferences target) ->
    warning MSB3245: Could not resolve this reference. Could not locate the assembly "AssemblyName.Fakes". Check to make sure the assembly exists on disk.
    If this reference is required by your code, you may get compilation errors.
    

    出现此警告是因为对 Fakes 生成所做的必要更改,可以忽略。 可以通过从项目文件中删除程序集引用来避免此问题,因为我们现在在生成过程中隐式添加它们。

运行 Microsoft Fakes 测试

只要Microsoft Fakes 程序集存在于配置的 FakesAssemblies 目录中(默认为 $(ProjectDir)FakesAssemblies),就可以使用 vstest 任务运行测试

对于使用 Microsoft Fakes 的 .NET Core 和 .NET 5+ 项目,使用 vstest task 进行分布式测试需要 Visual Studio 2019 Update 9 Preview 20201020-06 或更高版本。

不同.NET和Visual Studio版本中对 Microsoft Fakes 的兼容性和支持

旧版 .NET Framework 目标项目(非 SDK 样式)中的 Microsoft Fakes

  • Visual Studio Enterprise 2015 及更高版本支持 Microsoft Fakes 程序集生成。
  • Microsoft Fakes 测试可与所有可用的 Microsoft.TestPlatform NuGet 包配合运行。
  • 对于在 Visual Studio Enterprise 2015 及更高版本中使用 Microsoft Fakes 的测试项目,支持代码覆盖率。

SDK 样式的 .NET Framework、.NET Core 和 .NET 5.0 或更高版本项目中的 Microsoft Fakes

  • Microsoft Fakes 程序集生成功能在 Visual Studio Enterprise 2019 Update 6 中推出预览版,并在 Update 8 中默认启用。
  • 面向 .NET Framework 的项目的 Microsoft Fakes 测试可与所有可用的 Microsoft.TestPlatform NuGet 包一起运行。
  • 对于以 .NET Core 和 .NET 5.0 或更高版本为目标的项目,Microsoft Fakes 测试可配合版本为 16.9.0-preview-20210106-01 及更高版本的 Microsoft.TestPlatform NuGet 包运行。
  • 对于在 Visual Studio Enterprise 2015 及更高版本中使用 Microsoft Fakes、以 .NET Framework 为目标框架的测试项目,支持代码覆盖率功能。
  • 在 Visual Studio 2019 Update 9 及更高版本中,可为使用 Microsoft Fakes 且以 .NET Core 和 .NET 5.0 或更高版本为目标的测试项目提供代码覆盖率支持。