11

Following is my generic base repository interface

public interface IRepository<T>
{
    IQueryable<T> AllIncluding(params Expression<Func<T, 
                               object>>[] includeProperties);
}

my entity

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

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

    public string Identifier { get; set; }    
}

and following is the specific repo

public interface ISdkRepository : IRepository<Sdk>
{
}

now I am trying to test a controller, using moq

Following is the code I am trying to test

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());
    }

using following test

[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();
}

and it is throwing:

System.Reflection.TargetParameterCountException : Parameter count mismatch

Don't know why?

SteveC
  • 15,808
  • 23
  • 102
  • 173
AmanT
  • 135
  • 1
  • 1
  • 5

4 Answers4

29

Though there is an answer marked as accepted, I believe there is a way to mock your repository correctly.

Instead of

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

please use

mockRepo.Setup(k => k.AllIncluding(It.IsAny<Expression<Func<Sdk, object>>[]>()))
                     .Returns((Expression<Func<Sdk, 
                        object>>[] includeProperties) => sdks.AsQueryable());
SteveC
  • 15,808
  • 23
  • 102
  • 173
Olek
  • 676
  • 7
  • 11
  • 1
    It saved my day) I had exactly the same problem in exactly the same method, your proposal works! – Maxim Zabolotskikh Mar 20 '12 at 08:48
  • Thank you! saved me poking about – trailmax May 30 '13 at 10:00
  • Awesome! Worked. Is there an explanation for how it works (what this actually does)? – Marcel Dec 03 '13 at 12:12
  • 1
    @Marcel the reason it works as it does is that you've told Moq that `AllIncluding` expects (via `It.IsAny`) one parameter, but `sdks.AsQueryable()` is a(n extension) method that doesn't have any parameters. Since you can use just the method name as a shorthand for the delegate, it lets you compile it but fails when Moq evaluates it. Giving it an explicit delegate that _returns the evaluated `.AsQueryable`_ then fits the expected pattern. – drzaus Aug 25 '15 at 20:55
7

Another solution for solving this issue is to use: .AsQueryable() instead of .AsQueryable.

Robert
  • 5,278
  • 43
  • 65
  • 115
Alina
  • 126
  • 1
  • 6
5

I think you've hit some limitations here with Moq. It doesn't handle expression parameters well because it can be passed expressions as values itself. There's no way for Moq to know what part of the expression is intended to be resolved and what is part of the signature.

Also, I can't remember how well Moq handles params xx[] but it's quite possible you have a combination of two problems here.

Are you able to create a class that exposes the set of expressions as a property? If so it might be possible to change the signature of AllIncluding and tell Moq to match on any instance of that class.

Update

At the time of answering this was a limitation but is now possible. See the answer by Oleksandr Lytvyn

JRoughan
  • 1,635
  • 12
  • 32
2

For other people looking for answer to this the solution for me was adding the same number of parameters in Setup as in the expression in Returns.

For example:

Not working with different argument count

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

Working with same amount of args in expression in Returns as in Setup

mock.Setup(x => x.DoSomething(It.IsAny<string>()))
                .Returns((string s1, string s2) => s1.ToLower());
Jonas Stensved
  • 14,378
  • 5
  • 51
  • 80