Using Moq, how to mock a method with lambda arguments
Asked Answered
H

0

7

I have a fallowing method in my Repository class:

public virtual IEnumerable<T> GetAll(Expression<Func<T, bool>> where = null, Func<IQueryable<T>, IOrderedQueryable<T>> orderBy = null, Expression<Func<T, object>>[] includeProperties = null)

I would like to ask You, how it can be mocked to return some specific value, when I am passing in some concrete lambda expression?

SettingsRepository.Setup(
           r =>
           r.GetAll(
               It.IsAny<Expression<Func<Settings, bool>>>(),
               It.IsAny<Func<IQueryable<Settings>, IOrderedQueryable<Settings>>>(),
               It.IsAny<Expression<Func<Settings, Object>>[]>())).Returns((Settings[])null);

This will return null, no matter what lambda you will use.

I am looking for something like that:

 Expression<Func<Settings, bool>> asdasd = s => s.SubmissionId==1; 
 SettingsRepository.Setup(
     r =>
     r.GetAll(
         It.Is<Expression<Func<Settings, bool>>>(asdasd),
         It.IsAny<Func<IQueryable<Settings>, IOrderedQueryable<Settings>>>(),
         It.IsAny<Expression<Func<Settings, Object>>[]>()))
    .Returns(() => new[] { new Settings { Submission = ValidSubmission } });

Best regards, Angel

Edit: Thank you for the answers! Ilya Palkin, you are absolutely right! It should be something like this:

It.Is<Expression<Func<Settings,bool>>>(ex=>ex == null)

"ex" points to expression, that I'm supposed to pass as an argument, right? And the lambda expression is delegate from the type that you predicted. Now it's working!

 SettingsRepository.Setup(
     r =>
     r.GetAll(
         It.Is<Expression<Func<Settings,bool>>>(ex=>ex == null),
         It.IsAny<Func<IQueryable<Settings>, IOrderedQueryable<Settings>>>(),
                It.IsAny<Expression<Func<Settings, Object>>[]>()))
                          .Returns(() =>
                              {
                                  ValidSettings.Submission = ValidSubmission;
                                  return new[] { ValidSettings };
                              });

        SettingsRepository.Setup(
           r =>
           r.GetAll(
               It.Is<Expression<Func<Settings, bool>>>(ex => ex != null),
               It.IsAny<Func<IQueryable<Settings>, IOrderedQueryable<Settings>>>(),
               It.IsAny<Expression<Func<Settings, Object>>[]>())).Returns(new Settings[0]);

Now, on invocation, the method will return different things accordingly to the value of arguments in use.


I'm going back to the theme with another related question, that arise today among my colleagues and here it is:

  • Like example above, we have stubbed SettingsRepository object;

  • Is it possible to setup a mock object on that way, so if you pass one very specific lambda to return some predefined collection, otherwise empty collection;

e.g. If I say: SettingsRepository.Object.GetAll(x=>x.Id==3,...,...)-> I want to obtain predefined collection and if I say: SettingsRepository.Object.GetAll(x=>x.Id==4,...,...) -> empty collection. It is easy feasible with simple types like int and string, but with expressions??

You can control reactions of the mock by passing lambda on the It.Is() or It.IsAny() methods. It.Is<Expression<Func<Settings,bool>>>(x=>*what to do with "x"*) , "x" points to Expression<Func<...>> and now I have to specify the condition, but what it should be?

If I was using int I would do it like this:

mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true);
Hornbill answered 14/10, 2013 at 14:46 Comment(8)
Your code should not work. A variable 'asdasd' should be of type Func<Expression<Func<Settings, bool>>, bool>Hinton
I don't think moq does parameterized lambda expression normalisation.Rone
Raj, I'm sorry, but I don't understand your post. I entered in programming world just before 1 year and I need a little more explanation about what you are talking about. Maybe you can tell me the same thing with simpler words :) Could you look at edited post above. Thank you!Hornbill
Sorry @Hornbill should have explained bit more. What I meant was Moq dislike having variables in lambada expressions. i,e stub.Setup(x => x.Get((y) => true)).Returns("foo"); To a call like this the SUT would return null. It cannot normalise those expression . However Moq is able to produce the desired expression if you were to wrap them in lambdas expressions with It.IsAny<>() or It.Is<>() type expressions, which you have already done in your solution. i,e stub.Setup(x => x.Get(It.IsAny<Expression<Func<int, bool>>>())).Returns("foo");Rone
It looks like you have found your solution. But remember that instead of It.Is<Expression<Func<Settings,bool>>>(ex=>ex == null) you can simply use null, that is just use the simple value null as the first argument to GetAll inside your Setup.Unstrung
Check my answer to similar question: https://mcmap.net/q/1630021/-setup-and-verify-expression-with-moqThallic
Thank you very much, to all of you!Hornbill
Possible duplicate of Setup and verify expression with MoqMarvelous

© 2022 - 2024 — McMap. All rights reserved.