- Home
- .NET tutorials
- How to use Moq for mocking objects with xUnit and .NET
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.
C# coding challenges
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.
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.