C#如何使用Microsoft Fakes进行隔离测试

来源:站长站作者:杨建军头衔:草根站长
导读:本期聚焦于小伙伴创作的《C#如何使用Microsoft Fakes进行隔离测试》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《C#如何使用Microsoft Fakes进行隔离测试》有用,将其分享出去将是对创作者最好的鼓励。

在C#的单元测试场景中,当被测试的代码依赖外部资源或者难以直接构造的依赖对象时,测试的执行会变得复杂且不稳定。Microsoft Fakes框架提供了垫片(Shim)和存根(Stub)两种隔离机制,能够在测试运行时动态替换依赖的行为,让测试可以脱离真实依赖独立运行。

C#如何使用Microsoft Fakes进行隔离测试

Microsoft Fakes核心概念

Stub(存根)

Stub是基于接口或抽象类生成的替代实现,适用于被依赖项是接口或者抽象类的场景。它可以在测试时自定义接口方法的返回值,模拟不同的依赖响应,且不需要修改原有代码的逻辑。

Shim(垫片)

Shim可以替换任何.NET方法的实现,包括静态方法、密封类的方法、非虚方法等,即使被依赖项没有接口或抽象类也可以进行隔离。它通过在运行时修改方法调用入口来实现替换,灵活性更高。

环境准备

Microsoft Fakes框架目前仅支持Visual Studio企业版,使用前需要确认开发环境满足要求。首先需要在项目中安装单元测试框架,比如MSTest,然后为需要隔离的项目添加Fakes程序集。

操作步骤:在解决方案资源管理器中,右键点击被测试项目的引用,选择添加Fakes程序集,Visual Studio会自动生成对应的Fakes程序集,通常会在项目的Fakes目录下看到生成的文件。

Stub使用示例

假设我们有一个依赖IUserRepository接口的用户服务类,接口定义如下:

public interface IUserRepository
{
    User GetUserById(int id);
}

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class UserService
{
    private readonly IUserRepository _userRepository;

    public UserService(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public string GetUserName(int id)
    {
        var user = _userRepository.GetUserById(id);
        return user == null ? "未知用户" : user.Name;
    }
}

我们需要测试GetUserName方法,使用Stub隔离IUserRepository的实现:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using MyProject.Fakes; // 生成的Fakes命名空间
using MyProject.Services;
using MyProject.Models;

[TestClass]
public class UserServiceTests
{
    [TestMethod]
    public void GetUserName_用户存在_返回用户名()
    {
        // 创建Stub实例
        var stubRepo = new StubIUserRepository
        {
            // 自定义GetUserById方法的实现
            GetUserByIdInt32 = (id) => new User { Id = id, Name = "测试用户" }
        };
        var service = new UserService(stubRepo);

        // 执行测试
        var result = service.GetUserName(1);

        // 断言
        Assert.AreEqual("测试用户", result);
    }

    [TestMethod]
    public void GetUserName_用户不存在_返回未知用户()
    {
        var stubRepo = new StubIUserRepository
        {
            GetUserByIdInt32 = (id) => null
        };
        var service = new UserService(stubRepo);

        var result = service.GetUserName(1);

        Assert.AreEqual("未知用户", result);
    }
}

Shim使用示例

如果被依赖的是静态类或者没有接口的类,就需要使用Shim。比如我们有一个依赖DateTime.Now的工具类,需要测试不同时间下的逻辑:

public class TimeHelper
{
    public static string GetCurrentTimeGreeting()
    {
        var hour = DateTime.Now.Hour;
        if (hour < 12)
        {
            return "上午好";
        }
        else if (hour < 18)
        {
            return "下午好";
        }
        else
        {
            return "晚上好";
        }
    }
}

使用Shim替换DateTime.Now的返回值:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Fakes;
using MyProject.Helpers;

[TestClass]
public class TimeHelperTests
{
    [TestMethod]
    public void GetCurrentTimeGreeting_上午时间_返回上午好()
    {
        using (ShimsContext.Create())
        {
            // 替换DateTime.Now的返回值
            ShimDateTime.NowGet = () => new DateTime(2023, 1, 1, 8, 0, 0);
            var result = TimeHelper.GetCurrentTimeGreeting();
            Assert.AreEqual("上午好", result);
        }
    }

    [TestMethod]
    public void GetCurrentTimeGreeting_下午时间_返回下午好()
    {
        using (ShimsContext.Create())
        {
            ShimDateTime.NowGet = () => new DateTime(2023, 1, 1, 14, 0, 0);
            var result = TimeHelper.GetCurrentTimeGreeting();
            Assert.AreEqual("下午好", result);
        }
    }
}

注意使用Shim时需要创建ShimsContext,它会在作用域内生效,离开作用域后替换会失效,避免影响其他测试。

使用注意事项

  • Stub仅适用于接口和抽象类的场景,优先使用Stub,因为它的侵入性更低,更符合面向对象的设计原则。
  • Shim通过运行时修改方法调用来实现,可能会对测试性能有一定影响,且过度使用会让测试逻辑变得难以理解,非必要场景不要使用。
  • 添加Fakes程序集后,每次被依赖项目重新编译,可能需要重新生成Fakes程序集,避免版本不匹配的问题。
  • 测试类需要标记[TestClass]特性,测试方法需要标记[TestMethod]特性,否则测试框架无法识别。

常见问题处理

如果在生成Fakes程序集时出现找不到类型的错误,需要检查被依赖项目的目标框架是否和当前项目兼容,Microsoft Fakes支持大部分.NET Framework和.NET Core/.NET 5+版本,但部分旧版本可能存在兼容问题。

当使用Shim替换方法时,如果替换没有生效,需要确认方法是否是静态方法、是否是密封类的方法,以及是否在ShimsContext的作用域内执行了测试代码。

C#Microsoft_Fakes隔离测试单元测试修改时间:2026-06-18 02:39:26

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。