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

什么是Fakes,它现在还能用吗
Fakes 是 Microsoft 为 .NET Framework(仅限)提供的轻量级隔离测试框架,核心是生成 FakesAssemblies,把对 System、mscorlib 或第三方程序集的调用重定向到可自定义行为的委托。但它**仅支持 .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 工具生成桩类型(如 ShimDateTime、StubIList<t></t>)
- 务必在测试方法上标注
[TestMethod] 且类标记 [TestClass];Fakes 上下文只在 MSTest v2(Microsoft.VisualStudio.TestTools.UnitTesting)中有效
.csproj(即非 SDK 风格),且目标框架为 net472 或更高(但 ≤ net48)xxx.Fakes 子文件夹和 .fakes 配置文件Microsoft.QualityTools.Testing.Fakes 的引用,并在编译时调用 fakes.exe 工具生成桩类型(如 ShimDateTime、StubIList<t></t>)[TestMethod] 且类标记 [TestClass];Fakes 上下文只在 MSTest v2(Microsoft.VisualStudio.TestTools.UnitTesting)中有效常见失败现象:CS0246 未能找到类型“ShimDateTime” —— 多半是没成功生成 Fakes 程序集,或项目 SDK 风格被误改;检查 obj\Fakes 目录是否存在生成的 .dll 和 .pdb。
Shim 和 Stub 的区别与典型用法
Fakes 提供两类桩类型:Shim(针对静态/非虚成员,如 DateTime.Now、File.ReadAllText)和 Stub(针对接口或虚方法,需传入实现):
-
Shim 必须在 ShimsContext.Create() 作用域内使用,离开即失效;它修改的是 IL 调用点,线程局部生效
-
Stub 是运行时对象替换,无需上下文,但只能用于可被继承/实现的成员(如 IRepository 接口)
- 避免在
Shim 中捕获异常后吞掉——它会干扰原始调用链;应明确 ShimXXX.BehaveAsNotImplemented() 或抛出自定义异常
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 模拟接口(如 IMemoryCache、IHttpClientFactory),配合 ServiceCollection 替换服务,覆盖 80%+ 场景
- 对
DateTime 等基础类型,封装为 IDateTimeProvider 接口再注入,比 Shim 更易测、更清晰
- 对
File、Registry 等系统 IO,改用内存实现(如 InMemoryDatabase、MemoryStream)或抽象为服务
Moq 模拟接口(如 IMemoryCache、IHttpClientFactory),配合 ServiceCollection 替换服务,覆盖 80%+ 场景DateTime 等基础类型,封装为 IDateTimeProvider 接口再注入,比 Shim 更易测、更清晰File、Registry 等系统 IO,改用内存实现(如 InMemoryDatabase、MemoryStream)或抽象为服务Fakes 的唯一不可替代场景只剩:必须在不改源码前提下,临时劫持某个 .NET Framework 内部静态方法(如 Assembly.GetExecutingAssembly())——但这类需求本身已属反模式,长期维护成本极高。










