NSubstitute Mock带params参数方法返回集合为空如何正确配置
NSubstitute Mock带params参数方法返回值异常解决方案
问题复现
TestClass类定义的方法签名如下:
public virtual async Task<IEnumerable<T>> GetAll(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includes)
原有Mock配置代码可正常编译,但调用时返回空集合,未返回预设的2个Animal对象:
_testClass.GetAll(Arg.Any<Expression<Func<Animal, bool>>>()).Returns(new List<Animal>(){new Animal(), new Animal()});
根因分析
NSubstitute的参数匹配是严格按参数列表执行的。原配置只匹配了仅传入1个predicate参数的调用,但C#中params参数的本质是语法糖,即使调用时不显式传值,编译器也会自动传入一个空数组作为第二个参数。因此实际调用时参数个数为2,和配置的单参数规则不匹配,NSubstitute会返回IEnumerable<Animal>的默认值(空序列),导致返回集合长度为0。
正确配置方式
通用场景:匹配所有调用(无论是否传includes参数)
补充第二个params数组的任意匹配规则即可,这是最常用的配置方式:
_testClass.GetAll( Arg.Any<Expression<Func<Animal, bool>>>(), Arg.Any<Expression<Func<Animal, object>>[]>() ) .Returns(new List<Animal> { new Animal(), new Animal() });
若使用较低版本NSubstitute,不支持自动将同步值包装为Task返回,可显式返回Task包装结果:
.Returns(Task.FromResult<IEnumerable<Animal>>(new List<Animal> { new Animal(), new Animal() }));
精确场景:仅匹配不传includes参数的调用
如果需要精确匹配未传入任何includes参数(即第二个参数为空数组)的场景,可使用Arg.Is做条件匹配:
_testClass.GetAll( Arg.Any<Expression<Func<Animal, bool>>>(), Arg.Is<Expression<Func<Animal, object>>[]>(arr => arr.Length == 0) ) .Returns(new List<Animal> { new Animal(), new Animal() });
注意事项
- 如果存在传入1个或多个includes参数的调用场景,需要单独为对应参数数量的调用配置返回规则,否则仍会返回空序列
params是C#的编译期语法糖,对Mock框架而言和普通数组参数没有区别,必须显式配置匹配规则
内容的提问来源于stack exchange,提问作者Sike12
相关产品推荐
相关产品推荐

