关于NSubstitute的测试疑问:是测试替身还是真实业务代码?
关于NSubstitute测试替身的疑问解答
你测试的确实是替身(Stub/Mock)的返回结果,不是真实Calculator类的Add方法逻辑。
文档里的这个示例只是用来演示NSubstitute最基础的语法用法——教你怎么给替身的方法预设返回值,以及验证这个预设是否生效,本质上是在展示工具的使用方式,不是用来测试真实业务代码的。
这种替身的核心意义在于隔离依赖,聚焦目标代码的测试,具体场景包括:
- 隔离复杂依赖:如果你的业务代码依赖一个包含数据库、网络请求等复杂逻辑的组件,用替身可以跳过这些耗时或不稳定的环节,专注测试业务代码本身的逻辑是否正确。
- 模拟异常/边界场景:真实组件可能很难触发某些异常或边界情况,比如网络超时、参数越界报错,通过替身可以轻松模拟这些场景,验证你的代码是否能正确处理。
- 验证交互逻辑:除了预设返回值,你还可以用NSubstitute验证目标代码是否按照预期调用了依赖组件的方法——比如调用次数、传入参数是否正确,这才是替身更常用的测试场景。举个例子:
// 验证目标代码是否调用过calculator.Add(1,2) calculator.Received().Add(1, 2);
举个更贴近真实开发的例子:
假设你有一个OrderService类,它依赖ICalculator来计算订单总价:
public class OrderService { private readonly ICalculator _calculator; public OrderService(ICalculator calculator) { _calculator = calculator; } public decimal CalculateTotal(decimal unitPrice, int count) { // 调用计算器的乘法计算总价 return _calculator.Multiply(unitPrice, count); } }
测试OrderService时,就可以用NSubstitute的替身来隔离ICalculator:
// 创建ICalculator接口的替身 var calculator = Substitute.For<ICalculator>(); // 预设:当调用Multiply(10, 3)时返回30 calculator.Multiply(10, 3).Returns(30); // 实例化要测试的OrderService,传入替身 var orderService = new OrderService(calculator); // 调用业务方法 var total = orderService.CalculateTotal(10, 3); // 断言计算结果是否符合预期 Assert.That(total, Is.EqualTo(30)); // 验证OrderService是否正确调用了计算器的Multiply方法 calculator.Received().Multiply(10, 3);
这个测试里,我们不需要关心ICalculator的真实实现是否正确(那是Calculator类自己的单元测试要做的事),只需要验证OrderService是否正确使用了依赖的计算器来完成总价计算。
内容的提问来源于stack exchange,提问作者Jesse Liberty
相关产品推荐
相关产品推荐

