Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verifying a call parameter via a callback in NSubstitute

I have a failing test in NSubstitute because a parameter passed in to a substituted call does not match. Here is the relevant code that is being tested:

// Arrange
PermissionsProviderSub = Substitute.For<IPermissionsProvider>();
MenuDataProviderSub = Substitute.For<IMenuDataProvider>();
PermissionsProviderSub.GetPermissions(UserId).Returns(ExpectedUserPermissions);
MenuDataProviderSub.GetMenuData(ExpectedUserPermissions.AuthorisedPageIds).Returns(Arg.Any<IList<BusinessFocusArea>>());            
var sut = new MenuViewModelFactory(MenuDataProviderSub, PermissionsProviderSub);

// Act
var result = sut.Create();

// Assert
MenuDataProviderSub.Received().GetMenuData(ExpectedUserPermissions.AuthorisedPageIds);

The problem occurs in the ExpectedUserPermissions.AuthorisedPageIds property, which looks like this:

public IEnumerable<string> AuthorisedPageIds
{
    get
    {
        return ApplicationPagePermissions != null ? 
            ApplicationPagePermissions.Select(permissionSet => permissionSet.PageId) :
            Enumerable.Empty<string>();
    }
}

As you can see, there is a LINQ Select, which is extracting the PageId property from within the ApplicationPagePermissions collection and returning it as an IEnumerable<string>. Because the projection within that property creates a new object, the substitution does not match, as it sees the 2 objects as being different.

Can I create a callback on the parameter passed in to GetMenuData so that I can examine the value of it?

The documentation on NSubstitute callbacks only talks about examining the return value from a call, rather than a parameter passed into the call.

like image 764
levelnis Avatar asked Feb 22 '13 14:02

levelnis


1 Answers

Typical. As soon as I post to SO, the answer presents itself. Rather than expecting a specific object when creating the substitute call, I expect any instance of type IEnumerable<string> and create a callback when checking the Received() call that actually verifies the values. The substitute call becomes this:

MenuDataProviderSub.GetMenuData(Arg.Any<IEnumerable<string>>()).Returns(Arg.Any<IList<BusinessFocusArea>>());            

The Received() check becomes this:

MenuDataProviderSub.Received().GetMenuData(Arg.Is<IEnumerable<string>>(a => VerifyPageIds(ExpectedUserPermissions.AuthorisedPageIds, a)));

private static bool VerifyPageIds(IEnumerable<string> expected, IEnumerable<string> actual)
{
    var expectedIds = expected.ToList();
    var actualIds = actual.ToList();
    return expectedIds.Count == actualIds.Count && expectedIds.All(actualIds.Contains);
}
like image 50
levelnis Avatar answered Oct 05 '22 23:10

levelnis