Today we’re going to take a look at a concrete example of how we can handle integration tests in a CI pipeline.

Last time I gave few options of possible platforms. I am working with Gitlab in my daily job so the code today will be focusing on it. But the concepts can be applied basically everywhere.

All the sources are available as usual on GitHub.

The solution is not extremely interesting, there are just 2 projects: Users and Users.Tests.

The Users project exposes a basic User model, an EntityFramework Db Context and a Repository. I have added few tests for this last class in the Users.Tests project, specifically in the UsersRepositoryTests class.

The tests themselves are pretty basic, just making sure the FindById() method of the repository returns a proper value with valid or bad input.

The DbFixture class is basically the core of the project: it is responsible of reading the configuration from a file and acting as Factory for the Db Context.

The important parts are how it reads the config and how it builds the connection string. Let’s take a look.

The project has 2 config files, appsettings.json and appsettings.CI.json . The first one is used as default and holds the connection string that can be used on your localhost.

On the CI environment instead we will be using the other one as it defines the specific connection string we can use there.

We know if we’re running on CI or somewhere else by reading the default environment variable ASPNETCORE_ENVIRONMENT . Building the configuration then is a piece of cake thanks to the ConfigurationBuilder class:

var builder = new ConfigurationBuilder();

this.EnvironmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? string.Empty;
if (!string.IsNullOrWhiteSpace(this.EnvironmentName))
    builder.AddJsonFile($"appsettings.{this.EnvironmentName}.json", true);

var config = builder.Build();

For more details about configurations in .NET Core, make sure to read this article on the Microsoft website.

Now take a look at the connection string in the config file. It is used as a “template” to build the final one like this:

var connString = config.GetConnectionString("db");
this.ConnectionString = string.Format(connString, Guid.NewGuid());

This trick allows us to have a different db name for every test class using the Fixture. We can even push this further and have distinct db names for every test by moving the code to the BuildDbContext() method.

Make sure to read the article on the XUnit website for more details about fixtures.

Now that we’ve defined the integration tests, let’s take a look at the CI pipeline. In the .gitlab-ci.yml file you can find two jobs, “build_project” and “run_integration_tests“.

On the very first line I’ve specified the base image that will be used by all the jobs in the pipeline. This is relative to my Docker registry so feel free to update it to whatever suits your needs.

The build_project job is very simple, it just restores the Nuget dependencies and the runs dotnet build.

The second job is also simple, but with a little twist: by leveraging the “services” keyword, we can add additional Docker images that will be executed along the primary one. We will be using this to spin up the MSSQL instance.

In the “variables” section we also define the credentials for the sa account. We can safely use it as it will be only relative to the db container and won’t affect anything else.

If everything is correct, after every commit you should see something like this: