Write strongly typed Web API integration tests using Kiota and OpenAPI
 
 I like to write integration tests for my ASP.NET Web API endpoints to ensure that they behave as expected. For most of the APIs I work with, I believe these tests are crucial for maintaining code quality and reliability.
The problem with typical integration tests link
An integration test typically hosts the API in a test server and fires (one or more) HTTP requests against it, verifying the responses against expected results. To invoke the API, you have to manually create an HTTP request, setting the correct route and body for each request.
This practice can be tedious. It's easy to accidentally make a typo in the route, post a wrong model, or simply forget to update the test when the API changes. This can lead to some frustration and wasted time to figure out why the test is failing.
It can also lead to a bad design. To make testing easier, many tests reuse the API models as the request and response bodies. While this is convenient, it can be the cause to make changes to the production code simply to accommodate the tests. An example of this is that it's a good practice to treat the incoming request model as an immutable object, of which its properties cannot be modified. However, this makes it difficult to create test requests, where you might want to have the possibility to modify the request model. The same applies when you're using tools to dynamically create the models, such as AutoFixture, which requires the models to have public setters. On the other hand, we also don't want to manually create separate request and response models just for testing purposes, as this leads to code duplication and maintenance overhead.
Testcase without client generation link
Before diving into the solution, let's first look at a typical integration test without using a generated client.
The test below creates a new customer by sending an HTTP POST request, in the test:
- A customer is created using the constructor of the CreateCustomer.Commandmodel, this model exists in the API layer
- An HTTP POST request is sent to the /customersendpoint with the customer data in the request body, the route is hardcoded as a string
While this works, it has its downsides... As mentioned before, the test is tightly coupled to the API's internal implementation.
Why Kiota link
To make the code within the test strongly typed, a better approach would be to use a generated API client that mirrors the API's structure and endpoints. This way, you can leverage the benefits of strong typing and avoid hardcoding routes and request structures. There are several tools available to generate API clients from an OpenAPI specification, such as NSwag and Kiota. In this post, I'll focus on Kiota, as I recently discovered it and found it had a better experience compared to other tools.
format_quoteKiota is a command line tool for generating an API client to call any OpenAPI-described API you're interested in. The goal is to eliminate the need to take a dependency on a different API client library for every API that you need to call. Kiota API clients provide a strongly typed experience with all the features you expect from a high quality API SDK, but without having to learn a new library for every HTTP API.
Using Kiota to generate the client link
To get started with Kiota, you first need to install the Kiota CLI tool. You can do this using the following command:
Using the kiota command, you can generate a client library from an OpenAPI specification:
The above command generates a C# client library in the specified output directory, using the provided OpenAPI specification file from the API project. It's also possible to provide the URL to the API's OpenAPI endpoint instead of a local file path. Personally, I prefer the local file approach, as it allows me generate the client without needing to run the API first.
Prerequisite: Generating the OpenAPI specification link
To enable OpenAPI support in your ASP.NET Core Web API and generate the OpenAPI specification file, you can use the Microsoft.AspNetCore.OpenApi package (this is added by default starting from .NET 9). Next, configure the OpenAPI middleware in your Program.cs file as shown in the minimal example below:
This configuration activates the OpenAPI middleware, which generates the OpenAPI specification file for your API at run-time.
To also generate the OpenAPI specification file during the build process, you must add the Microsoft.Extensions.ApiDescription.Server package as well.
I also like to set the GenerateDocumentationFile property in your API project's .csproj file to include XML comments in the generated OpenAPI specification:
Now the specification file is automatically generated during the build process, and is created within the obj directory of your project directory (this can be customized using the OpenApiDocumentsDirectory property). For more information about generating the OpenAPI documents, please take a look at the official documentation.
For an example of a generated OpenAPI specification document, you can check out the file Sandbox.ApiService.json. It contains information about the available endpoints, request and response models, and other relevant details about the API.
Generated client link
With the openAPI specification file in place, you can now generate the API client using Kiota as shown earlier. Once the client is generated, you can use it in your integration tests to interact with the API in a type-safe manner.
Using the OpenAPI specification, Kiota generates classes and methods that correspond to the API's endpoints and models, and adds these to your project. Because we want to use Kiota for testing, the generated client is added to the integration test project.
The generated client for my sample API can be found at Sandbox/Sandbox.Modules.CustomerManagement.IntegrationTests /ApiServiceSDK.
Testcase with generated client link
The refactored integration test using the generated API client looks like this.
To create the ApiClient instance, I added a method to the WebApplicationFactory class, which instantiates the client using the HttpClientRequestAdapter provided by Kiota.
Bonus tip link
Instead of manually running the Kiota command each time the API changes, you can automate the client generation process by adding a custom MSBuild target to your integration test project's .csproj file. This way, the client will be regenerated automatically during the build process.
Keep in mind that if you're building your application within a CI/CD pipeline, you might need to install the Kiota tool in the pipeline environment first. That's why I added the condition to only run the target in Debug mode, so it only runs during local development.
Conclusion link
Using the OpenAPI specification document to generate a strongly typed API client with Kiota has significantly improved my integration test flows. It eliminates the need for hardcoded routes and allows me to leverage the generated models, allowing me to quickly update models (even while this is prohibited by the production API models). If you're looking for a way to streamline your API testing process. While other tools exists, I highly recommend giving Kiota a try because of its ease of use and the way it creates the API methods.
Benefits link
Using Kiota to generate a strongly typed API client from the OpenAPI specification has several benefits for integration testing:
- Type safety: The generated client provides strong typing for API endpoints and models, reducing the risk of runtime errors due to typos or usage of incorrect data types.
- Maintainability: When the API changes, you can simply regenerate the client using Kiota, ensuring that your tests are always in sync with the API's specification.
- Decoupling from production code: By using the generated client, you can avoid coupling your tests to the internal implementation of the API, allowing for more flexible and isolated testing.
More than just testing link
In this blog post we've seen how Kiota is used for testing purposes, but Kiota can also be used to generate clients for consuming APIs in production code. This can be especially useful when working with third-party APIs that provide OpenAPI specifications. Instead of manually re-creating the client code, you can use Kiota to generate a client that is always in sync with the API's specification. This makes integrating with external APIs much easier and faster to implement.
You can find the complete integration test code in my Sandbox project.
More resources link
Feel free to update this blog post on GitHub, thanks in advance!
Join My Newsletter (WIP)
Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.
Support me
I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.
 
 