.NET Core

How To Do Unit Test In .NET Core WebApi – XUnit

In this article, we are going to cover Unit Testing(Xunit) in .net Core and the need for Unit Testing, and how we can implement it.

Why do we need unit tests?

As we know Testing our Software Application is very important. As our Application can respond in an unexpected way to a change. So to test each and every Fall we need automatic Testing after all the changes are done in an application.

Manual Testing is not a reliable way to test any application. It is the slowest and the more expensive way of testing an application.

An application that follows good architectural Principles is easily testable. And Asp .Net Core supports automated unit, integration, and functional testing.

What is Unit Testing?

In Unit Testing, Unit refers to the unit of work i.e a single individual method in our code.

Unit Testing means testing this block of code to verify whether it’s working as per the requirement for what it is written or not.

Unit Testing will not test the behavior of dependency of the code that is part of integration testing.

Example

Let Create Asp .net Core Web API Application.

Delete the default Controller, Create a StudentController and perform Crud Operation in it as shown below.

StudentController

[Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        private readonly IStudentService _studentService;

        public StudentController(IStudentService studentService)
        {
            _studentService = studentService;
        }

        [HttpGet("GetAllStudent")]
        public async Task<IActionResult> GetAllStudent()
        {
            return Ok(await _studentService.GetStudentList());
        }
        
        [HttpGet("GetById")]
        public async Task<IActionResult> GetById(int studentId)
        {
            return Ok(await _studentService.GetById(studentId));
        }

        [HttpPost("AddStudent")]
        public async Task<IActionResult> AddStudent(StudentEntity studentEntity)
        {
            await _studentService.AddStudent(studentEntity);
            return Ok();
        }

        [HttpPost("UpdateUser")]
        public async Task<IActionResult> UpdateStudent(StudentEntity studentEntity)
        {
            await _studentService.UpdateStudent(studentEntity);
            return Ok();
        }

        [HttpDelete("Delete Student")]
        public async Task<IActionResult> DeleteStudent(int studentId)
        {
            await _studentService.RemoveStudent(studentId);
            return Ok();
        }
    }

There’s nothing new done in the controller we have performed add, update and delete operations in Student Entity.

StudentService

To Perform Operations in Student Entity we are Using StudentService that implements IStudentService.This allows us to use the dependency injection principle which is used heavily for the purpose of unit testing.

The Complete Code of StudentService is shown below: –

public class StudentService: IStudentService
   {
       private readonly ApplicationDBContext _dbContext;

       public StudentService(ApplicationDBContext dBContext)
       {
           _dbContext = dBContext;
       }

       public async Task AddStudent(StudentEntity studentEntity)
       {
           await _dbContext.StudentEntities.AddAsync(studentEntity);
           await _dbContext.SaveChangesAsync();
       }
       public async Task<List<StudentEntity>> GetStudentList()
       {
           var studentList = await _dbContext.StudentEntities.ToListAsync();
           return studentList;
       }
       public async Task<StudentEntity> GetById(int studentId)
       {
           var studentData = await _dbContext.StudentEntities.FirstOrDefaultAsync(z => z.StudentId == studentId);
           return studentData;
       }
       public async Task UpdateStudent(StudentEntity studentEntity)
       {
           _dbContext.Entry(studentEntity).State = EntityState.Modified;
           await _dbContext.SaveChangesAsync();

       }
       public async Task RemoveStudent(int studentId)
       {
           var alreadyExists = await _dbContext.StudentEntities.FirstOrDefaultAsync(z => z.StudentId == studentId);
           if (alreadyExists != null)
           {
               _dbContext.StudentEntities.Remove(alreadyExists);
               await _dbContext.SaveChangesAsync();
           }
       }
   }

IStudentService

This is the interface of StudentService which contains the signature of all the methods implemented in StudentService.

public interface IStudentService
{
    Task AddStudent(StudentEntity studentEntity);
    Task<List<StudentEntity>> GetStudentList();
    Task<StudentEntity> GetById(int studentId);
    Task UpdateStudent(StudentEntity studentEntity);
    Task RemoveStudent(int studentId);
}

StudentEntity

This is our main entity (and the only class) in this project

[Table("Student")]
public class StudentEntity
{
    [Key]
    public int StudentId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string DOB { get; set; }
}

Note:- Here we are using dependency Injection to create an instance of our service. so for that register the service in startup Class as shown below

services.AddScoped<IStudentService, StudentService>();

Let’s Create Test Project

Now after creating the .net Core Application let’s create a test project for our Xunit testing. There is a xUnit testing project template available in Visual Studio 2019. Create a project using that template.

The XUnit is an open-source unit testing tool for the .NET framework that simplifies the testing process and allows us to spend more time focusing on writing our tests.

Steps for Creating a Test Project:-

  1. Right Click on your solution in Solution Explorer
  2. Click on Add -> New Project
  3. Now search for Xunit. you will see an XUnit test Project(.net Core) template .select the template
  4. Click on Next
  5. Now name the project as “Tests” and add the location (best practice to place it in the same solution folder) and click on Ok

And You Unit Test project is created.

The Next Step is to Give the Reference of the WebApi Project for which we are going to write test cases.

Steps to add Reference of WebApi Project

  1. Right Click on Test Project in Solution Explorer
  2. Click on Add -> New Reference
  3. Browse for your API project and select your project and click Ok

As we know we are using dependency injection in our application where we are implementing the method of IStudentService Interface. So when we write a test case for any controller or class that is having dependency injection we should isolate the dependency.

Why do we need to isolate the dependency 

  • we don’t need to initialize all dependencies for the correct output . Thus it makes our code easy.
  • If in any case, our test cases fail .it can easily identify whether it fails due to dependency or due to an error in our controller or service.
  • when our test case communicates with our database the same as the repository or service it can take more than the expected time for the execution .this can happen due to a database connection issue or due to the time needed to fetch the data.

So to overcome all problems it’s a best practice to isolate dependency and create a MOCK for them. For Mock, we need to install Moq library

run the following command in package console in visual studio Install-Package Moq

Now in our Test Class, we will mock IStudentService as we are going to create the test case for our StudentService that is having a dependency on the IStudentService Interface.

Let’s Start Writing Test Cases

We will use [Fact] Attribute to our method which is used by XUnit Framework, which will make it the actual testing method. Except for the Test method, we can have an N number of methods in our test class.

While writing Test Cases its best practice to Follow the AAA principle (Arrange, Act, Assert).

Arrange – It is part where we will prepare objects and set up them for our test case.

Act – This is the part where actual testing will be executed.

Assert – This is the final part where we will compare the derived result with the expected result.

Note:- As additional information, it is best to name the test method the same as our actual method so that we don’t need to read the whole code that is tested.

Testing Our Methods.

Get Method 

First We will test our Get Method . Our Expected Test Criteria will be should return all the records of students.

public class StudentTest
   {
       private readonly Mock<IStudentService> studentService;

       public StudentTest()
       {
           studentService = new Mock<IStudentService>();
       }
       [Fact]
       public async Task GetAllStudent_Test()
       {
           // Arrange
           studentService.Setup(srvc => srvc.GetStudentList()).ReturnsAsync(new List<StudentEntity>()
           {
               new StudentEntity()
               {

                   StudentId=1,
                   FirstName=" Juan",
                   LastName="Hoffman",
                   DOB="5/7/1988",
                   Email= "juan.hoffman@example.com"
               },new StudentEntity()
               {
                   StudentId=2,
                   FirstName=" Gary",
                   LastName="Hawkins",
                   DOB="6/5/1985",
                   Email= "gary.hawkins@example.com"
               },new StudentEntity()
               {
                   StudentId=3,
                   FirstName="Claude",
                   LastName="Flores",
                   DOB="12/1/1952",
                   Email= "claude.flores@example.com"
               }
           });
           //Act
           var result = await studentService.Object.GetStudentList();
           //Assert
           Assert.True(result.Count == 3);
       }
            
   }

In the above code, we have created an instance of our StudentService and in our GetAllStudent_Test we are setting up our GetStudentList method to return 3 records of a student that is arranged as part of AAA principal, we have Acted on it and called the GetStudentList method to get the result, after that in assert we have checked where we have received count as 3 or not in the result of our Act.

Add Method

Now let’s write the test case for our Add method.

[Fact]
   public async Task AddSTudent_Test()
   {
       //Arrange
       StudentEntity studentEntity = null;
       studentService.Setup(srvc => srvc.AddStudent(It.IsAny<StudentEntity>())).Callback<StudentEntity>(x => studentEntity = x);
       var studData = new StudentEntity
       {
           FirstName = " First Name",
           LastName = "Last Name",
           DOB = "Date of Birth",
           Email = "Email"
       };

       //Act
       await studentService.Object.AddStudent(studData);

       //Assert
       studentService.Verify(x => x.AddStudent(It.IsAny<StudentEntity>()), Times.Once);
       Assert.Equal(studentEntity.FirstName, studData.FirstName);
       Assert.Equal(studentEntity.LastName, studData.LastName);
       Assert.Equal(studentEntity.DOB, studData.DOB);
       Assert.Equal(studentEntity.Email, studData.Email);
   }

In The above Code also once again we have tested whether the expected value is returned or not when someone Calls the AddStudent method. Here we have checked whether the same values are added in the student list that we are passing or not.

Update Method

Now, let’s Test Our Update method to check whether the updated value overwrites the old value or not. The code for the Update Test case is as below

[Fact]
   public async Task UpdateStudent_Test()
   {
       //Arrange
       StudentEntity studentEntity = null;
       studentService.Setup(srvc => srvc.UpdateStudent(It.IsAny<StudentEntity>())).Callback<StudentEntity>(x => studentEntity = x);
       var studData = new StudentEntity
       {
           FirstName = " First Name updated",
           LastName = "Last Name updated",
           DOB = "Date of Birth updated",
           Email = "Email updated",
           StudentId = 2
       };
       //Act
       await studentService.Object.UpdateStudent(studData);
       //Assert
       studentService.Verify(x => x.UpdateStudent(It.IsAny<StudentEntity>()), Times.Once);

       Assert.Equal(studentEntity.FirstName, studData.FirstName);
       Assert.Equal(studentEntity.LastName, studData.LastName);
       Assert.Equal(studentEntity.DOB, studData.DOB);
       Assert.Equal(studentEntity.Email, studData.Email);


   }

Delete Method

This is the Last Test Method we need to Test to check whether the passed object is removed or not the code is as below.

[Fact]
public async Task DeleteStudent_Test()
{
  //Arrange
  var studentId = 2;
  studentService.Setup(srvc => srvc.RemoveStudent(studentId));
  //Act
  await studentService.Object.RemoveStudent(studentId);
  //Assert
  studentService.Verify(repo => repo.RemoveStudent(studentId), Times.Once);
}

Conclusion

In this blog, we have learned the basic concept of unit testing and how we can test different methods and how to set up the unit testing project with xUnit.

You can get The Source code of this demo here.
Thanks for Reading, I Hope this article helps you guys.

Ankita Jain

I am Ankita Jain. I started my journey as a .Net Developer and Learning and developing new things in IT Industries. I completed MSC(ICT) from Veer Narmad South Gujarat University.

Share
Published by
Ankita Jain

Recent Posts

Testing hk

Testing

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

Operation

Testing

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

Create and Used PIPE in angular

In this article, we have to show Create and Used PIPE in angular

2 years ago

TETS NEW

test

3 years ago