如何用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
相关产品推荐
相关产品推荐

