I’m a stickler for code that is short, concise, and easy to read. I try to not miss an opportunity to refactor code into a shared method, or even better, an extension method. Unit test code is no different. Since properly written unit tests become the defacto documentation for a class, it is important for them to be as clean and legible as possible. That way a new developer can easily and quickly figure out what is going on.

To that end, I will to share with you some techniques I use to make .NET unit test mocks more readable while remaining composable. I’ll be using the excellent mocking framework, Moq. Our example happens to be using .NET Core with Xunit, but this can easily apply to classic .NET with NUnit.

Here is an example of a mock that expects a method invocation with certain parameters and returns a result. The system under test is a login controller that depends on an user service for authentication. Like Good Programmers™, we use dependency injection to inject a type implementing a IUserService interface. This allows us to pass in a mock implementation for testing purposes.*

[Fact]

public void Login_With_Success_Returns_User

{

//Arrange

var userId = Guid.NewGuid();

var username = "foo";

var password = "bar";

var user = new User { Id = userId }; var mockUserService = new Mock<IUserService>();



mockUserService.Setup(x => x.Authenticate(

It.Is<string>(i => i == username),

It.Is<string>(i => i == password)

)).Returns(userId);



mockUserService.Setup(x => x.GetUserById(

It.Is<Guid>(i => i == userId),

)).Returns(user); //Act

var loginController = new LoginController(mockUserService.Object);

var output = loginController.Login(username, password); //Assert

Assert.Equal(output, user);

mockUserService.VerifyAll();

}

In this example, we are verifying that the Login method invokes the user service twice: Once to authenticate the same username and password and once to query for the user object. Then we assert that the User object we get back from the method matches the one we expect.

Moq is a great tool but you have to admit that this code is pretty ugly. Multiple nested lambda expressions with lots of parentheses are hard to read. If you are setting up multiple mocks in a test method, it gets pretty verbose. Even worse, if you use the same mocks in multiple tests methods you end up repeating this setup code in each test!

Not feeling satisfied with this, I tried using a simple Factory Pattern to encapsulate the creation of a pre-configured mock:

Take 1: Factory pattern

public static class UserServiceMocks

{

public static Mock<IUserService> MockAuthenticateAndGetUserById(string username, string password, Guid userId, User output)

{

var mock = new Mock<IUserService>();



mock.Setup(x => x.Authenticate(

It.Is<string>(i => i == username),

It.Is<string>(i => i == password)

)).Returns(userId);



mock.Setup(x => x.GetUserById(

It.Is<Guid>(i => i == userId),

)).Returns(output);



return mock;

}

}

However, I really didn’t like how both methods were being set up within the same factory method. It felt unnatural and arbitrary. It was hard to even name this mega method, which is a definite code smell. This approach may be ok for individual method mocks, but breaks down when multiple ones are required.

Instead of a static mock factory, let’s try to create a new class that inherits from the user service mock, with individual methods for each setup method:

Take 2: Inheritance

public class MockUserService : Mock<IUserService>

{

public void MockAuthenticate(string username, string password, Guid output)

{

Setup(x => x.Authenticate(

It.Is<string>(i => i == username),

It.Is<string>(i => i == password)

)).Returns(output);

} public void MockGetUserById(Guid userId, User output)

{

Setup(x => x.GetUserById(

It.Is<Guid>(i => i == userId),

)).Returns(output);

}

}

Now in our unit test we can set up the mock like this:

[Fact]

public void Login_With_Success_Returns_User

{

//Arrange

var userId = Guid.NewGuid();

var username = "foo";

var password = "bar";

var user = new User { Id = userId }; var mockUserService = new MockUserService();

mockUserService.MockAuthenticate(username, password, output: userId);

mockUserService.MockGetUserById(userId, output: user); //Act

var loginController = new LoginController(mockUserService.Object);

var output = loginController.Login(username, password); //Assert

Assert.Equal(output, user);

mockUserService.VerifyAll();

}

Much cleaner! Note that we also take advantage of C# named parameters to make the output parameter separate from the input parameters. We can make this code even better by adopting a Fluent API. A fluent API is simply one that returns the current instance in instance methods instead of just returning void, which enables method chaining.

Take 3: Fluent API

public class MockUserService : Mock<IUserService>

{

public MockUserService MockAuthenticate(string username, string password, Guid output)

{

Setup(x => x.Authenticate(

It.Is<string>(i => i == username),

It.Is<string>(i => i == password)

)).Returns(output);

return this;

} public MockUserService MockGetUserById(Guid userId, User output)

{

Setup(x => x.GetUserById(

It.Is<Guid>(i => i == userId),

)).Returns(output);

return this;

}

}

So now our unit test code becomes:

[Fact]

public void Login_With_Success_Returns_User

{

//Arrange

var userId = Guid.NewGuid();

var username = "foo";

var password = "bar";

var user = new User { Id = userId }; var mockUserService = new MockUserService()

.MockAuthenticate(username, password, output: false)

.MockGetUserById(userId, output: user); //Act

var loginController = new LoginController(mockUserService.Object);

var output = loginController.Login(username, password); //Assert

Assert.Equal(output, user);

mockUserService.VerifyAll();

}

Much cleaner and readable! Plus, this approach is completely composable so you can combine mocked methods with the same flexibility as in the original example.

So there you have it, an easy way to make your Moq setups cleaner and more reusable across different test methods and classes. Enjoy!

*Moq allows mocking of classes as well as interfaces, but it’s still wise to code to interfaces to reduce coupling between classes.