Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock result from Func with NSubstitute

I'm trying to use NSubstitute to mock the return value from a Substitute, but I cannot get the substitute to return the correct value because the method signature is using a Func.

I've seen these questions, but cannot make it work with my Func.

Mocking Action<T> with NSubstitute

Mocking out expression with NSubstitute

The interface I try to mock is this (somewhat simplyfied):

public interface IOrgTreeRepository<out T> where T : IHierarchicalUnit
{
    T FirstOrDefault(Func<T, bool> predicate);
}

I'm substituting it with NSubstitute like so:

_orgTreeRepository = Substitute.For<IOrgTreeRepository<IOrganizationUnit>>();

And then I try to change the return value like so:

_orgTreeRepository.FirstOrDefault(Arg.Is<Func<IOrganizationUnit, bool>>(x => x.Id== _itemsToUpdate[0].Id)).Returns(existingItems[0]);

But it simply returns a proxy-object instead of my defined object in existingItems.

However, thanks to the other questions I managed to get this to work, but it does not help me, since I need a specific item every time.

_orgTreeRepository.FirstOrDefault(Arg.Any<Func<IOrganizationUnit, bool>>()).Returns(existingItems[0]); // Semi-working

I guess it's treating the lambda expression as a kind of absolute reference and therefore skips it? Is there any way I can mock the return value?

like image 429
smoksnes Avatar asked Oct 08 '15 13:10

smoksnes


People also ask

How do we set a return value for a method call on a substitute?

To set a return value for a method call on a substitute, call the method as normal, then follow it with a call to NSubstitute's Returns() extension method. var calculator = Substitute. For<ICalculator>(); calculator. Add(1, 2).

What is NSubstitute?

NSubstitute is a friendly substitute for . NET mocking libraries. It has a simple, succinct syntax to help developers write clearer tests. NSubstitute is designed for Arrange-Act-Assert (AAA) testing and with Test Driven Development (TDD) in mind.


1 Answers

As you correctly guessed, NSubstitute just uses reference equality here, so unless you have a reference to the same predicate (which is sometimes an option) then you'll have to match any call (Arg.Any or .ReturnsForAnyArgs) or use an approximate form of matching to check the function passed in.

An example of approximate matching:

[Test]
public void Foo() {
    var sample = new Record("abc");
    var sub = Substitute.For<IOrgTreeRepository<Record>>();
    sub.FirstOrDefault(Arg.Is<Func<Record,bool>>(f => f(sample))).Returns(sample);

    Assert.AreSame(sample, sub.FirstOrDefault(x => x.Id.StartsWith ("a")));
    Assert.AreSame(sample, sub.FirstOrDefault(x => x.Id == "abc"));
    Assert.Null(sub.FirstOrDefault(x => x.Id == "def"));
}

Here we've stubbed FirstOrDefault to return sample whenever the Func<T,bool> returns true for sample (this is using a different overload of Arg.Is which takes an expression, rather than the value of the argument passed in).

This passes the test for two different predicates, because sample satisfies both of them. It also passes the last assertion, in that it doesn't return sample for a func that checks for a different id. We can't guarantee a specific predicate was used in this case, but it might be enough. Otherwise we're stuck with reference quality on the Func.

Hope this helps.

like image 78
David Tchepak Avatar answered Oct 18 '22 21:10

David Tchepak