Unit Testing Controllers in ASP.NET Web API
WebAPI
19 Articles
In this article, let's learn about how to unit test Controllers in WebAPI in ASP.NET Core.
Table of Contents
- Introduction
- Why Unit Testing?
- What is a Controller?
- Unit Testing Controller
- Verifying Action Result
- Verifying Model Type
- Verifying Model Content
- Combining All Together
- Summary
Introduction
In this article, we will focus on unit testing thick controllers, which are controllers that contain behavior suitable for testing. While it's ideal to start with thin controllers, it's not always possible, especially when working with existing projects or teams that have different design decisions. Writing pragmatic unit tests for thick controllers can greatly improve the application's reliability.
Why Unit Testing ?
Unit testing allows developers to verify the behavior and logic of individual units of code in isolation. By writing tests, you can ensure that your code functions correctly and remains reliable even after making changes or adding new features. Unit tests help catch bugs early in the development process and provide confidence in the correctness of the code.
Note: If you have not done so already, I recommend you read the article on Implementing TDD in C# .Net.
What is a Controller ?
When it comes to testing API controllers in ASP.NET Core, it's important to consider the behavior contained within the controllers. Controllers can be categorized as thick or thin. Thick controllers contain logic and behavior that can be tested, such as model state checks, database calls, mapping code, and conditional code. On the other hand, thin controllers delegate the implementation of behavior to other components and typically don't require unit testing.
Unit Testing Controller
To test API controllers in ASP.NET Core, it's crucial to isolate the controller's behavior from external dependencies, such as model binding, filters, and routing. Unit testing should focus on testing the controller's behavior itself, avoiding testing the ASP.NET Core framework.
Veriyfing Action Result
One aspect of testing API controllers is verifying the type of ActionResult returned from a specific action. In many cases, ActionResult<T> is used as the return type, allowing for flexibility in returning different types of action results. To test the ActionResult type, you can assert that the returned result is of the expected type, such as OkObjectResult, NotFoundObjectResult, or BadRequestObjectResult.
Here's an example of testing the type of ActionResult returned from the GetBlogs action:
Code Sample - WebAPI Controller Action Result Test
Veriyfing Model Type
Another important aspect of testing API controllers is verifying the expected model type returned by the action. The model type is the generic type parameter of the ActionResult<T>. You can use the Assert.IsAssignableFrom method to check if the returned model is assignable to the expected type.
For example, let's verify that the returned model from the GetBlogs action is of type IEnumerable<BlogDto>:
Code Sample - WebAPI Controller Model Type Test
Veriyfing Model Content
Finally, we're going to verify whether the returned DTO, in our case an IEnumerable<BlogDto>, is correctly constructed by the action. We expect it to contain as many objects as were inputted, and in our case, we input three blogs. So what we want to test is that we end up with three blog DTOs.
GetBlogs_GetActionMustReturnNumberOfInputtedBlogs. There is, again, nothing to arrange. To act, we execute the GetBlogs method again. And to assert, we first need to get a hold of the action result. We know how to do that by now, as it's the same as what we did in the two previous demos. Once we've got that action result, we can cast the result of the action result to an OkObjectResult and get the Value property. Once we have that value, we can cast it to an IEnumerable<BlogDto> and count it.
Code Sample - WebAPI Controller Model Content Test
Combining All Together
So far we focused on testing individual aspects of the controller's behavior. However, it is often useful to combine multiple asserts related to the same action in one unit test. This not only makes the test code more concise but also provides a clearer overview of the expected behavior.
To combine the asserts and fix the null reference issues, we can make use of the ActionResult<T> type's pattern matching capabilities. This allows us to simplify the code and handle null values more effectively.
Let's update our test to incorporate these improvements:
Code Sample - WebAPI Controller Complete Test
Summary
In this article, we explored the process of unit testing controllers in ASP.NET Core. We discussed the importance of unit testing and when it is suitable to test API controllers. We focused on testing the behavior of the controllers and provided examples of verifying ActionResult types, model types, and model content using C#.
Unit testing controllers allows us to ensure that the expected behavior is correctly implemented and provides valuable feedback on the reliability of our application. By isolating the tests and using mocks or framework techniques, we can focus solely on testing our code.