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

如何用NSubstitute模拟带工厂方法的类并保留原行为与调用校验

使用NSubstitute模拟带私有构造函数的第三方Logger类

需求

需要模拟第三方库中的SomeLogger类,同时满足两个要求:

  1. 调用日志方法时执行真实逻辑(向控制台输出内容)
  2. 能通过NSubstitute的.Received()方法验证日志是否被正确记录

限制条件

目标类存在以下限制,导致常规NSubstitute用法失效:

  • 构造函数为私有,仅能通过静态工厂方法Create(ILogSettings)创建实例
  • 日志方法LogSomething为非虚方法,无法被NSubstitute直接拦截
  • Substitute.For/Substitute.ForPartsOf均因私有构造函数报错,CallBase配置无效果

解决方案:接口代理+真实逻辑转发

利用ISomeLogger接口,创建NSubstitute接口代理,同时配置代理在调用方法时转发到真实的SomeLogger实例。这种方式既保留真实日志输出,又能使用NSubstitute的调用验证能力。

实现代码

[TestFixture]
public class LoggerTest
{
    [Test]
    public void Logger_ExecutesRealLogicAndCanBeVerified()
    {
        // 1. 创建真实Logger实例
        var logSettings = Substitute.For<ILogSettings>();
        var realLogger = SomeLogger.Create(logSettings);

        // 2. 创建ISomeLogger的代理
        var loggerProxy = Substitute.For<ISomeLogger>();

        // 3. 配置代理调用时转发到真实实例
        loggerProxy.When(x => x.LogSomething(Arg.Any<string>()))
                   .Do(call => realLogger.LogSomething(call.Arg<string>()));

        // 4. 执行测试调用
        loggerProxy.LogSomething("测试日志内容");

        // 5. 验证调用次数与参数
        loggerProxy.Received(1).LogSomething("测试日志内容");
    }
}

方案说明

  • 真实实例通过工厂方法Create创建,确保执行完整的初始化逻辑
  • 接口代理由NSubstitute创建,负责跟踪调用次数与参数
  • 通过When(...).Do(...)配置,将代理的方法调用转发到真实实例,保留控制台输出
  • 最终可通过.Received()验证日志方法是否被正确调用

为什么其他方法失效?

  • Substitute.ForPartsOf<T>仅支持可实例化的类,私有构造函数无法满足实例化要求
  • 非虚方法无法被NSubstitute拦截,即使创建类代理也无法修改或跟踪其调用
  • 接口的CallBase配置无效,因为接口本身没有方法实现

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:35:16