Dotnet6 Integration Testing with Sqlite Database

Evren Pehlivan
inventiv

--

Integration testing provides different application components functionality working accurately together. Dotnet6 supports integration tests using different unit test frameworks. In this article, we will be implementing an integration test using an sqlite database. An sqlite db can be an effective way to test an EF Core application. In unit tests, components are mocked. On the contrary, integration tests ensures all related components and their infrastructures work properly without mocking. Although integration tests are slower than unit tests, all components combined together while testing.

Brief Info About Testing

Below we will elaborate more on the testing types, namely, unit testing, functional testing and integration testing.

Unit testing

The smallest part of a project is called unit which can be a function, a class or any other component. The main purpose of unit testing is to guarantee that every independent/individual component of the software is working as designed.

Functional testing

On the other hand, functional test is result-oriented and tests whether the features are working. The main goal is to ensure a functionality works as it is supposed to. The correctness of the used data is not very important while testing.

Integration testing

Integration testing can be used to test the components which are interdependent. The aim is to piece together the different modules of the software and ensure their correctness. While methods can pass the unit tests in individual basis, some issues may arise when they are combined. With the help of integration testing, these problems can be detected and solved before deployment.

SUT (system under test) Project

Now create an example SUT project. In the sample project we will retrieve a user list via web api. Firstly, we create a repository class which includes crud operations and DemoContext configurations which uses SqlServer in “Program.cs”

Then, we will define User entity, UserDto and their mappings.

Infrastructure

Since we will be using only one user table in this sample project, the DBContext only contains User entity.

After that, we will create repository which includes read part of crud operations for our example

Lastly, api controller will be created

Let the tests begin!

The test requires followings:
A test project with reference of SUT.
A web host for the SUT and a test client server communicates with the SUT.
NUnit as test adapter and runner.

In order to create a unit test, we need to complete all listed steps below.
- Configure web host
- Use a test server client for requests.
- Prepare request parameters
- Create a request and receive the response
- Make assertion
- Wait for all test executed and get reported results

DemoContextSqlite

Different migrations are created to be used in sqlite. The reason for this is that different migrations are created for each db provider. Types in sql server may have different equivalents in sqlite, same functionality may not be supported. So, we created a custom DbContext named DemoContextSqlite.

TestWebApplicationFactory

TestWebApplicationFactory is a custom implementation of WebApplicationFactory. The necessary settings for the test project are defined here. Other DbContexts, if any, are deleted from the IOC container. So that there will be only DemoContextSqlite and DemoContext classes that we defined in the test project. Migrations for SQLite are run here in the MigrateDbContext method at runtime.

TestBase

For all test fixtures, base class is used. Infrastructure works are taken care of here. For methods that are called once to perform setup before any child tests or methods that immediately before each test are run described here. Also to use client for creating requests are defined in this class.

Up to now we have prepared to arrange and act infrastructures that are needed for test methods. Lets use them in test methods. “Get User Should return valid data” method defined to test GET “api/user” endpoint. First, a user created via repository. Then, get request is sent to endpoint. Since returned response is a json array, its content deserializes into UserDto list. First item of list is assigned to actualUser variable. In assertion, expectedUser should be equal to actualUser.

In the conclusion, writing test for our projects is very important step to prevent errors that we may encounter before going live. In this article, we explained what integration testing is and how you can apply in your projects with examples. If you choose the appropriate test method for your application and use it, you will increase the predictability in your project. By this way many serious bugs can be nipped in the bud if they are detected early enough that may arise in the future. We wish you to encounter fewer mistakes in daily life and to realize them before they explode on your face.

See you in our next articles,

Thanks to Ali Karaca and İncilay Dikbıyık for great contributions.

Get the code here…

--

--