Skip to content

Combine mock and fluent asserts for detailed testing feedback

Notifications You must be signed in to change notification settings

marctalary/MoqFluentAssertions

Repository files navigation

MoqFluentAssertions

Combine Moq and Fluent Assertions for detailed testing feedback and comparison capabilities.

Its.EquivalentTo

Usage:

booMock.Verify(b => b.ItWorked(Its.EquivalentTo(barParam)));

Usage when equivalent check is between two different types:

booMock.Verify(b => b.ItWorked(Its.EquivalentTo<BarParam, FooParam>(fooParam)));

This gives rich feedback on failure courtesy of the FluentAssertions.ShouldBeEquivalentTo method used to implement it.

Expected member Description to be
"expected description" with a length of 20, but
"actual description" has a length of 18.
Expected member ReferenceNumber to be 12345, but found 54321.

However using this method has major drawbacks. It works by throwing an Exception with the test message and so fails the test whenever it is given an object that isn't equivalent, even when used in a Moq.Setup.

By contrast the behavior of the Moq.It.Is() method takes an expression which returns true or false for each object given and then, if they are all false the Moq.Verify fails the test by throwing a MockExpcetion or when used in a Moq.Setup statement does not evoke the statements expression usually a Return.

Therefore it is never advisable to use Its.EquivalentTo in setups and only useful in Moq.Verify when you only have a single verify for the method signature.

To get around this there is an AllowMultipleSetups parameter.

AllowMultipleSetups

Usage:

booMock.Verify(b => b.ItWorked(Its.EquivalentTo(barParam, true)));

Usage when equivalent check is between two different types:

booMock.Verify(b => b.ItWorked(Its.EquivalentTo<BarParam, FooParam>(fooParam, true)));

The AllowMultipleSetups parameter defaults to false but when true does the FluentAssertions.ShouldBeEquivalentTo comparison but instead of failing the test on first non-equivalent object implements the same behavior as Moq.It.Is().

You lose the rich feedback from FluentAssertions but gain the capability of using Its.EquivalentTo anywhere you would have used Moq.It.Is().

In the example below the test would have failed on the foo.CallBoo(fooParam); statement as all of the Moq.setup statements are checked when applicable and the second Its.EquivilentTo would have ended the test.

By passing allowMultipleSetups: true the call will only fail if there are no relevant Moq.Setup statements.

var fooParam = new FooParam
{
    Description = "given value 1", ReferenceNumber = 12345
};
var fooParam2 = new FooParam
{
    Description = "given value 2", ReferenceNumber = 23456
};
var expectedBarParam = new BarParam
{
    Description = fooParam.Description, ReferenceNumber = fooParam.ReferenceNumber
};
var expectedBarParam2 = new BarParam
{
    Description = fooParam2.Description, ReferenceNumber = fooParam2.ReferenceNumber
};

booMock.Setup(b => b.ItWorked(Its.EquivalentTo(expectedBarParam, allowMultipleSetups: true)));
booMock.Setup(b => b.ItWorked(Its.EquivalentTo(expectedBarParam2, allowMultipleSetups: true)));
foo.CallBoo(fooParam);
foo.CallBoo(fooParam2);

Other Implementations

Using the MatcherAttribute there are other implementations of the same functionality. The AllowMultipleSetups option is set to true and not provided as an override as it gives different behaviour than the standard It methods.

Not sure which is better but I'm leaning towards It<T> extensions.

It<T>.IsEquivalentTo

booMock.Verify(b => b.ItWorked(It<BarParam>.IsEquivalentTo(expectedFooParam)), Times.Once);

_It.IsEquivalentTo

booMock.Verify(b => b.ItWorked(_It.IsEquivalentTo(expectedBarParam)));

About

Combine mock and fluent asserts for detailed testing feedback

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages