DEV Community

Cover image for SparkyTestHelpers: Moq
Brian Schroer
Brian Schroer

Posted on • Edited on

SparkyTestHelpers: Moq

SparkyTestHelpers.Moq:
NuGet package | Source code | API documentation
SparkyTestHelpers.Moq.Fluent:
NuGet package | Source code | API documentation

I really like Moq, “the most popular and friendly mocking framework for .NET”, but I find some of the syntax to be a bit unwieldy.

The SparkyTestHelpers.Moq and SparkyTestHelpers.Moq.Fluent NuGet packages provide extension methods that allow you to use Moq with “wieldier” (Is that a word?) syntax.

SparkyTestHelpers.Moq.Fluent uses Fluent Assertions to provide a more natural language-like verification syntax. If you don't want that dependency, you can use SparkyTestHelpers.Moq. I'll discuss the verification syntaxes below, but both packages provide alternate "Any" syntax and the .Where and .Expression extension methods...

“Any” - Syntax alternative to “It.IsAny”

mock.Setup(x => x.DoSomething(
    It.IsAny<string>(), It.IsAny<int>(), It.IsAny<IEnumerable<int>>())
    .Returns(true);
Enter fullscreen mode Exit fullscreen mode

…can be simplified to:

using SparkyTestHelpers.Moq;
. . .
mock.Setup(x => x.DoSomething(
    Any.String, Any.Int, Any.IEnumerable<int>()) 
    .Returns(true);
Enter fullscreen mode Exit fullscreen mode

“Any” members:

  • Any.Boolean
  • Any.DateTime
  • Any.Decimal
  • Any.Double
  • Any.Int
  • Any.Object
  • Any.String
  • Any.InstanceOf<T>()
  • Any.Array<T>()
  • Any.IEnumerable<T>()
  • Any.List<T>()
  • Any.Dictionary<TKey, TValue>
  • Any.KeyValuePair<TKey, TValue>
  • Any.Tuple<T1, T2>
  • (several more members for all of the intrinsic .NET types)

mock.Where extension method

…provides an alternate syntax for “It.Is”:

mock.Setup(x => x.Foo(It.Is<int>(i => i % 2 == 0))).Returns(true);
Enter fullscreen mode Exit fullscreen mode

...can be written as:

mock.Setup(x => x.Foo(Any.Int.Where(i => i % 2 == 0))).Returns(true);
Enter fullscreen mode Exit fullscreen mode

mock.Expression extension method

…makes it easy to create a reusable expression so you don’t duplicate code in “.Setup” and “.Verify” calls. This test:

// Arrange:
_mock.Setup(x => 
    x.Foo(Any.String, Any.Int, Any.InstanceOf<Bar>()))
    .Returns(true);

// Act:
subjectUnderTest.Fooify("yo", 5, myBar);

//Assert:
_mock.VerifyOneCallTo(x => 
    x.Foo(Any.String, Any.Int, Any.InstanceOf<Bar>()));
Enter fullscreen mode Exit fullscreen mode

…where you have to code the same “x => x.Foo(
Any.String, Any.Int, Any.InstanceOf()
” expression for both the .Setup and .Verify calls — can be simplified to:

using SparkyTestHelpers.Moq;
. . .
// Arrange:
var fooExp = _mock.Expression(x => 
    x.Foo(Any.String, Any.Int, Any.InstanceOf<Bar>()));

_mock.Setup(fooExp).Returns(true);

// Act:
subjectUnderTest.Fooify("yo", 5, myBar);

// Assert:
_mock.VerifyOneCallTo(fooExp);
Enter fullscreen mode Exit fullscreen mode

…so you only have to code the expression once, reducing finger fatigue and the possibility of the Setup and Verify expressions not matching because of a typo!


Alternate Verify syntax with SparkyTestHelpers.Moq.Fluent

The “out of the box” Moq syntax:

mock.Verify(x => x.Foo());
mock.Verify(x => x.Foo(), Times.Once);
mock.Verify(x => x.Foo(), Times.AtLeastOnce);
mock.Verify(x => x.Foo(), Times.AtMostOnce);
mock.Verify(x => x.Foo(), Times.Exactly(3));
mock.Verify(x => x.Foo(), Times.Between(2, 5));
mock.Verify(x => x.Foo(), Times.AtLeast(2));
mock.Verify(x => x.Foo(), Times.AtMost(5));
mock.Verify(x => x.Foo(), Times.Never);
Enter fullscreen mode Exit fullscreen mode

…can be coded fluently as:

mock.Should().HaveCallsTo(x => x.Foo());
mock.Should().HaveOneCallTo(x => x.Foo());
mock.Should().HaveAtLeastOneCallTo(x => x.Foo());
mock.Should().HaveAtMostOneCallTo(x => x.Foo());
mock.Should().HaveCallCount(3).To(x => x.Foo());
mock.Should().HaveCallCount(2, 5).To(x => x.Foo());
mock.Should().HaveCallCount(2).OrMore().To(x => x.Foo());
mock.Should().HaveCallCount(5).OrLess().To(x => x.Foo());
mock.Should().NoCallsTo(x => x.Foo());
Enter fullscreen mode Exit fullscreen mode

…or:

mock.Method(x => x.Foo()).Should().HaveBeenCalled();
mock.Method(x => x.Foo()).Should().HaveBeenCalledOnce();
mock.Method(x => x.Foo()).Should().HaveBeenCalledAtLeastOnce();
mock.Method(x => x.Foo()).Should().HaveBeenCalledAtMostOnce();
mock.Method(x => x.Foo()).Should().HaveCallCount(3);
mock.Method(x => x.Foo()).Should().HaveCallCountBetween(2, 5);
mock.Method(x => x.Foo()).Should().HaveCallCountOfAtLeast(2);
mock.Method(x => x.Foo()).Should().HaveCallCountOfAtMost(5);
mock.Method(x => x.Foo()).Should().NotHaveBeenCalled();
Enter fullscreen mode Exit fullscreen mode

There are property Get and Set equivalents for all of the “.Method … .Should… .HaveBeen” methods listed above, e.g.:

mock.Get(x => x.Bar).Should().HaveBeenCalledOnce();
mock.Set(x => x.Bar = "Baz").Should().HaveBeenCalledOnce();
Enter fullscreen mode Exit fullscreen mode

Alternate Verify syntax with SparkyTestHelpers.Moq

_mock.Verify(x => x.Foo("bar", 3), Times.Once);
Enter fullscreen mode Exit fullscreen mode

…can be coded as:

using SparkyTestHelpers.Moq;
. . .
_mock.VerifyOneCallTo(x => x.Foo("bar", 3));
Enter fullscreen mode Exit fullscreen mode

mock.Verify… extension methods:

  • mock.VerifyCallCount(int count, expresssion)
  • mock.VerifyOneCallTo(expression)
  • mock.VerifyAtLeastOneCallTo(expression)
  • mock.VerifyAtMostOneCallTo(expression)
  • mock.VerifyNoCallsTo(expression)
  • mock.VerifyGetCount(int count, expresssion)
  • mock.VerifyOneGet(expression)
  • mock.VerifyAtLeastOneGet(expression)
  • mock.VerifyAtMostOneGet(expression)
  • mock.VerifyNoGets(expression)
  • mock.VerifySetCount(int count, expresssion)
  • mock.VerifyOneSet(expression)
  • mock.VerifyAtLeastOneSet(expression)
  • mock.VerifyAtMostOneSet(expression)
  • mock.VerifyNoSets(expression)

Happy Testing!

Top comments (0)