-
Notifications
You must be signed in to change notification settings - Fork 277
Description
Sorry if this has already been requested, I looked through the issues and couldn't see one for the suggestion. Also great job on NSubstitute it's a great package!
Is your feature request related to a problem? Please describe.
When using argument matchers to assert a call has been made, it would be great if it would surface results from assertion frameworks. For example when using FluentAssertions or AwesomeAssertions:
[Test]
public void MyTest()
{
// Arrange
var target = Substitute.For<IClassUnderTest>();
var complexObject = new ComplexObject();
// Act
target.DoWork(complexObject);
// Assert
target.Received(1).DoWork(Arg.Is<ComplexObject>(o => AssertOnComplexObject(o));
}
private bool AssertOnComplexObject(ComplexObject o)
{
o.Should().BeEquivalentTo(complexObject);
return true;
}the assertion raises an AssertionException and test does fail, but the help description from the NSubstitute Argument Matcher is not very helpful and doesn't contain any of the details within the exception. This is the following information it receives:
NSubstitute.Exceptions.ReceivedCallsException : Expected to receive exactly 1 call matching:
DoWork(o => AssertOnComplexObject(o))
Actually received no matching calls.
Received 1 non-matching call (non-matching arguments indicated with '*' characters):
DoWork(*ComplexObject*)
Describe the solution you'd like
I would like the rich error information from the assertion framework surfaced. It could be a change to the error message to surface exceptions within the Arg.Is call. For example, adding:
NUnit.Framework.AssertionException:
Expected property Value1 to be 887, but found 0.
Expected property Value2 to be "My Value", but found <null>.
Expected property Currency to be "USD", but found <null>.
Another alternative could be to add an Arg.Is method that accepts just an Expression<T> rather than an Expression<Predicate<T>>. That way the previous behaviour is backwards compatible, but the new one lets the developer setup the assertion. For example:
[Test]
public void MyTest()
{
// Arrange
var target = Substitute.For<IClassUnderTest>();
var complexObject = new ComplexObject();
// Act
target.DoWork(complexObject);
// Assert
target.Received(1).DoWork(Arg.Assert<ComplexObject>(o => o.Should().BeEquivalentTo(complexObject));
}I do understand something like this is harder with the scemantics of Recieved, where it's trying to match to any number of calls, not sure how to get around that, maybe with RecievedOnly, or even .Recieved(target => target.DoWork(Arg.Is...)
Describe alternatives you've considered
Alternatives include setting up a When().Do() phrase, but then the test doesn't read as Arrange Act Assert, but rather as Arrange, Setup Assert, Act. Also if the DoWork is called within another class with error handling, then the AssertionException is squashed and the test passes.
Additional context
If we settle on an idea I'm happy to help implement it