如何使用NSubstitute模拟运算符重载?测试ClassA时配置ClassB的*运算结果
在NSubstitute中模拟重载了*运算符的ClassB实例
要解决这个问题,得先搞清楚.NET中运算符重载的本质:所有运算符重载在编译后都会变成命名特殊的静态方法,比如二元*运算符对应的是op_Multiply静态方法。而NSubstitute的核心能力是模拟实例成员,直接处理静态运算符方法并不支持——不过我们可以通过重构代码或者间接模拟的方式实现需求。
下面分两种常见场景给出解决方案:
场景1:重构代码,将运算符逻辑委托给实例方法
这是最推荐的做法,既保持代码的可测试性,又符合单一职责原则。
假设你的ClassB原来的运算符重载是这样的:
public class ClassB { public static ClassB operator *(ClassB left, int multiplier) { // 这里是运算符的逻辑 return new ClassB(left.Value * multiplier); } public int Value { get; } public ClassB(int value) => Value = value; }
我们可以把运算符的核心逻辑提取到一个实例方法中,让运算符直接调用这个方法:
public class ClassB { public static ClassB operator *(ClassB left, int multiplier) { // 委托给实例方法 return left.MultiplyBy(multiplier); } // 提取出的实例方法,用于核心逻辑 public virtual ClassB MultiplyBy(int multiplier) { return new ClassB(Value * multiplier); } public int Value { get; } public ClassB(int value) => Value = value; }
现在在测试中,你就可以用NSubstitute模拟这个MultiplyBy实例方法,从而间接控制*运算符的返回结果:
// 创建ClassB的模拟实例 var mockB = Substitute.For<ClassB>(10); // 构造函数参数按需传入 // 设置当调用MultiplyBy任意整数时,返回指定的ClassB实例 mockB.MultiplyBy(Arg.Any<int>()).Returns(new ClassB(100)); // 测试*运算:mockB * 5 会调用MultiplyBy(5),返回我们设置的实例 var result = mockB * 5; Assert.AreEqual(100, result.Value);
场景2:如果无法重构ClassB(比如第三方类库)
如果ClassB是第三方类,你无法修改它的代码,那可以考虑包装一层适配器类,将运算符的调用转化为实例方法的调用,再模拟适配器。
比如创建一个ClassBWrapper:
public class ClassBWrapper { private readonly ClassB _innerB; public ClassBWrapper(ClassB innerB) => _innerB = innerB; // 包装*运算符 public virtual ClassB Multiply(int multiplier) { return _innerB * multiplier; } }
然后在ClassA中依赖ClassBWrapper而不是直接依赖ClassB,测试时模拟ClassBWrapper的Multiply方法:
var mockWrapper = Substitute.For<ClassBWrapper>(new ClassB(10)); mockWrapper.Multiply(Arg.Any<int>()).Returns(new ClassB(200)); // 注入到ClassA中 var classA = new ClassA(mockWrapper); // 后续测试逻辑...
关键注意点
- NSubstitute不支持直接模拟静态方法(包括运算符对应的静态方法),所以必须通过实例方法的间接方式来处理。
- 如果你遇到的是一元
*运算符(比如指针解引用),对应的静态方法是op_UnaryMultiply,处理思路和上面一致——把逻辑提取到实例方法再模拟。
内容的提问来源于stack exchange,提问作者François
相关产品推荐
相关产品推荐

