1

New to NSubstitute and having trouble mocking the returns for method calls that take a predicate. For example I have this in the main code

var currReport = this.ClientRepo.Get<Report>(x => x.Uid == reportUid).FirstOrDefault();

I want to do something like this in my test

var parentReport = new Report(){Uid = request.ParentReportUid, Name = "Test"};
this.clientRepository.Get(Arg.Is<Expression<Func<Report, bool>>>(expr => Lambda.Eq(expr, i => i.Uid == request.ParentReportUid))).Returns(new List<Report>() { parentReport }.ToArray());

This is not working. I have confirmed that request.ParentReportUid matches the reportUid in the actual method call. But still it returns a null. If I switch to an Arg.Any then it returns the report, like this

 this.clientRepository.Get(Arg.Any<Expression<Func<Report, bool>>>()).Returns(new List<Report>() { parentReport }.ToArray());

This is the signature of the actual method I am trying to mock.

 T[] Get<T>(System.Linq.Expressions.Expression<Func<T, bool>> predicate = null);

Please advise. Thanks

Gotts
  • 2,274
  • 3
  • 23
  • 32
  • I think [this answer](https://stackoverflow.com/a/5658873/906) (excuse self promotion :)) covers what you need here. If not please let me know and I'll try to provide more information. – David Tchepak Jul 16 '19 at 02:59
  • Alternatively, [this answer](https://stackoverflow.com/a/6334749/906) is great if you don't need to check the actual predicate passed in. – David Tchepak Jul 16 '19 at 03:05

1 Answers1

1

Try to use NSubstitute class Arg public static T Is<T>(Expression<Predicate<T>> predicate) method. You did not specifed what is type X in your predicate.

I have invested some time and there is a already solution for it. It's a Neleus.LambdaCompare Nuget Package. You can use Lambda.Eq method. I have tried it and it worked fine. In your example it should be something like:

this.Repo.Get<Report>(Arg.Is<Expression<Func<Report, bool>>>(expr => Lambda.Eq(expr, i => i.ParentType == "1AType" && i.OwnerUid == 5))).Returns(reports);

Here is a example that I tried and the test ist green.This example match your signature.

public class ExpresionClass : IExpresionClass
{
    T[] IExpresionClass.Get<T>(Expression<Func<T, bool>> predicate)
    {
        throw new NotImplementedException();
    }
}

public interface IExpresionClass
{
    T[] Get<T>(Expression<Func<T, bool>> predicate = null);
}

public interface ITestClass
{
    Person[] GetPerson();
}

public class Person
    {
        public string ParentType { get; set; }

        public int OwnerUid { get; set; }
    }

public class TestClass : ITestClass
{
    private readonly IExpresionClass expressionClass;

    public TestClass(IExpresionClass expressionClass)
    {
        this.expressionClass = expressionClass;
    }

    public Person[] GetPerson()
    {
        var test = expressionClass.Get<Person>(x => x.ParentType == "1AType" && x.OwnerUid == 10);

        return test;
    }

}

[TestMethod]
    public void DoesLinqMatch()
    {
        var person = new Person();
        person.OwnerUid = 59;
        person.ParentType = "ParentType";

        Person[] personsarray = new Person[] { person };
        var expressionClass = Substitute.For<IExpresionClass>();
        expressionClass.Get(Arg.Is<Expression<Func<Person, bool>>>(expr => Lambda.Eq(expr, i => i.ParentType == "1AType" && i.OwnerUid == 10))).Returns(personsarray);

        var cut = new TestClass(expressionClass);
        var persons = cut.GetPerson();

        persons.First().ParentType.Should().Be("ParentType");
    }
Sead Avdic
  • 108
  • 1
  • 10
  • Doesnt work...i get CS1503 Argument 1: cannot convert from 'YOURTYPE' to 'System.Linq.Expressions.Expression>' – Gotts Jul 16 '19 at 11:30
  • Can you write the signature of you method Repo.Get? – Sead Avdic Jul 16 '19 at 12:28
  • If your Signature is Expression than you Arg must be Arg.Is>>. I will edit my answer so maybe that helps. – Sead Avdic Jul 16 '19 at 12:42
  • Thanks. It compiles now but unfortunately my code returns null even though its called the same Get with a matching predicate. Do you know for sure that these predicate specific substitutes actually work? – Gotts Jul 16 '19 at 18:42
  • 1
    You are right. In this situation it calles the wrong method overload. I will try to look into it. – Sead Avdic Jul 17 '19 at 09:14
  • 1
    @Gotts I think there is solution. I have edited my answer. Can you please try it and let me now if it had worked. – Sead Avdic Jul 18 '19 at 17:58
  • 1
    Looked really promising but unfortunately I still get a null when the calling code calls the method passing in the predicate :( Thanks for trying! – Gotts Jul 18 '19 at 21:28
  • I did a test project and I used similar example and it has worked. Can you send me exactly your signature of a method Repo.Get? – Sead Avdic Jul 18 '19 at 21:45
  • Try the example from the answer. – Sead Avdic Jul 18 '19 at 21:51
  • 1
    I added the signature to the bottom of my question – Gotts Jul 20 '19 at 21:36
  • @Gotts I have adjusted my example to match your signature and it works, my test is green. Can you try it. Maybe it is something else in your code that causes the problem. It would be nice to see that it works for you to. – Sead Avdic Jul 21 '19 at 08:38
  • 1
    thanks for all your efforts. I tried again but no luck. In case I am missing something obvious I have updated my question above to show the actual method call and test return that I am using. Maybe you can see something different. Dont get thrown off by the different names of ClientRepo - they are the same. – Gotts Jul 21 '19 at 12:34
  • I have quickly tried your example and I do not see anything obviously wrong.If you use my example and change it to your method call and signature it still works. Maybe you have not mocked repository correctly or problem is present in some other part of the code. Without more of your code I can't reproduce it. – Sead Avdic Jul 21 '19 at 13:21