如何在NUnit中替换Prism的ContainerLocator.Container对象
你遇到的CouldNotSetReturnDueToNoLastCallException异常核心原因是:NSubstitute 原生不支持对静态成员进行 Mock,ContainerLocator.Container 是静态属性,你直接对它调用.Returns()方法时,NSubstitute 无法捕获到对应的前置调用记录,因此无法设置返回值。
以下是三种可行的解决方案,按推荐优先级排序:
方案1:重构业务代码(优先推荐,可测试性最高)
直接依赖静态服务定位器本身会大幅降低代码可测试性,建议改为构造函数注入依赖,不在类内部主动解析服务:
修改后待测试类示例
public class YourTestClass { private readonly IDevicesList _devices; // 直接注入所需依赖,不再内部调用ContainerLocator public YourTestClass(IDevicesList devices) { _devices = devices; } }
对应测试代码
var fakeDeviceList = Substitute.For<IDevicesList>(); // 直接传入伪造对象即可完成测试类构造,无需处理容器逻辑 var testInstance = new YourTestClass(fakeDeviceList);
方案2:增加静态调用适配层(兼容旧代码的最优选择)
如果原有业务逻辑不能重构,可以添加一层极薄的适配层封装静态容器调用,将静态依赖转为可Mock的实例依赖:
定义适配接口与实现
// 适配接口 public interface IContainerLocatorAdapter { IContainerProvider Container { get; } } // 适配实现 public class ContainerLocatorAdapter : IContainerLocatorAdapter { public IContainerProvider Container => ContainerLocator.Container; }
修改待测试类依赖
public class YourTestClass { private readonly IDevicesList _devices; public YourTestClass(IContainerLocatorAdapter locatorAdapter) { _devices = locatorAdapter.Container.Resolve<IDevicesList>(); } }
对应测试代码
// 伪造依赖对象 var fakeDeviceList = Substitute.For<IDevicesList>(); var fakeProvider = Substitute.For<IContainerProvider>(); fakeProvider.Resolve<IDevicesList>().Returns(fakeDeviceList); var fakeLocator = Substitute.For<IContainerLocatorAdapter>(); fakeLocator.Container.Returns(fakeProvider); // 构造测试实例 var testInstance = new YourTestClass(fakeLocator);
方案3:使用支持静态Mock的工具(不推荐)
如果完全不允许修改业务代码,可以选择支持静态成员Mock的测试工具(如Typemock、JustMock等付费工具),或使用.NET平台的底层Hook方案实现静态成员伪造。但这类方案可维护性差、依赖特殊工具,非必要不建议使用。
内容的提问来源于stack exchange,提问作者Miamy
相关产品推荐
相关产品推荐

