Please take a look at the following sample:
public interface IDomainClass
{
int A { get; set; }
void CalledMethod(IDomainClass data);
}
public class DomainClass : IDomainClass
{
public int A { get; set; }
public void CalledMethod(IDomainClass data)
{
throw new NotImplementedException();
}
}
And the following test:
[Test]
public void TestSample()
{
//Arrange
IDomainClass testingClass = Substitute.For<IDomainClass>();
IDomainClass data = new DomainClass() { A = 123, };
IDomainClass expectedResult = new DomainClass() { A = 123, };
//Act
testingClass.CalledMethod(data);
//Assert
testingClass.ReceivedWithAnyArgs(1).CalledMethod(null); //ok
data.ShouldBeEquivalentTo(expectedResult); //ok
testingClass.Received(1).CalledMethod(expectedResult); //fail
}
The problem is that I don't know how to test the arguments in the received call (CallMethod). As it is, the arguments is compared using first object.ReferenceEquals and then object.Equals, and since I usually don't have control over the delivered data to the method, the objects (data and expectedResult) never references the same object.
However, there is a way to make it work, and that is if I override Equals, like this:
public override bool Equals(object obj)
{
return this.A.Equals((obj as DomainClass).A);
}
public override int GetHashCode()
{
return this.A.GetHashCode();
}
This will work, but I don't want to implement Equals to satisfy a test since it will have all kind of other implications not worth mentioning here.
What I want is a comparer doing the same a the second assert line:
data.ShouldBeEquivalentTo(expectedResult);
But this is not supported per default.
So, how do I solve this problem. Thank you.
NSubstitute doesn't have fully-baked support for this at the moment (v1.10). Issue 160 has some discussion of this.
One option as David Osborne mentioned is to catch the arguments and assert on them using your assertion library of choice.
Another is to use a custom argument matcher. I've included an example from this comment:
[Test]
public void UsingArgMatcher() {
var repos = Substitute.For<IRepos>();
var sut = new SomeService(repos);
sut.Process();
repos.Received().Save(Arg.Is(EquivalentTo(new int[] { 1, 2, 3 })));
}
private Expression<Predicate<IEnumerable<T>>> EquivalentTo<T>(IEnumerable<T> enumerable) {
return x => Equiv(enumerable, x);
}
private bool Equiv<T>(IEnumerable<T> a, IEnumerable<T> b) { ... }
As described in the comment, this works but has problems with providing a pretty terrible error message when it fails.
There is also an example of hooking NSubstitute up to FluentAssertions.
You can store what's passed and then compare later:
[Test]
public void TestSample()
{
//Arrange
IDomainClass testingClass = Substitute.For<IDomainClass>();
IDomainClass data = new DomainClass() { A = 123, };
IDomainClass methodReceievedThis = null;
testingClass
.When(t => t.CalledMethod(Arg.Any<IDomainClass>())
.Do(p => methodReceievedThis = p);
//Act
testingClass.CalledMethod(data);
//Assert
testingClass.ReceivedWithAnyArgs(1).CalledMethod(null); //ok
methodReceievedThis.ShouldBeEquivalentTo(data);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With