How to use Moq for mocking objects with xUnit and .NET

Published: Monday 8 April 2024

We used the Moq mocking framework in an xUnit test project.

As a result, we can mock objects in unit tests for a .NET and C# project.

Mocking is important as it allows for testing code in isolation and to isolate code from its dependencies and focus on testing the code itself.

This tutorial will look at how we set up mocking as part of our unit tests.

Creating services

For this tutorial, we created an xUnit test project and a class library.

The xUnit project has a project reference to the class library and we are going to be mocking classes and interfaces from the class library as part of our unit tests.

The first step is to create to create the services and interfaces. Inside the class library, we'll create a ProductService class which will implement the IProductService interface. In-addition, we'll create an ICategoryService interface where the ProductService class will have a dependency for.

The ProductService class will have a GetProductCategory method. This will call the GetCategoryName method in the ICategoryService interface for getting the category name.

// ICategoryService.cs
public interface ICategoryService
{
	string GetCategoryName(int id);
}
// IProductService.cs
public interface IProductService
{
	string GetProductCategory(int id, int categoryId);
}
// ProductService.cs
public class ProductService : IProductService
{
	private readonly ICategoryService _categoryService;
	public ProductService(ICategoryService categoryService)
	{
		_categoryService = categoryService;
	}

	public string GetProductCategory(int id, int categoryId)
	{
		return _categoryService.GetCategoryName(categoryId);
	}
}

Mocking objects

With the objects set up, we can now mock them. To do that, we are now going to write some unit tests on the ProductService class.

In the xUnit test project, we need to add the Moq NuGet package to the xUnit project.

Add Moq to an xUnit test project through the NuGet package manager

Add Moq to an xUnit test project through the NuGet package manager

Once the package is installed, we can mock the objects.

In the xUnit test project, we are going to create a test class called ProductTests, and create a mock instance for the ProductService class and the ICategoryService interface.

This is done through importing the Moq assembly into the class and using the Mock class that comes with it.

As we want to use these instances for each test method, we are going to create the instances in the constructor and set the references to them in a private readonly field.

The Mock class comes with a generic type. This represents the type that we wish to mock.

As the ProductService class has a dependency on the ICategoryService interface, we pass in the ICategoryService instance as a parameter when creating the ProductService mock object. To ensure we are using the actual ICategoryService object reference and not the mock instance, we call the Object property from the mock instance.

Setup returns

In the GetProductCategory method in the ProductService class, there is a call to the GetCategoryName method in the ICategoryService interface. However, because the ICategoryService is only an interface, it only represents an implementation of the method and it will always return the default response.

To get around this, we can use the Setup method in Moq to call the method including any parameters and return a value.

// ProductTests.cs
using Moq;
using RoundTheCode.xUnitMock.Library;

public class ProductTests
{
	private readonly Mock<ProductService> _productServiceMock;
	private readonly Mock<ICategoryService> _categoryServiceMock;

	public ProductTests()
	{
		_categoryServiceMock = new Mock<ICategoryService>();
		_productServiceMock = new Mock<ProductService>(_categoryServiceMock.Object);

		_categoryServiceMock.Setup(s => s.GetCategoryName(1)).Returns("Games");
		_categoryServiceMock.Setup(s => s.GetCategoryName(2)).Returns("Computers");
	}
}

In this instance, if the GetCategoryName method in the ICategoryService interface passes in a parameter of 1, it will return a value of Games. Similarly, if it passes 2, it will return Computers.

Testing the mock objects

We can now write some unit tests to ensure that the mock objects are set up correctly.

We'll set up two test methods and both will call the GetProductCategory method in the ProductService. It will pass in 1 for both the Id and CategoryId parameters.

The first test will check whether the returned result is Games and the second test will check that the returned result is not Computers.

// ProductTests.cs
...
public class ProductTests
{
	...

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldReturnGames()
	{
		var productCategoryName = _productServiceMock.Object.GetProductCategory(1, 1);

		Assert.Equal("Games", productCategoryName);
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldNotReturnComputers()
	{
		var productCategoryName = _productServiceMock.Object.GetProductCategory(1, 1);

		Assert.NotEqual("Computers", productCategoryName);
	}
}

Assuming that the mock objects are set up correctly, both tests will pass.

Here is the full code for the ProductTests class at this stage.

// ProductTests.cs
using Moq;
using RoundTheCode.xUnitMock.Library;

public class ProductTests
{
	private readonly Mock<ProductService> _productServiceMock;
	private readonly Mock<ICategoryService> _categoryServiceMock;

	public ProductTests()
	{
		_categoryServiceMock = new Mock<ICategoryService>();
		_productServiceMock = new Mock<ProductService>(_categoryServiceMock.Object);

		_categoryServiceMock.Setup(s => s.GetCategoryName(1)).Returns("Games");
		_categoryServiceMock.Setup(s => s.GetCategoryName(2)).Returns("Computers");
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldReturnGames()
	{
		var productCategoryName = _productServiceMock.Object.GetProductCategory(1, 1);

		Assert.Equal("Games", productCategoryName);
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldNotReturnComputers()
	{
		var productCategoryName = _productServiceMock.Object.GetProductCategory(1, 1);

		Assert.NotEqual("Computers", productCategoryName);
	}
}

Verify the number of times a method is called

Moq also allows you to verify the amount of times a method is called.

In the GetProductCategory method inside the ProductService class, we want to verify that the GetCategoryName method with a parameter of 1 inside the ICategoryService interface is only called once.

This can be done by calling the Verify method as part of the mock object and we can select a method in the Times struct to determine how many times a method is called.

As we only want this method called once, we use Times.Once.

// ProductTests.cs
...
public class ProductTests
{
	...
	
	[Fact]
	public void GetProductCategory_CategoryIdOf1_CallsGetCategoryNameOnce()
	{
		var productCategoryName = _productServiceMock.Object.GetProductCategory(1, 1);

		_categoryServiceMock.Verify(s => s.GetCategoryName(1), Times.Once);
	}
}

How to handle exceptions

Exceptions is also within the capabilities of Moq.

For this to happen, we have to set up a method in a mock object and get it to throw an exception.

In this instance, if a parameter of 3 is passed in to the GetCategoryName method inside the ICategoryService interface, we have set it up to throw an exception.

When we call the GetProductCategory method inside the ProductService class, passing in a CategoryId of 3, we then expect it to throw that exception.

// ProductTests.cs
...
public class ProductTests
{
	...
	[Fact]
	public void GetProductCategory_CategoryIdOf3_ShouldThrowException()
	{
		_categoryServiceMock.Setup(s => s.GetCategoryName(3)).Throws<Exception>();

		var productCategoryName = () => _productServiceMock.Object.GetProductCategory(1, 3);

		Assert.Throws<Exception>(productCategoryName);
	}
}

The full code

Here is the full test code for the ProductTests method.

// ProductTests.cs
using Moq;
using RoundTheCode.xUnitMock.Library;

public class ProductTests
{
	private readonly Mock<ProductService> _productServiceMock;
	private readonly Mock<ICategoryService> _categoryServiceMock;

	public ProductTests()
	{
		_categoryServiceMock = new Mock<ICategoryService>();
		_productServiceMock = new Mock<ProductService>(
			_categoryServiceMock.Object);

		_categoryServiceMock.Setup(s => s.GetCategoryName(1))
			.Returns("Games");
		_categoryServiceMock.Setup(s => s.GetCategoryName(2))
			.Returns("Computers");
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldReturnGames()
	{
		var productCategoryName =
			_productServiceMock.Object.GetProductCategory(1, 1);

		Assert.Equal("Games", productCategoryName);
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_ShouldNotReturnComputers()
	{
		var productCategoryName =
			_productServiceMock.Object.GetProductCategory(1, 1);

		Assert.NotEqual("Computers", productCategoryName);
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf1_CallsGetCategoryNameOnce()
	{
		var productCategoryName =
_productServiceMock.Object.GetProductCategory(1, 1);

		_categoryServiceMock.Verify(s => s.GetCategoryName(1), Times.Once);
	}

	[Fact]
	public void GetProductCategory_CategoryIdOf3_ShouldThrowException()
	{
		_categoryServiceMock.Setup(s => s.GetCategoryName(3)).Throws<Exception>();

		var productCategoryName = () => _productServiceMock.Object
		.GetProductCategory(1, 3);

		Assert.Throws<Exception>(productCategoryName);
	}
}

Watch the video tutorial

Watch our video tutorial where we take you through the steps of setting up Moq in an xUnit test project, creating services and mocking these services as part of unit tests.

In-addition, download the code example where you can try mocking objects yourself.