Today in this article, we will learn RESTful API Unit Testing – Best Practices.
The recent popularity of frameworks like RESTful services (WebAPI) is getting huge traction.
We must develop robust microservices with a clear focus on TDD ( Test-driven Development) by following basic Unit Testing, Integration Testing, and Functional testing as a whole.
Today in this article, we will cover below aspects,
While performing Unit testing there is always confusion in developers on what is scoped under the Unit Testing.
Today we shall see basic guidelines for WebAPI Controller Unit testing.
These guidelines revolve more around RESTFul services built using ASP.NET Core WebAPI project templates.
We shall discuss below things that are important from Controller level Unit Testing.
- Verify Inputs
- Verify Controller method Response
- Verify HTTP Status Code(static check only, don’t get confused by the Integration test)
- Verify Mocked method invocation if any
- Verify Extension method invocation if any
- Verify Annotation/Attribute if any
Here I am using the XUnit test framework but you can use a test framework of your choice.
A Controller is a Class!
Before we begin writing unit test cases for the controller, the first thing you should understand is that “Controller” is not special when it comes to Unit testing.
The controller is a class like any other class which has members like methods and properties etc.
In Unit Testing, we create an instance of the target class call its method for various inputs, and assert the result as per expectation.
//Arrange BooksController service = new BooksController(mockBookClient.Object); //Act var result = await service.GetAsync(document.Id) as ObjectResult; var actualtResult = result.Value;
The only thing we do a bit differently in Controller unit testing is that of the REST response assertion additionally.
All you need to do is create an instance of the Controller class and invoke all its methods and verify I/O
Verify HTTP Status Code
Controller methods always return HTTP responses along with resource details by following the REST principles which should include Model state verification and HTTP Status Code.
Controller methods should be unit tested using assert for REST HTTP Status code.
Use the HttpStatusCode enum type to Assert the responses.
Example 1
Assert.Equal(HttpStatusCode.OK, (HttpStatusCode)result.StatusCode);
Example 2
Assert.IsType<OkObjectResult>(result);
Above, either way, the Unit test makes our API robust and validates the implementation of the REST principle following HTTP verbs correctly.
Each Controller method should be asserted for all possible types of HTTP Status codes like,
Commonly assertions should include
- Status Code – 200 (OK)
- Status Code – 401(Unauthorized)
- Status Code -201 – Created
- Status Code – 400 (Bad Request)
- Status Code – 500 (InternalServerError )
- + Others
These assertions will ensure that the Controller method produces proper results.
Reference: Asynchronous Method Unit Testing in .NET Core
Verify API Response – Static Checking
If the controller method is returning resources, such resources should be validated for their structure.
The below example has the response cast to the actual type i.e. Book to very the schema of returned responses.
//Act var result = await service.GetAsync(document.Id) as ObjectResult; var actualtResult = result.Value; //Assert Assert.Equal(document.Author, ((Book)actualtResult).Author); Assert.Equal(document.BookName, ((Book)actualtResult).BookName); Assert.Equal(document.Id, ((Book)actualtResult).Id);
- This will ensure that the code follows a contract properly when the consumer consumes your API.
- This schema assertion will red flag the code while development if there are any breaking changes.
Reference: Asynchronous Method Unit Testing in .NET Core
Verify Mocked/Extension invocation
Always assert if mocked methods are invoked at least once. The mocked method is the dependency that is avoided intentionally to concentrate only on the unit of work in isolation.
Example:
Verifying for the above code if the GetBooksAsync method which is a dependency (mocked) is called once.
mockBookClient.Verify(c => c.GetBookAsync(It.IsAny<string>()), Times.Once);
Reference: Unit Testing Extension Method in ASP.NET Core
Verify Business exception
API responses are critical as there will be consumers using the same as criteria. One can cross-check if business exception messages are raised appropriately.
Most business exceptions will be based on the HTTP status code giving an indication of the resource state. This static check on the return type will make your code robust.
Reference: Asynchronous Method Unit Testing in .NET Core
Verify Attributes for the Controller method
There is absolutely no problem in adding more test cases including Custom attribute validation or [Authorize] attribute validation within the Unit Test cases.
References: Unit Testing Authorize Attribute ASP.NET Core
Mark your Test method as Async
As good practice mark your Unit test method as async if Controller methods are Asynchronous in nature.
Your test cases are a state machine. Your test suite in any form will protect your code from anomalies and breaking changes apart from making new code robust and compatible with existing code.
-TheCodebuzz
On the good side of unit test cases, you need not have wait for the integration of different modules ( require in Integration test and real API Test) helping in real-time identifying the breaking changes.
Most Unit test cases run as you type your code, hence it is easy to be tested or identify breaking changes.
We are in the world of XP practices and Continuous Development, Continuous review, and Continuous deployment is the way to go.
Do you have any better suggestions to test the Controller method? Please sound off in your comments below.
That’s all, Happy Coding!
Summary
Today in this article, we learned helpful guidelines on Controller or RESTFul API Unit testing. It’s important to unit-test all possible scenarios for a Controller to make our API robust.
Please bookmark this page and share it with your friends. Please Subscribe to the blog to receive notifications on freshly published(2024) best practices and guidelines for software design and development.
Nicely explained Unit testing of REST API. Similarly could you please provide guideline and example for Integration Testing of REST API.
Thanks Priya for your query and feedback. I have covered few aspects of Integration Testing in general (not specific to API but will soon post an new article on this).Please refer Integration Testing Best Practices in Agile
And what do you think about this article https://andrewlock.net/should-you-unit-test-controllers-in-aspnetcore/?
I have concerns about unit testing as well
Thanks for your query. That one is a great article. As per my understanding, every manual code added by developers requires a Unit test. They are always easy to run, faster and finds the issue at early phases for any breaking changes. Other tests are like an integration test etc required definite components to be available first before could run them could be risky in relying fully on them especially for CI-CD. Best combination is you should have Unit, Integration, and Functional test complimenting each other.
Nice tips. Good suggestions.
Thank you Max.I appreciate your feedback. Please do subscribe to get a notification on new guidelines. Thanks.
Your guidelines are helpful.. thanks
Thanks Lucas for encouraging feedback!! Appreciate it.