Creating an Application from Scratch using .NET Core and Angular — Part 7
By: Henrique Siebert Domareski
Tags: Unittest, Fullstack Development, Moq, Xunit, Dotnet Core

In this article we are going to see how to create the unit tests for the Controllers in the API layer. To create these unit tests we are also going to use the xUnit and Moq framework.

Creating the Unit Test project for the API layer

Let’s start creating a new xUnit project for the API layer, similar to the one we created for the domain layer in the previous article (you can read the previous article clicking here). Open the solution with Visual Studio, and create a new xUnit project and add it on the “test” folder:

Select the xUnit, add the name of the unit test project and the location of the project (remember to add inside the ‘test’ folder):

It’s necessary to add the reference for the API layer in the unit test project. To do it, right-click on Dependencies (in the unit test project) > click in Add Reference and select the BookStore.API:

We also need to add the Moq framework in our project. To install MOQ open the Package Manager Console, select the BookStore.API.Tests project and execute this command (or install Moq through the NuGet Package Manager):

Install-Package Moq

Testing the BooksController

On this new unit test project, delete the class “UnitTest1” that is automatically created with the project, and create the class “BooksControllerTests”. On this class, we have three private properties that we are going to use in the unit test methods, and on the constructor, we initialize these properties. This is the initial structure of the BooksControllerTests class:

On line 16 and 17, we are creating a mock to use in the tests methods. This way we can simulate the return of the methods from the BookService class and also mock the result of the mapping, which is made by AutoMapper. On line 18 we are creating an instance of the BooksController.

This test class also has four private methods, two of them are responsible for creating the data that will be used in the tests, and the other two are responsible to do the mapping from the entity to the Dto. This way, instead of manually create the default data on the methods that we need to use this data, or always manually do the mapping, we can call these methods when necessary, avoiding repeating code and making the code cleaner and easier to use. For specific data then we can only manually create the objects that we need. These methods are:

CreateBook — which create a single Book

MapModelToBookResultDto — which do the mapping converting a Book entity to a BookResultDto

CreateBookList — which create a list of Book

MapModelToBookResultListDto— which do the mapping converting a List of Book entity to a List of BookResultDto

These are the methods:

Now let’s implement the unit tests methods on the BooksControllerTests class.

The process to create the unit tests for the Controllers is similar to what was explained in the previous article. First, we need to check what the method is doing and create the unit test that will validate if the method is doing exactly what it should do. If we look at the BooksController we can see what we need to test, which are:

GetAll

GetById

GetBooksByCategory

Add

Update

Remove

Search

SearchBookWithCategory

Let’s start by looking at the first one, the GetAll:

For the GetAll we can test if:

The method returns Ok when a book exists

The method returns Ok when do not exist any book

The method calls the GetAll method from the Service class only one time

On line 4, where the GetAll method from the BookService class is called, we will mock, as we did with the repository classes when we were testing the Service classes. On line 6, in the return, you can see that there is a mapping from the result of the GetAll method, to a IEnumerable<BookResultDot>, so for this mapping, we also need to mock the result. This is the first unit test method:

From line 4 to 8, we are doing the “Arrange” of this unit test.

On line 4 we calling the method to create a book list.

On line 5 we are calling the method to do the mapping from the List<Book> to List<BookResultDto>.

On line 7 we are mocking the return of the GetAll() method from the BookService class.

On line 8 we are mocking the mapping from List<Book> to IEnumerable<BookResultDto>.

On line 10 we are doing the “Act”, calling the method that we want to test.

And on line 12 we are doing the “Assert”, to check if the result is of type OkObjectResult, which is the expected type.

For the next unit test method, we will also have something similar:

The difference from this unit test method, to the previous one, is that in this method we are mocking the method to return an empty list of Book.

And the third test method for GetAll, we want to be sure that the GetAll method from the BookService class was called only once:

For the next unit tests methods, we will have something similar. Let’s see the method GetById from the BooksController:

For the GetById method we can test if:

The method returns Ok when a book exists

The method returns NotFound when a book does not exist

The method calls the GetById method from the Service class only one time

These are the implementation of the test methods for the GetById method:

Next is the GetBooksByCategory:

For the GetBooksByCategory method we can test if:

The method returns Ok when book with searched category exists

The method returns NotFound when book with the searched category does not exist

The method calls the GetBooksByCategory method from the Service class only one time

These are the implementation of the test methods for the GetBooksByCategory method:

Next is the Add:

For the Add method we can test if:

The method returns Ok when the book is added

The method returns BadRequest when the model state is invalid

The method returns BadRequest when the book is not added

The method calls the Add method from the Service class only one time

These are the implementation of the test methods for the Add method:

Next is the Update:

On the Update method, there is an extra validation, which is the one on line 4. If the id is different than the id of the entity, should return BadRequest. So for the Update method, we can test if:

The method returns Ok when the book is updated correctly

The method returns BadRequest when the book id is different than the parameter id

The method returns BadRequest when the model state is invalid

The method calls the Update method from the Service class only one time

These are the implementation of the test methods for the Update method:

Next is the Remove:

For the Remove method we can test that:

The method returns Ok when the book is removed

The method returns NotFound when the book does not exist

The method calls the Remove method from the Service class only one time

These are the implementation of the test methods for the Remove method:

Next is the Search:

For the Search method we can test if:

The method returns Ok when book with searched name exists

The method returns NotFound when book with searched name does not exist

The method calls the Search method from the Service class only one time

These are the implementation of the test methods for the Search method:

Next is the SearchBookWithCategory:

For the SearchBookWithCategory method we can test if:

The method returns Ok when book with the searched value exists

The method returns NotFound when book with the searched value does not exist

The method calls the SearchBookWithCategory method from the Service class only one time

These are the implementation of the test methods for the SearchBookWithCategory method:

Executing the tests

To execute the test on Visual Studio, go to “Test” and click on “Test Explorer”:

On the test explorer, right click on the BookStore.API.Tests and click in “Run”, to execute all the tests from this project:

After the tests are executed, if everything works as expected, they will be green like in the image below:

The tests methods for the CategoriesController follows the same steps. Since the methods are not so different than the methods on the BooksController, I will not add them here on this article. You can check the complete code on my GitHub:

On the next article, we are going to see how we can create the unit tests for the Repository classes on the Infrastructure layer.

Thanks for reading!