用 Microsoft Fakes 隔离测试代码

代码隔离是一种测试策略,通常使用 Microsoft Fakes 等工具实现,其中要测试的代码与应用程序的其余部分分开。 这种分离是通过将与受测代码交互的应用程序的部分替换为存根或填充码来实现的。 这些是受你的测试控制的小段代码,用来模拟正在替换的实际部分的行为。

此方法的好处是,它可以让你专注于单独测试代码的特定功能。 如果测试失败,你会知道原因就在独立代码,而不是其他地方。 此外,通过使用 Microsoft Fakes 提供的存根和填充码,即使应用程序的其他部分尚未正常运行,也能测试代码。

要求

注意

Visual Studio 分析不能用于使用 Microsoft Fakes 的测试。

Microsoft Fakes 在代码隔离中的角色

Microsoft Fakes 通过提供两种机制(存根和填充码)在代码隔离中起着关键作用。

  • 存根:这些用于将类替换为可实现同一接口的小型替代项。 这要求将应用程序设计为每个组件仅依赖接口,而不依赖其他组件。

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

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

Diagram that show Fakes replacing other components.

有关何时使用存根的建议

存根通常用于 Visual Studio 解决方案中的调用,因为通过按照存根要求的方式定义接口来分离组件是一个很好的做法。 但是,外部程序集(如 System.dll)通常没有单独的接口定义,因此在这些情况下改用填充码。

使用存根时将应用程序设计为使不同的组件不相互依赖,而只依赖接口定义。 这种分离不但使应用程序更加可靠和灵活,还让你能够将接受测试的组件连接到接口的存根实现,以便进行测试。

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

有关何时使用填充码的建议

为在 Visual Studio 解决方案中进行的调用使用存根时,通常为对其他引用的程序集的调用使用填充码。 这是因为外部程序集(如 System.dll)通常没有单独的接口定义,因此必须改用填充码。

但是,使用填充码时需要考虑一些因素:

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

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

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

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

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


将 .NET Framework 中的 Microsoft Fakes 转换为 SDK 样式项目

将使用 Microsoft Fakes 的 .NET Framework 测试项目转换为 SDK 样式 .NET Framework、.NET Core 或 .NET 5+ 项目。

只需要在 .NET Framework 的 Microsoft Fakes 设置中进行一点点更改,即可转换为 .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 测试

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

使用 vstest 任务对使用 Microsoft Fakes 的 .NET Core 和 .NET 5+ 项目进行分布式测试需要 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 或更高版本的测试项目的代码覆盖率支持。