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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 15:39:02