Ads

Web API 12 : Let's test our C# .NET Core Web API

Hello All,

In this article, we will learn that how to fully test our ASP.NET Core Web API and also discuss best practices that we can use to keep our code and tests clean. 


With an integration test, we can test the API from the outside out by spinning up the (in-memory) API client and making an actual HTTP request. 

We mock the data as much as possible, and we will consume the API in the same way as an application (or user) would

Implementation:

Lets create the web API with Entity Framework CRUD operation

1. Open Visual Studio --> Create New Project --> Select ASP.Net Core Web API Template --> Click Next

2. Provide the project Name and Select the Location --> Click Next


Click on Create


3. Application is created, Lets clean up the unwanted files. So we will delete the highlighted items or class files


4. Create the folder called Models and add the class file Article.cs

namespace CodeWithChakri.API.Testing.Models
{
    public class Article
    {
        public int ArticleId { get; set; }
        public string Title { get; set; }
    }
}

5. Next, Create folder called Interfaces and add the interface file called IArticle.cs

using CodeWithChakri.API.Testing.Models;

namespace CodeWithChakri.API.Testing.Interfaces
{
    public interface IArticle
    {
        string Add(Article article);
        List<Article> All();
        string Update(Article article);
        string Delete(Article article);
    }
}

6. Then we will create the folder called Repository and add the implementation for IArticle, means we will create the class file called ArticleRepository.cs

Lets add static data to perform the CRUD operation

using CodeWithChakri.API.Testing.Interfaces;
using CodeWithChakri.API.Testing.Models;

namespace CodeWithChakri.API.Testing.Repository
{
    public class ArticleRepository : IArticle
    {
        public static List<Article> _articles = new List<Article>()
        {
            new Article() { ArticleId = 1,Title="C# Programming"},
            new Article() { ArticleId = 2,Title="ASP.Net Web API"},
            new Article() { ArticleId = 3,Title="ASP.Net Core MVC"},
            new Article() { ArticleId = 4,Title="MS SQL Server"}
        };

        public string Add(Article article)
        {
           _articles.Add(article);
            return article.Title;
        }

        public List<Article> All()
        {
            return _articles;
        }

        public string Delete(Article article)
        {
            _articles.Remove(article);
            return "Success";
        }

        public string Update(Article article)
        {
            var data=_articles.Where(x => x.ArticleId == article.ArticleId)
                .FirstOrDefault();
            data.Title = article.Title;
            return article.Title;
        }
    }
}

Above we have create the static variable _articles and added data in it for CRUD operation.

7. As we are using dependency injection to create instances of our services, make sure not to forget to register the service in the Startup.cs class or Program.cs

builder.Services.AddTransient<IArticle,ArticleRepository>();

8. Create the Empty API Controler called ArticleController.cs, With constructor inject we will create the IArticle variable and perform the CRUD operation.

using CodeWithChakri.API.Testing.Interfaces;
using CodeWithChakri.API.Testing.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace CodeWithChakri.API.Testing.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class ArticleController : ControllerBase
    {
        private IArticle articleContext;

        public ArticleController(IArticle articleContext)
        {
            this.articleContext = articleContext;
        }

        [HttpGet("list")]
        public List<Article> Get()
        {
            return articleContext.All();
        }

        [HttpPost("create")]
        public string Create(Article article)
        {
            return articleContext.Add(article);
        }

        [HttpPost("update")]
        public string Update(Article article)
        {
            return articleContext.Update(article);
        }

        [HttpPost("delete")]
        public string Delete(int articleId)
        {
            var article = articleContext.All()
.Where(x => x.ArticleId == articleId).FirstOrDefault();
            return articleContext.Delete(article);
        }
    }
}

We have done with API Creation which has CRUD operation.

Its time to test the API

Lets run the application and test the same in swagger


Endpoint List:

https://localhost:7072/api/Article/list

Output:

[
  {
    "articleId": 1,
    "title": "C# Programming"
  },
  {
    "articleId": 2,
    "title": "ASP.Net Web API"
  },
  {
    "articleId": 3,
    "title": "ASP.Net Core MVC"
  },
  {
    "articleId": 4,
    "title": "MS SQL Server"
  }
]

Great! Our API is working Boom.

Now start implementing the Test cases for Our WEB API.

Creating the Unit Test Project:

We Use xUnit, It is an open-source unit testing tool for the .NET framework or .Net Core that simplifies the testing process and allows us to spend more time focusing on writing our tests.

1. Right Click on Solution --> New Project


2. Select xUnit Test Project Template and Click Next

3. Enter the name of the project and Click Next


4. Select .NET Core version and Click on Create


5. Next, add the reference(of project CodeWithChakri.API.Testing) to the project we are about to write tests for


6. Also we will create the fake implementation of the IArticle interface, which we are going to inject into our controller at the time of testing.

It has an in-memory collection which we are going to fill up with our dummy data:

Create folder called Repository and add the class file called FakeArticleRepository.cs

using CodeWithChakri.API.Testing.Interfaces;
using CodeWithChakri.API.Testing.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CodeWithChakri.API.Testing.UnitTest.Repository
{
    public class FakeArticleRepository:IArticle
    {
        public static List<Article> _articles = new List<Article>()
        {
            new Article() { ArticleId = 1,Title="Test C# Programming"},
            new Article() { ArticleId = 2,Title="Test ASP.Net Web API"},
            new Article() { ArticleId = 3,Title="Test ASP.Net Core MVC"},
            new Article() { ArticleId = 4,Title="Test MS SQL Server"}
        };

        public string Add(Article article)
        {
            _articles.Add(article);
            return article.Title;
        }

        public List<Article> All()
        {
            return _articles;
        }

        public string Delete(Article article)
        {
            _articles.Remove(article);
            return "Success";
        }

        public string Update(Article article)
        {
            var data = _articles.Where(x => x.ArticleId == article.ArticleId)
                .FirstOrDefault();
            data.Title = article.Title;
            return article.Title;
        }
    }
}

7. Now we will write the test cases, Create file called ArticleControllerTest.cs file

Note :

We should keep in mind that When we write unit tests it should follow the AAA principle (Arrange, Act, and Assert)

Arrange: This is the first step of a unit test application. Here we will  do the necessary setup of the test. For example, to perform the test we need to create an object of the targeted class, if necessary, then we need to create mock objects and other variable initialization, something like this.

Act: This is the middle step of a unit step application. In this step we will execute the test. Here we will do the actual unit testing and the result will be obtained from the test application. Basically we will call the targeted function in this step using the object that we created in the previous step.

Assert: This is the last step of a unit test application. In this step we will check and verify the returned result with expected results.

Implementation:

Lets start writing the test.

First we will create the object

        private readonly ArticleController _controller;
        private readonly IArticle _service;
        public ArticleControllerTest()
        {
            _service = new FakeArticleRepository();
            _controller = new ArticleController(_service);
        }

Get Method:
 
[Fact]
public void Get_All_Articles_When_Called()
{
	//Act
	var listResult = _controller.Get() as List<Article>;

	// Assert
	var items = Assert.IsType<List<Article>>(listResult);
	Assert.Equal(4, items.Count);
}

Create Method:
[Fact]
public void Add_Article_Returns_Response()
{
	// Arrange
	Article testItem = new Article()
	{
		ArticleId = 5,
		Title = "Test Python Article"
	};

	// Act
	var createdResponse = _controller.Create(testItem);

	// Assert
	Assert.Equal(testItem.Title,createdResponse);
}

Update Method:

[Fact]
public void Update_Article_Returns_Response()
{
	// Arrange
	Article testItem = new Article()
	{
		ArticleId = 1,
		Title = "Test C# Programming Language"
	};

	// Act
	var updatedResponse = _controller.Update(testItem);

	// Assert
	Assert.Equal(testItem.Title, updatedResponse);
}

Delete Method:

[Fact]
public void Remove_Article_Returns_Response()
{
	//Arrange
	int articleId = 4;

	// Act
	var deleteResponse = _controller.Delete(articleId);

	// Assert
	Assert.Equal("Success", deleteResponse);
}

Here is the complete file....

using CodeWithChakri.API.Testing.Controllers;
using CodeWithChakri.API.Testing.Interfaces;
using CodeWithChakri.API.Testing.Models;
using CodeWithChakri.API.Testing.UnitTest.Repository;
using System.Collections.Generic;
using Xunit;

namespace CodeWithChakri.API.Testing.UnitTest
{
    public class ArticleControllerTest
    {
        private readonly ArticleController _controller;
        private readonly IArticle _service;
        public ArticleControllerTest()
        {
            _service = new FakeArticleRepository();
            _controller = new ArticleController(_service);
        }

        [Fact]
        public void Get_All_Articles_When_Called()
        {
            //Act
            var listResult = _controller.Get() as List<Article>;

            // Assert
            var items = Assert.IsType<List<Article>>(listResult);
            Assert.Equal(4, items.Count);
        }

        [Fact]
        public void Add_Article_Returns_Response()
        {
            // Arrange
            Article testItem = new Article()
            {
                ArticleId = 5,
                Title = "Test Python Article"
            };

            // Act
            var createdResponse = _controller.Create(testItem);

            // Assert
            Assert.Equal(testItem.Title,createdResponse);
        }

        [Fact]
        public void Update_Article_Returns_Response()
        {
            // Arrange
            Article testItem = new Article()
            {
                ArticleId = 1,
                Title = "Test C# Programming Language"
            };

            // Act
            var updatedResponse = _controller.Update(testItem);

            // Assert
            Assert.Equal(testItem.Title, updatedResponse);
        }

        [Fact]
        public void Remove_Article_Returns_Response()
        {
            //Arrange
            int articleId = 4;

            // Act
            var deleteResponse = _controller.Delete(articleId);

            // Assert
            Assert.Equal("Success", deleteResponse);
        }
    }
}

Running The Tests:

Right click on test project --> Run Tests



In this post, we’ve learned what unit testing is and how to set up the unit testing project with xUnit.

We’ve also learned the basic scenarios of testing the controller logic on some CRUD operations.

Assignment for you is to cover the negative scenarios.

You can download complete Source Code Here

Thats it for this article, See you in next article.

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.

#buttons=(Accept !) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Accept !