Skip to content

Instantly share code, notes, and snippets.

@ColinScott
Created March 9, 2014 05:22
Show Gist options
  • Save ColinScott/9443227 to your computer and use it in GitHub Desktop.
Save ColinScott/9443227 to your computer and use it in GitHub Desktop.
Adding ExpectedObjects to NSubstitute
This adds a new Arg.ShouldMatch<T> method that uses expected objects to verify the received argument matches the expected object. For example the code below gives an error message of "ReceivedCallsException: Expected to receive exactly 1 call matching:
Blah(For Thing.Stuff, expected "Whatever2" but found "Whatever".
For Thing.OtherStuff, expected "abcd2" but found "abcd".
)
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
Blah(*Thing*)"
void Main()
{
var blah = Substitute.For<IBlah>();
blah.Blah(new Thing { Stuff = "Whatever", OtherStuff = "abcd" });
blah.Received(1).Blah(Arg.ShouldMatch<Thing>(new { Stuff = "Whatever2", OtherStuff = "abcd2" }));
}
public interface IBlah
{
void Blah(Thing thing);
}
public class Thing
{
public string Stuff { get;set; }
public string OtherStuff { get;set; }
}
@dtchepak
Copy link

I was originally intending to have something like this:

blah.Received(1).Blah(Arg.Is<Thing>(x => x.Stuff == "Whatever2" && x.OtherStuff == "abcd2"));

And then describe the failed match for each argument. Would that do what you wanted?

I spiked out some custom arg match stuff ages ago but we dropped that after it was suggested implementing custom matchers isn't what devs really want, they really want to specify their conditions and have the formatting of non-matches taken care of automatically. If you're really keen on custom matchers using ExpectedObjects or other I can look at reinstating that?

@ColinScott
Copy link
Author

What we have been doing is something like:

Model persistModel = null;

_repository.WhenForAnyArgs(r => r.Store(null))
.Do(info => persistModel = info.Arg<IList>().FirstOrDefault());

// Act

new
{
Id = _theId,
Thing = "something"
}.ToExpectedObject().ShouldMatch(persistModel);

This will tell us each individual property that doesn't match along with the expected value or indicate that the object is null (without a NullReferenceException). So 1 test can show all the issues in the data item at once. It's just really ugly to do it this way. It's also messy if I want to validate multiple items.

From your description I thing that your solution would work in the simpler cases. I'm not sure how effective it would be if the parameter is a collection where I want to validate properties on multiple entries. It might be better for some checks such as verifying that a collection item is of a specific type which Expected Objects doesn't seem to support.

Really the key point here is that the error message from what we're doing isn't just a "it failed", it lists everything that has failed which makes fixing things a lot easier. My real driver is to be able to do that without the When/Do overhead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment