Unit testing .NET REST APIs with Xunit and Moq

Unit testing .NET REST APIs with Xunit and Moq

Learn the basics of writing unit test for .NET REST APIs

·

9 min read

In the last article we designed a REST API in .NET 5. The REST API was designed to perform CRUD operations on the database using best practices. In this article, we would be looking at writing unit tests for the REST API we built. You might ask yourself why test the software if it works? Great question! Unit testing helps you properly debug your application and anticipate errors when they emanate whether there are from the server or the database. Have you ever thought about Google’s server going down for even 30 mins? Hmm, that could pose catastrophic and collateral damages as a lot of businesses rely on Google to function and effectively serve their customers.

Unit testing is a type of software testing where individuals test individual units or components of their application. We would be using a popular and mature unit testing suite in the .NET ecosystem, Xunit. Too much talk already! Let’s get to write unit tests for our API.

On the Solution Explorer, right click on the project to add a new test project, xUnit Test Project (.NET Core). After naming the project go add to create.

Unit 1.PNG

After creating the unit test project, add Moq nuget package on the Package Manager Solution. Moq helps in mocking the behaviour of actions inside the controller we intend to test.

Right click on Dependencies inside the unit project to reference the API project.

Unit 2.PNG

Unit 3.PNG

You can rename the default class that comes with the unit test project as GenreControllerTest.cs. Inside the class, we would be writing test for all the controller actions we created in the REST API project. Test for Create, Read, Update and Delete (CRUD) operations.

Inside the test class, do ensure you reference the following namespaces and others you would add as the project progresses:

  • System.Collections.Genrics
  • System.Linq
  • Xunit

Unit 4.PNG

Unit test for GetAllGenre action

Our first unit test case would be GetAllGenre_NoCondition_Returns_OkObjectResult(), Our GET action retrieves all the resources in the database and sends back a 200 OK response indicative that the query operation was successful. We are writing a test to see if the action really returns a 200 OK response.

Unit 5.PNG

We are going to be initializing and mocking all the behavior of the action in the Arrange section. The IGenreRepository is mocked (creating an instance of the default behavior of the repository). We also configured the mock for the AutoMapper. We can then go ahead to create an instance of the GenreController. We also initialised a GenreDTO and GenreModel object. Finally, we then setup the GetGenre action which returns an ICollection of the GenreModel type.

Unit 6.PNG

In the Act section we write a case where our API calls on the GetAllGenre action, we make the action result an OKObjectResult.

Unit 7.PNG

In the Assert section we check if the status code we got from our action result is a 200 OK. If this is true the test passes.

Unit 8.PNG

Unit 9.PNG

Unit test for GetGenreById action

Our second unit test case would be GetGenreById_Returns_OkObjectResult(), our GET action returns a specific resource based on the id passed in, if this is successful it returns us a 200 OK result indicative that the action was successful.

Unit 10.PNG

In the Arrange section we repeat the procedures from the previous unit test.

Unit 11.PNG

We repeat the same for the Act section.

Unit 12.PNG

Same for the Assert section. If the conditions are satisfied the test passes.

Unit 13.PNG

Unit 14.PNG

Unit test for the CreateGenre action

CreateGenre_Returns_CreatedAtRoute() would be our third unit test case, our POST action makes a request to the server to create a new resource based on the content of the DTO. If this action is successful, it should return a 201 CreatedAtRoute response from the server showing the data has been created on the database.

Unit 15.PNG

In the Arrange section we repeat the procedures from previous unit test.

Unit 16.PNG

The Act section, we repeat the same procedure from previous unit test

Unit 17.PNG

We also repeat the same procedure on the Assert section. If the conditions are satisfied the test passes.

Unit 18.PNG

Unit 19.PNG

Unit test for the UpdateGenre action

UpdateGenre_Returns_NoContent() is our fourth unit test case, a PUT action makes a request to the server to updates part or all of the properties of the resource in the database with a specific id. If this action is successful, it should return a 204 NoContentResult response from the server indicative that the resource has been updated.

Unit 20.PNG

The Arrange section follows procedures from above.

Unit 21.PNG

The Act section follows procedures from previous unit test.

Unit 22.PNG

Assert section follows procedures from above. If the conditions are met the test passes.

Unit 23.PNG

Unit 24.PNG

Unit test for the PartialUpdateGenre action

PartialUpdateGenre_Returns_NoContent(), is our fifth unit test case, a PATCH action makes a request to the server to update one part of the resource in the database based on the id passed. If the action is successful, it returns a 204 NoContent response from the server indicating it has updated that part of the resource. You would have to install Microsoft.AspNetCore.JsonPatch nuget package to complete this action.

Unit 25.PNG

The setup for the Arrange section is the same from previous unit test.

Unit 26.PNG

Act section follows procedures previous unit tests.

Unit 27.PNG

Assert section follows procedures previous unit tests. If the conditions are met the test passes.

Unit 28.PNG

Unit 29.PNG

Unit test for the DeleteGenre action

DeleteGenre_Returns_NoContent(), is our sixth unit test case, a DELETE action makes a request to the server to delete a resource based on the id passed into the delete action. If the action is successful, it returns a 204 NoContent response from the server indicating the resource has been deleted.

Unit 30.PNG

The Arrange section initializes all the Mock identities and sets up the mock behavior.

Unit 31.PNG

Act section follows procedures from previous unit tests.

Unit 32.PNG

The Assert section follows procedures from previous unit tests. If the condition is met the test passes.

Unit 33.PNG

Unit 34.PNG

We can now see below that all our test passes. This shows our application is coming along well. Unit test might be tasking but it is rewarding because it helps you debug your application to know where is defective.

Unit 35.PNG

That will be all for now friends. After reading through this article you should be comfortable writing unit test cases. If you need more complex examples you can check my Github project.