C# Fakes框架使用方法 C#如何使用Microsoft Fakes进行隔离测试

1次阅读

fakes是仅适用于.net framework 4.0+的隔离测试框架,依赖vs ide生成fakesassemblies,不支持.net core/5+及vs 2022,现已淘汰;推荐改用moq+di等现代方案。

C# Fakes框架使用方法 C#如何使用Microsoft Fakes进行隔离测试

什么是Fakes,它现在还能用吗 Fakes 是 microsoft 为 .NET Framework(仅限)提供的轻量级隔离测试框架,核心是生成 FakesAssemblies,把对 Systemmscorlib 或第三方程序集的调用重定向到可自定义行为的委托。但它**仅支持 .NET Framework 4.0+,不支持 .NET Core / .NET 5+**。visual studio 2019 是最后一个提供完整 Fakes 设计器支持的版本;VS 2022 已完全移除 Fakes 项目模板和右键“Add Fakes Assembly”菜单。

如果你正在用 .NET 6+ 或跨平台开发,Microsoft.Fakes 不可用——不是配置问题,而是根本没实现。别浪费时间查“为什么 Fakes 不生成”或“如何在 SDK 风格项目中启用”,答案统一:不能。

在 .NET Framework 项目中启用 Fakes 的关键步骤 Fakes 不是 NuGet 包,也不靠 dotnet test 驱动,它依赖 VS IDE 的专有生成逻辑和特定项目结构:

  • 必须使用传统 .csproj(即非 SDK 风格),且目标框架为 net472 或更高(但 ≤ net48
  • 测试项目需引用待测程序集(.dll),右键该引用 → “Add Fakes Assembly” → VS 自动生成 xxx.Fakes 子文件夹和 .fakes 配置文件
  • 生成后,项目自动添加对 Microsoft.QualityTools.Testing.Fakes 的引用,并在编译时调用 fakes.exe 工具生成桩类型(如 ShimDateTimeStubIList<t></t>
  • 务必在测试方法上标注 [TestMethod] 且类标记 [TestClass];Fakes 上下文只在 MSTest v2(Microsoft.visualstudio.TestTools.UnitTesting)中有效

常见失败现象:CS0246 未能找到类型“ShimDateTime” —— 多半是没成功生成 Fakes 程序集,或项目 SDK 风格被误改;检查 objFakes 目录是否存在生成的 .dll.pdb

Shim 和 Stub 的区别与典型用法 Fakes 提供两类桩类型:Shim(针对静态/非虚成员,如 DateTime.NowFile.ReadAllText)和 Stub(针对接口或虚方法,需传入实现):

  • Shim 必须在 ShimsContext.Create() 作用域内使用,离开即失效;它修改的是 IL 调用点,线程局部生效
  • Stub 是运行时对象替换,无需上下文,但只能用于可被继承/实现的成员(如 IRepository 接口)
  • 避免在 Shim 中捕获异常后吞掉——它会干扰原始调用链;应明确 ShimXXX.BehaveAsNotImplemented() 或抛出自定义异常

示例:拦截 DateTime.Now

using (ShimsContext.Create()) {     ShimDateTime.NowGet = () => new DateTime(2020, 1, 1);     Assert.AreEqual(new DateTime(2020, 1, 1), DateTime.Now); }

注意:ShimDateTime 类型由 Fakes 自动生成,命名规则是 Shim + 原类型名;属性访问器需写成 NowGet(而非 get_Now)。

为什么现在更推荐 Moq + Microsoft.Extensions.DependencyInjection Fakes 的强耦合性带来几个硬伤:fakes.exe 生成慢、调试符号难追踪、无法用于 CI(因依赖 VS 安装)、不支持 async 成员桩(ShimTask 无可靠行为)。而现代替代方案更直接:

  • Moq 模拟接口(如 IMemoryCacheIHttpClientFactory),配合 ServiceCollection 替换服务,覆盖 80%+ 场景
  • DateTime 等基础类型,封装IDateTimeProvider 接口再注入,比 Shim 更易测、更清晰
  • FileRegistry 等系统 IO,改用内存实现(如 InMemoryDatabaseMemoryStream)或抽象为服务

Fakes 的唯一不可替代场景只剩:必须在不改源码前提下,临时劫持某个 .NET Framework 内部静态方法(如 Assembly.GetExecutingAssembly())——但这类需求本身已属反模式,长期维护成本极高。

text=ZqhQzanResources