- 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.
Creating services
For this tutorial, we created an xUnit test project and a class library.
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.
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.
Add Moq to an xUnit test project through the NuGet package manager
Once the package is installed, we can mock the objects.
ProductTests, and create a mock instance for the ProductService class and the ICategoryService interface.
Moq assembly into the class and using the Mock class that comes with it.
private readonly field.
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.
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.
GetProductCategory method in the ProductService. It will pass in 1 for both the Id and CategoryId parameters.
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.
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.
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.
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.
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.
3 is passed in to the GetCategoryName method inside the ICategoryService interface, we have set it up to throw an exception.
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.
Related tutorials