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

如何用NSubstitute实现类似Moq的泛型传入值返回功能?

用NSubstitute Mock泛型Set方法返回传入值的正确实现

需求是Mock如下接口的Set方法,使其返回泛型参数中传入的value值:

public interface IMemoryCache
{
    TItem Set<TItem>(object key, TItem value);
}

用Moq可以轻松实现:

[Fact]
public void SetupUsingMoq()
{
    Mock<IMemoryCache> mock = new();

    mock
        .Setup(x => x.Set(It.IsAny<object>(), It.IsAny<It.IsAnyType>()))
        .Returns((object _, object input) => input);

    mock.Object.Set(1, "ok").Should().Be("ok");
}

但尝试用NSubstitute实现时写法有误,导致失败:

[Fact]
public void SetupUsingNSubstitute()
{
    IMemoryCache mock = Substitute.For<IMemoryCache>();

    mock
        .Set(Arg.Any<object>(), Arg.Any<Arg.AnyType>())
        .Returns(callInfo => callInfo.ArgAt<object>(1));

    mock.Set(1, "ok").Should().Be("ok");
}

错误原因

原写法中Arg.Any<Arg.AnyType>()是错误用法,NSubstitute不支持这种方式匹配泛型参数。正确做法是用ReturnsForAnyArgs捕获任意参数,或通过When配合泛型方法的正确匹配逻辑。

正确实现方式

方式一:使用ReturnsForAnyArgs

[Fact]
public void SetupWithReturnsForAnyArgs()
{
    IMemoryCache mock = Substitute.For<IMemoryCache>();

    // 匹配任意参数,返回第二个参数(即传入的value)
    mock.Set(Arg.Any<object>(), Arg.Any<object>())
        .ReturnsForAnyArgs(callInfo => callInfo.ArgAt(1));

    // 验证不同类型的调用
    mock.Set(1, "ok").Should().Be("ok");
    mock.Set("cacheKey", 456).Should().Be(456);
}

方式二:使用When配合泛型匹配

[Fact]
public void SetupWithWhenForGenericMethod()
{
    IMemoryCache mock = Substitute.For<IMemoryCache>();

    // 匹配任意泛型的Set方法调用
    mock.When(x => x.Set(Arg.Any<object>(), Arg.Any<It.IsAnyType>()))
        .Do(callInfo => 
        {
            // 获取传入的value参数并返回
            var inputValue = callInfo.ArgAt<object>(1);
            callInfo.Return(inputValue);
        });

    mock.Set("testKey", true).Should().BeTrue();
}

这两种方式都能让Mock的Set方法正确返回传入的泛型参数值,和Moq的实现效果一致。

内容的提问来源于stack exchange,提问作者Eduardo Brites

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 12:52:53