You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用FakeItEasy伪造商用第三方库的非虚成员完成单元测试

解决方案

方案1:引入抽象适配层(优先推荐,开源无额外依赖)

这是最通用的解耦方案,完全避开对第三方类的直接依赖,不需要修改第三方库代码:

  1. 定义抽象接口,声明你需要用到的Discovery类方法
public interface IDiscoveryService
{
    List<ApplicationDescription> FindServers(string discoveryUrl);
}
  1. 编写第三方Discovery类的包装实现
public class DiscoveryServiceWrapper : IDiscoveryService
{
    private readonly Discovery _realDiscovery;
    public DiscoveryServiceWrapper(ApplicationInstanceBase applicationInstance)
    {
        _realDiscovery = new Discovery(applicationInstance);
    }
    public List<ApplicationDescription> FindServers(string discoveryUrl)
    {
        return _realDiscovery.FindServers(discoveryUrl);
    }
}
  1. 修改业务代码,改为依赖抽象接口而非具体实现
    你可以通过构造函数注入IDiscoveryService的实例,或者注入工厂来按需创建:
// 业务类构造函数新增依赖注入
private readonly IDiscoveryService _discoveryService;
public OpcClient(IDiscoveryService discoveryService)
{
    _discoveryService = discoveryService;
}

public List<ApplicationDescription> FindServers(ApplicationInstanceBase applicationInstance, string serverName, string serverPort)
{
    try
    {
        var discoveryUrl = "opc.tcp://" + serverName + ":" + serverPort;
        // 直接调用抽象接口的方法,不再直接实例化Discovery
        return _discoveryService.FindServers(discoveryUrl);
    }
    catch (Exception)
    {
        return new List<ApplicationDescription>();
    }
}
  1. 修改测试代码,直接伪造抽象接口即可
[Test]
public void FindServersTest__simple()
{
    _serverList = CreateServerList();
    // 伪造接口不需要处理构造函数、非虚方法的问题
    var fakeDiscovery = A.Fake<IDiscoveryService>();
    A.CallTo(() => fakeDiscovery.FindServers(A<string>.Ignored)).Returns(_serverList);
    
    // 把伪造的接口注入被测业务类
    var opcClient = new OpcClient(fakeDiscovery);
    var servers = opcClient.FindServers(_applicationInstance, _OPCServer, _OPCServerPort);
    Assert.AreEqual(2, servers.Count);
}

优点:完全解耦第三方库,后续更换OPC库只需要修改包装层,单元测试逻辑稳定,完全兼容FakeItEasy等免费伪造框架


方案2:用支持拦截非虚方法的付费伪造框架

如果不想修改现有业务代码,可以使用支持非虚成员拦截的商用测试框架:

  • Typemock Isolator
  • Telerik JustMock
    这类框架不需要修改业务代码,直接可以伪造非虚的第三方类方法,但是需要付费,且部分框架对.NET Core/5+的支持需要额外配置。

方案3:提取第三方调用逻辑为虚方法,最小改动适配测试

如果不想引入新的接口和包装类,可以对业务代码做最小改动:

  1. 把直接调用Discovery的逻辑提取为受保护的虚方法
public List<ApplicationDescription> FindServers(ApplicationInstanceBase applicationInstance, string serverName, string serverPort)
{
    try
    {
        var discoveryUrl = "opc.tcp://" + serverName + ":" + serverPort;
        return CallDiscoveryFindServers(applicationInstance, discoveryUrl);
    }
    catch (Exception)
    {
        return new List<ApplicationDescription>();
    }
}

// 新增虚方法,封装所有第三方Discovery的调用逻辑
protected virtual List<ApplicationDescription> CallDiscoveryFindServers(ApplicationInstanceBase appInstance, string discoveryUrl)
{
    Discovery discovery = new Discovery(appInstance);
    return discovery.FindServers(discoveryUrl);
}
  1. 测试时直接伪造被测类的这个虚方法,返回模拟数据即可
[Test]
public void FindServersTest__simple()
{
    _serverList = CreateServerList();
    // 伪造被测类的虚方法,配置默认调用基类方法避免其他逻辑被拦截
    var fakeOpcClient = A.Fake<OpcClient>(x => x.CallsBaseMethods());
    A.CallTo(() => fakeOpcClient.CallDiscoveryFindServers(A<ApplicationInstanceBase>.Ignored, A<string>.Ignored)).Returns(_serverList);
    
    var servers = fakeOpcClient.FindServers(_applicationInstance, _OPCServer, _OPCServerPort);
    Assert.AreEqual(2, servers.Count);
}

优点:业务代码改动极小,不需要引入新的类结构
缺点:被测类的伪造需要注意配置调用基类方法,避免其他业务逻辑被拦截


内容的提问来源于stack exchange,提问作者sdmorris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 14:33:03