Integration testing for dotnet core APIs: Handling database

Article Banner
Author(s): Ajay Kumar
Published On: 08 Feb 2025

Summary


Welcome to the 2nd post in our Integration testing series. You may check out the previous post that introduces the concept of writing integration tests using WebApplicationFactory in dotnet below:

Integration testing for dotnet core APIs: Introduction

Integration testing for dotnet core APIs: Introduction

devcodex.in
Blog Image

Almost every application relies on persistent storage, typically through a database. Integration testing with a real database can be challenging, especially when trying to maintain isolation and consistency across tests. In this post, we will explore how to effectively manage database dependencies in integration tests using WebApplicationFactory and containerized databases.

Pre-requisites, in case you want to follow the same setup on your system:

  • Postgres DB Server: This is needed in case you want to test out the main application.
  • Docker: This is needed to run test containers.

Setting Up the Database


To do this we need to first introduce a database in our sample superhero API. For this demo purpose, we have used a Postgres database.

For this, we made the below changes in our superhero API:


{
  "ConnectionStrings": {
    "WebApiDatabase": "Host=localhost; Database=superhero; Username=postgres; Password=postgres"
  }
}
        
Code Sample #2 : Connection String in appsettings.json

Install the package Npgsql.EntityFrameworkCore.PostgreSQL in the main API project. After that, we need to provide options in the program file to guide the application to use the Postgres database:


builder.Services.AddDbContext<SuperHeroDbContext>(opt =>
    opt.UseNpgsql(configuration.GetConnectionString("WebApiDatabase")));
        
Code Sample #3 : Configuring DbContext in Program.cs

Along with this, we also need to create a migration, if not already present, to set up the database schema.

Unit Test Example


Finally, our unit test:


[Fact(DisplayName = "Get all superheros API returns all superheroes")]
public async Task Get_All_SuperHeroes_Returns_List_Of_SuperHero()
{
    // Arrange
    factory.SharedFixture.SuperHeroDbContext.SuperHero.AddRange(new List<SuperHero>()
    {
        new SuperHero(1, "Batman","Bruce Wayne","Short distance fly,Common sense","Gotham", 40),
        new SuperHero(2, "Superman", "Clark kent", "Fly, Shoot laser beam, Super strength, ice breath","Gotham", 42),
        new SuperHero(3, "Robin", "John Blake", "Detective","Gotham", 35)
    });
    await factory.SharedFixture.SuperHeroDbContext.SaveChangesAsync();
    
    // Act
    var response = await factory.CreateClient().GetAsync("/SuperHero");

    // Assert
    response.StatusCode.Should().Be(HttpStatusCode.OK);
    var superHeroes = await response.Content.ReadFromJsonAsync<List<SuperHero>>();
    superHeroes.Should().NotBeEmpty();
    superHeroes![0].Id.Should().Be(1);
    superHeroes![0].SuperName.Should().Be("Batman");
}
        
Code Sample #4 : Unit Test for Get All SuperHeroes API

Let's understand the above test:

  • Now before any of the tests will start executing, our SharedFixture code will run and it will fire up the test container as you can see in the below image:
Test containers in action
Figure 2 : Test containers in action
  • In the Arrange step, I added a few records directly to the database using the SharedFixture.
  • After the above step, there are some records in the system and in the Act step, we will be trying to call the GET superheroes API.
  • If everything is correct, we should be able to see our tests being passed like below:
Tests passing
Figure 3 : Tests passing

This is it for the setup with database. I will be covering more in the future articles like, how to work with authentication, events etc.

For reference, the code repository being discussed is available at github: https://github.com/ajaysskumar/SuperHeroSolution

Thanks for reading through. Please share feedback, if any, in comments or on my email ajay.a338@gmail.com

Copyright © 2025 Dev Codex

An unhandled error has occurred. Reload 🗙