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.
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.
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.
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>();
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:-
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
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
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.
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); }
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.
In this article, we have to show Create and Used PIPE in angular
In this article, we have to show Create and Used PIPE in angular
In this article, we have to show Create and Used PIPE in angular