API Testing in ASP.NET Core

A simple guideline to setup API integration tests in ASP.NET core with NUnit.

José Rojas
4 min readSep 24, 2023

Discover the world of API integration testing with my latest blog post. I simplify application logic to focus on showcasing integration tests for two straightforward endpoints. Explore the pros and cons, setup details, and key components of an effective integration testing suite. Uncover the benefits and challenges, and learn how to create a robust testing environment. Enhance your application’s quality with integration testing.

The application

The application deliberately keeps its logic and architectural patterns simple to highlight the core purpose of demonstrating integration tests. As a result, it exposes only two straightforward endpoints: one for creating an item in a to-do list and another for retrieving it.

Api documentation

Get Todo by ID

GET /api/todos/{id}

Create a Todo

POST /api/todos

APIs Integration Tests

Integration testing ensures that an application’s API functions correctly by testing how its various components interact. It verifies that API endpoints produce expected results when called, helping ensure seamless communication within the system.

Pros:

  1. Comprehensive Validation: It provides a holistic assessment of the entire system’s functionality by testing interactions between different components, catching potential issues early.
  2. Realistic Testing: Integration tests mimic real-world scenarios, offering confidence that the API works as expected when different parts of the application communicate.
  3. End-to-End Validation: These tests verify the entire data flow and communication pathways within the application, ensuring that all integrated components function together seamlessly.

Cons:

  1. Complexity: Writing and maintaining integration tests can be more challenging than unit tests due to the need to set up various system components and dependencies.
  2. Resource-Intensive: Integration tests may require substantial resources, including external services or databases, which can slow down the testing process.
  3. Time-Consuming: Running integration tests can be time-consuming, especially as the application grows, potentially affecting development and CI/CD pipelines.

Setup

The main challenge that this project will face is accessing the database when calling the API. Since the goal is to establish a proper integration test setup, it is not possible to mock the repositories or the data access layer. Additionally, it may be difficult to maintain a database with only the expected data for our tests. Therefore, we will rely on an in-memory SQL-Lite database.

  1. Create a test project with NUnit (e.g. ApiTestDemo.IntegrationTests)
  2. Install the package Microsoft.AspNetCore.Mvc.Testing. This package provides the following features:
    TestServer: It includes a TestServer class that allows you to host your. ASP.NET Core application in-memory during testing.
    Integration Testing: You can use the TestServer to send HTTP requests to your application’s API endpoints, just like a real client.
    Dependency Injection: The package seamlessly integrates with the dependency injection system in ASP.NET Core, allowing you to inject services and dependencies required for your tests. This makes it easy to configure your application’s services and dependencies specifically for testing.
    WebApplicationFactory: It provides the WebApplicationFactory class, which simplifies the setup of the TestServer and application configuration for testing. This class helps you create a test environment that closely resembles the production environment.
  3. Install Microsoft.EntityFrameworkCore.Sqlite.Core. This package provides SQLite database support for Entity Framework Core, allowing to use SQLite as database.

Test suite

First of all, in order to correctly inherit from WebApplicationFactory, it is necessary to create a proper class for your Program.cs file. The class should be structured as follows:

public class Program
{
protected Program()
{
}

public static async Task Main(string[] args)
{
...
}
}

The WebAppFactory: it has to inherit from the WebApplicationFactory<Program> and overrides the Configure.

public class WebAppFactory : WebApplicationFactory<Program>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(ReplaceDbContextWithInMemoryDb);
}

private static void ReplaceDbContextWithInMemoryDb(IServiceCollection services)
{
...
}

public TodoDbContext CreateDbContext()
{
...
}
}

This class will be responsible for the configuration of all services required for API integration tests. In this example, the ReplaceDbContextWithInMemoryDb method replaces the actual database configuration to use the SQLite database.

The CreateDbContext method must ensure that the SQLite database has been created before making calls to the endpoints.

  1. The HttpClientFactory: this is a simple yet useful class. Given the WebAppFactory, it will create the instance of the HttpClient. This allows a single location to configure the client properly. It is possible to configure settings such as the BaseAddress or, in more advanced scenario, the Authentication headers.
  2. ApiIntegrationTestFixture: This abstract class serves as template for the actual tests. It defines the Setup and Teardown procedures. To prevent tests from interfearing each others, it is important follow these guidelines:
    Setup: create a new instance of the WebAppFactory.Ensure that the SqlLite database has been created correctly. Create a new instance of the HttpClient.
    Teardown: delete the database and dispose it. Dispose the WebAppFactory and HttpClient.
  3. Finally we can test the code:
    [Test]
public async Task Post_ValidTodo_Returns201Created()
{
var todo = new TodoForCreationDto { Title = "Title", Description = "Description" };

var httpResponseMessage = await HttpClient.PostAsJsonAsync("api/todos", todo);

Assert.That(httpResponseMessage.StatusCode, Is.EqualTo(HttpStatusCode.Created));
}

Conclusion

Setting up an entrire test suite for your application will be quite challenging but at the end the efforts will pay high dividends.
You can find the entire code at https://github.com/rojasjo/ApiTestDemo .

🚀 See you! 🚀

--

--

José Rojas

🚀 I develop innovative web and mobile software products with .NET 🚀