Moq Params TargetParameterCountException: 参数计数不匹配异常

11
以下是我的通用基本存储库接口。
public interface IRepository<T>
{
    IQueryable<T> AllIncluding(params Expression<Func<T, 
                               object>>[] includeProperties);
}

我的实体

public class Sdk 
{
    public Sdk()
    {
       this.Identifier = Guid.NewGuid().ToString();
    }

    public virtual ICollection<Resource> AccessibleResources { get; set; }

    public string Identifier { get; set; }    
}

以下是具体的代码库

public interface ISdkRepository : IRepository<Sdk>
{
}

现在我正在尝试使用Moq测试控制器。

以下是我要测试的代码:

public ActionResult GetResources(string clientId) {
        var sdkObject = sdkRepository
                           .AllIncluding(k => k.AccessibleResources)
                           .SingleOrDefault(k => k.Identifier == clientId);
        if (sdkObject == null)
            throw new ApplicationException("Sdk Not Found");
        return Json(sdkObject.AccessibleResources.ToList());
    }

使用以下测试
[Test]
public void Can_Get_GetResources()
{
    var cid = Guid.NewGuid().ToString();
    var mockRepo = new Moq.Mock<ISdkRepository>();
    var sdks = new HashSet<Sdk>()
    {
        new Sdk()
        {
            Identifier = cid,
            AccessibleResources = new HashSet<Resource>()
            {
                new Resource()
                {
                    Id = Guid.NewGuid(),
                    Description = "This is sdk"
                }
            }
        }
    };
    mockRepo.Setup(k => k.
        AllIncluding(It.IsAny<Expression<Func<Sdk,object>>[]>()))
                       .Returns(sdks.AsQueryable);
    var sdkCtrl = new SdksController(mockRepo.Object);
    var returnedJson=sdkCtrl.GetResources(cid);
    returnedJson.ToString();
}

它会抛出以下异常:

System.Reflection.TargetParameterCountException:参数计数不匹配

不知道为什么?


你能粘贴一下堆栈跟踪吗? - Raghu
4个回答

29

虽然有一个标记为已接受的答案,但我认为有一种正确模拟您的存储库的方法。

不是

mockRepo.Setup(k => k.AllIncluding(It.IsAny<Expression<Func<Sdk, object>>[]>()))
                     .Returns(sdks.AsQueryable);

请使用

mockRepo.Setup(k => k.AllIncluding(It.IsAny<Expression<Func<Sdk, object>>[]>()))
                     .Returns((Expression<Func<Sdk, 
                        object>>[] includeProperties) => sdks.AsQueryable());

1
它救了我的一天) 我在完全相同的方法中遇到了完全相同的问题,你的建议有效! - Maxim Zabolotskikh
谢谢!这救了我一番搜索的麻烦。 - trailmax
太棒了!成功了。这个是怎么工作的,有解释吗(它实际上是做什么的)? - Marcel
1
@Marcel,它能够按照预期工作的原因是你已经告诉Moq AllIncluding 通过 It.IsAny<TExpected> 需要一个参数,但是 sdks.AsQueryable() 是一个没有任何参数的(扩展)方法。由于您可以仅使用方法名称作为委托的速记,因此它允许您编译它,但在Moq评估它时失败。给它一个明确的委托,返回评估的 .AsQueryable 然后符合预期的模式。 - drzaus

7
解决这个问题的另一个方法是使用.AsQueryable()而不是.AsQueryable

5
我认为您在使用Moq时遇到了一些限制。它无法很好地处理表达式参数,因为它本身可以将表达式作为值传递。Moq无法知道表达式的哪一部分是要解决的,哪一部分是签名的一部分。
此外,我记不清Moq如何处理params xx[],但您可能同时遇到了两个问题。
您能否创建一个公开表达式集合作为属性的类?如果可以,可能可以更改AllIncluding的签名,并告诉Moq匹配该类的任何实例。
更新:
在回答时,这是一个限制,但现在已经可以做到了。请参见Oleksandr Lytvyn的答案。

请查看Oleksandr Lytvyn的答案。 - Marcel

2

对于其他人寻找答案而言,对我来说解决方案是在Setup中添加与Returns表达式中相同数量的参数。

例如:

如果参数数量不同,则无法正常工作

mock.Setup(x => x.DoSomething(It.IsAny<string>(), It.IsAny<string>()))
                .Returns((string s) => s.ToLower());

在表达式中的ReturnsSetup中使用相同数量的参数。
mock.Setup(x => x.DoSomething(It.IsAny<string>()))
                .Returns((string s1, string s2) => s1.ToLower());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接