Moq Unit Testing in .NET Core with xUnit

Introduction

A software design pattern called unit testing is used to test the tiniest parts of the software development process.

Prior to moving forward with the QA Team and the production environment, unit testing is used to validate functionality and create expected output.

Early problem detection in the software development cycle is beneficial.

The.NET Framework comes with a number of unit test tools, including NUnit, xUnit, and many others.

xUnit

For .NET development, xUnit is a free and open-source unit testing framework.

There are numerous features in xUnit that make it easier to write clear and effective unit test cases.

It offers a mechanism to create our own attributes in addition to numerous attributes, such as fact, theory, and many more, to help write test cases clearly and efficiently.

Features of the xUnit

  1. xUnit in.NET uses the [Fact] attribute to specify the unit test method.
  2. The test procedure's parameters are provided by the [Theory] attribute.

Creating a Testing Project

At last, we reach the stage where our tests will require the creation of a new project. We will take advantage of the handy xUnit testing project template that comes with Visual Studio 2022 when we use it.

An open-source unit testing tool for the.NET framework called xUnit makes testing easier and frees up more time to concentrate on creating tests.

.NET framework

Moq

Fundamentally, the mocking library is called Moq.

If our application depends on one or more services, we can use the Moq library to mock certain classes and functionality using fake data instead of having to initialize everything associated with it.

Write some more unit tests, please!

As you can see, the interface is being injected into our controller via Dependency Injection. Thus, through that injected interface, our controller is essentially dependent on the repository logic.

That method is also highly advised and has no issues at all. However, we should isolate those dependencies when writing tests for our controller or any other class in a project.

The following are some benefits of dependency isolation in test code.

  • Our test code is significantly simpler because we don't need to initialize every dependency in order to return accurate values.
  • If our test fails and we don't isolate the dependency, we won't know if the failure was caused by a controller error or by the dependency itself.
  • Test code may run more slowly when dependent code interacts with an actual database, as our repository does. This may occur as a result of poor connections or just taking too long to retrieve data from the database.

You get the idea, though there are more justifications for isolating dependencies in test code.

Having said that, let's add the Moq library to the project Tests.

Install-Package Moq

OR

Package Moq

We are now prepared to write tests for our EmpController's first GetAll method.

The xUnit framework uses the [Fact] attribute, which we will use to decorate test methods to identify them as the real testing methods. In the test class, in addition to the test methods, we can have an infinite number of helper methods.

The AAA principle (Arrange, Act, and Assert) is typically followed when writing unit tests.

  1. Arrange: this is the part where you usually get everything ready for the test or put another way, you get the scene ready for the test (making the objects and arranging them as needed).
  2. Act: Here is where the procedure that we are testing is carried out.
  3. Assert: In this last section of the test, we contrast the actual outcome of the test method's execution with our expectations.

Testing Our Actions

We will want to confirm the following in the Get method, which is the first method we are testing.

  • Whether the method yields the OkObjectResult, a response code of 200 for an HTTP request.
  • Whether the returned object includes every item in our list of Emps.

Testing the GET Method

using Microsoft.AspNetCore.Mvc;
using Moq;
using System.Linq.Expressions;
using WebApplication1.Contract;
using WebApplication1.Controllers;
using WebApplication1.Database;
using WebApplication1.Model;
using WebApplication1.Repository;

namespace TestDemo
{
    public class EmpControllerTest
    {
        private readonly EmpController _empController;
        private readonly Mock<IEmpRepository> _empRepository;

        public EmpControllerTest()
        {
            _empRepository = new Mock<IEmpRepository>();
            _empController = new EmpController(_empRepository.Object);
        }

        [Fact]
        public void GetAll_Success()
        {
            // Arrange
            var expectedResult = GetEmps().AsQueryable();
            _empRepository.Setup(x => x.GetAll(It.IsAny<FindOptions>())).Returns(expectedResult);

            // Act
            var response = _empController.Get();

            // Assert
            Assert.IsType<OkObjectResult>(response as OkObjectResult);
        }
    }
}

Fact

[Theory]
[InlineData("503df499-cabb-4699-8381-d76917365a9d")]
public void GetById_NotFound(Guid empId)
{
    // Arrange
    Emp? emp = null;
    _empRepository
        .Setup(x => x.FindOne(It.IsAny<Expression<Func<Emp, bool>>>(), It.IsAny<FindOptions?>()))
        .Returns(emp!);

    // Act
    var response = _empController.Get(empId);

    // Assert
    Assert.IsType<NotFoundObjectResult>(response as NotFoundObjectResult);
}

Theory

In case all of the unit test cases are passed, then it looks like the screenshot below.

Unit test

In case any of the unit test cases fail, then it looks like the screenshot below.

Test cases fail

We learned the new technique and evolved together.

Happy coding!


Similar Articles