How to write Mocking Tests using xUnit and Moq

In this article, let's understand why Faking Tests are not efficient and how we can use Moq framework to create Mocking Tests in xUnit

In a previous article we have seen how to get started with writing unit tests in ASP.NET Core using xUnit. We have also seen an approach of faking required dependencies of a Unit under Test by means of interfaces and faking implementations in place of real world logic. while it is indeed a nice approach, it’s still tedious and not an elegant approach for unit testing any given component.

Why Faking Tests are Hard?

Faking a real implementation for unit testing is easy, provided when the implementation has lesser functionalities to fake. For example, let’s say we have a dependency class for a component for which we are interested in writing unit tests and this class contains around 30 to 40 methods of different purposes (say they all serve the same responsibility though). In order to fake this dependency class, we extract an interface and try faking each and every method of that interface in our own fake class for a simple reason of passing in a fake object, it doesn’t seem simple or useful in any case.

How to write Mocking Tests

While fakes have such shortcomings, an elegant alternative for such scenarios would be to create a mock implementation, instead of a fake implementation. A mock object is yet another normal object of the declared type, but with a provision to send out a specific response whenever a specific inputs are given. For example, we can program a mock object to always return true for a method when called with two integer parameters. This results in a simpler and faster way of arranging dependencies for unit tests. There are several mocking frameworks available such as Moq, Mockito, EasyMock and many such which get the job done in an easiest way possible. In our case, we use Moq, a simple and lightweight mocking framework for mocking in asp.net core.

“Moq is intended to be simple to use, strongly typed (no magic strings!, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional!).” – Moq

Moq framework can be added to our project by running the below command using dotnet CLI:

dotnet add package Moq --version 4.13.1

and then importing it in our class:

using Moq;

Hands-on : returning to the ReaderController

Let’s return to our previous example of ReaderController class, which requires a dependency of type IReaderRepo, and we are interested in testing the unit of function GetReaders() method for a give n initial. We have previously implemented a fake class FakeReaderRepo and passed it as an argument while arranging for the test. Let’s replace the fake with a moq implementation for the same.

How to create a Mock

Creating a moq object involves three steps:

1. Create a moq object
2. Setup or program the returnables
3. Use the object when required

In our example, let’s create a moq object for the type IReaderRepo, which needs an implementation for the method GetAllReaders(). It can be done as follows:

// 1. Create moq object
var readerRepoMoq = new Moq<IReaderRepo>();

// 2. Setup the returnables
readerRepoMoq
.Setup(o => o.GetAllReaders(It.IsAny<string>()))
.Returns(new List<Reader>() {
			new Reader {
				Id = 1001,
				Name = "Mr.A",
				Initial = "A"
			}
		});

Let’s observe each step one-by-one. In step 1, we create a new mock object readerRepoMoq of type IReaderRepo by newing up a Moq instance with a type passed. Next, we invoked Setup function on the object which takes a lambda function as argument and in that we defined what is the function that the setup is meant for, in this case GetAllReaders() method. We have also passed a function It.IsAny<string>() as an argument. This is to refer that we are setting this function for any passed value of type string as parameter. Then we attach a mock return by Returns() method which has a lambda return of whatever value we need to return.

Tip: Generally for class level dependencies, we end up repeating the same mocking code in every function to test, and in such cases its best to put all of the mocking logic into a separate function and call it whenever necessary.

Our test function now simplifies as:

public class ReaderController_UnitTests 
{
	IReaderRepo readerRepo;

	private void SetupMocks() 
	{
		// 1. Create moq object
		var readerRepoMoq = new Moq<IReaderRepo>();

		// 2. Setup the returnables
		readerRepoMoq
		.Setup(o => o.GetAllReaders(It.IsAny<string>()))
		.Returns(new List<Reader>() {
			new Reader {
				Id = 1001,
				Name = "Mr.A",
				Initial = "A"
			}
		});

		// 3. Assign to Object when needed
		readerRepo = readerRepoMoq.Object;
	}
	
	[Fact]
	public void GetReadersWhenCalledReturnListOfReaders()
	{
		//Arrange the resources
		SetupMocks();
		var controller = new ReadersController(readerRepo);
		string initial = "A";

		//Act on the functionality
		List<Reader> response = controller.GetAllReaders(initial);

		//Assert the result against the expected
		Assert.True(response.Count() > 0);
	}
}

In the above arrangement, we call a function SetupMocks() which encapsulates repeatable logic to create a mock implementation of IReaderRepo, which then is passed on to the actual unit under test. Observe that we call readerRepoMoq.Object which returns an object of type IReaderRepo with programmed mock logic to return a list of Reader objects when called.

While this approach is simple, it also helps in TDD (Test Driven Development), particularly when we write unit tests for a yet-to-be-implemented logic in our applications.


Buy Me A Coffee

Found this article helpful? Please consider supporting!

Ram
Ram

I'm a full-stack developer and a software enthusiast who likes to play around with cloud and tech stack out of curiosity. You can connect with me on Medium, Twitter or LinkedIn.

Leave a Reply

Your email address will not be published. Required fields are marked *