Yazının Türkçe versiyonuna bu link ile ulaşabilirsiniz.
How can integration tests be run easily in the CI pipeline? In this article, we will try to find the answer to this question using Docker containers.
I was working on a project and trying to write an integration test but having difficulty managing external components. I started looking for ways to automatically create message queues, database servers etc. before running the tests, and to clean those components after the tests were executed. I came across an open source package called TestContainers. I really liked this package and wanted to create a small demo so I could help people who had similar difficulties while writing the integration test.
You can access the sample project via the GitHub link.
Let’s Create the Project
We will prepare a very simple ToDo WebApi project for demo purposes. Through this WebApi, we will perform the following operations.
- Creating a ToDo
- To be able to query ToDo with Id
- Labeling ToDo values as “Completed” or “Incomplete”
First of all, let’s create our ToDoItemModel class whose model is given below.
Next, let’s create our class that inherits the DbContext that we call ToDoDbContext.
We will ensure that scripts are created to configure our database via dotnet-ef. After this process, we will modify the Startup class as follows. By doing so, we will make sure that the necessary changes are made in the database with the first request.
We can start preparing our ToDoController class. To keep the demo simple, we will code business rules directly here.
We have created an application with business processes that we can test. Now we can move on to the testing phase.
Creating a Test Environment with Docker
We will write our test cases using the xUnit library, a library that will be familiar to those who write unit test. We will run our application on TestServer and test our application via our test cases. Below we can see the code block that creates the version of our application running on TestServer.
Here, we come to the main focal topic. Our application would create the database tables that should be on the Sql Server with the first request. So before running our application instance we will need to configure and run a Sql Server. For this, we add the following code snippet to the space left blank with three dots in the above code snippet. We abstract our problem by imagining that the method named BuildSqlServerTestContainer will give us an executable container.
We encapsulated the configuration logic of the Sql Server container via a method called BuildSqlServerTestContainer. In this method, we will obtain the connection string through the DbContext class. Using the connection string, we will extract the port and password information we need to provide for the Sql Server that the application wants to connect to.
We can create a container from the Docker Image we want by using the TestcontainerBuilder class. DotNet.TestContainers library provides built-in interfaces for frequently needed components such as Sql Server, RabbitMq. We set the port and password of our container using the interface provided by the package below.
We designed a representation of Infra. It’s time to create the object of this class before running the tests. For this, we can use the Collection Fixture feature offered by the xUnit library. By doing so, we will use a single Sql Server for all our test scenarios. The reason we avoid create multiple Sql Server Containers is that creating containers is costly, both in terms of time and memory.
Below, we can see the test scenarios of the GET operation of the ToDo source.
We have tests to check if our Get-ToDo endpoint is working properly. It is time to run these tests automatically on the CI pipeline.
Let’s Run Tests on the CI Pipeline
By adding the below yml file into the project, let’s make the tests run on GitHub Actions in every git-push operation. Thus, we can be sure that our application will work as expected with every change we make.