如何用NSubstitute模拟带工厂方法的类并保留原行为与调用校验
使用NSubstitute模拟带私有构造函数的第三方Logger类
需求
需要模拟第三方库中的SomeLogger类,同时满足两个要求:
- 调用日志方法时执行真实逻辑(向控制台输出内容)
- 能通过
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
相关产品推荐
相关产品推荐

