Write an Integration test, not a Unit test
Tags: dotnet, testing, architecture, csharp
Published: 2022-05-04 05:32:38

_As a lazy software engineer I want to write code only when necessary. If I happen to write code I want to utilise it as much as possible. If this sounds like you, then let’s look at how Integration tests can allow your code to be more efficient._

## Too Long To Read
Write both, **Integration** and **Unit** tests, when you have enough time or it’s a critical piece of your system. Write **Integration** tests first when time is off the essence.

## More…

> Integration test — is a type of software testing in which the different units, modules or components of a software application are tested as a combined entity.

Unit test proves correct work of **one unit** only. Whereas an Integration test proves work of **more than one unit**.

### System Under Test
Why is it important to understand what is System Under Test? It will help us define the efficient test.

> System under test (SUT) — system that is being tested for correct operation.

It’s normal that **Integration** test covers wider SUT than a **Unit** test. Let’s consider the following test:

```csharp
[Fact]
public async void IntegrationTest()
{
    var client = new HttpClient();
    var model = new Model();

    var result = await client.PostAsync(_url, new StringContent(JsonConvert.SerializeObject(model)));
    var expectedModel = JsonConvert.DeserializeObject<Model>(await result.Content.ReadAsStringAsync());

    var response = await client.GetAsync($"{_url}/{expectedModel.Id}");
    var actualModel = JsonConvert.DeserializeObject<Model>(await result.Content.ReadAsStringAsync());

    Assert.Equal(expectedModel.Id, actualModel.Id);
    Assert.Equal(expectedModel.Name, actualModel.Name);
}
```

The SUT for the test above is the whole journey of a request in a web service (Controller, Service, Repository and Database). Depending on our assertions we can catch a potential issue in all layers of this web service.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/upgcj6z85co7ad8bm5kq.png)

Here is how a **Unit** test might look for Controller in a web service:

```csharp
[Fact]
public async void UnitTest()
{
    var serviceMock = new Mock<IService>();
    serviceMock.Setup(p => p.MyServiceMethod()).Returns(true);
    var controller = new MyController(serviceMock);
    
    var model = new Model();
    var expectedModel = controller.MyControllerMethod(model);

    Assert.Equal(1, expectedModel.Id);
    Assert.Equal("Expected Name", expectedModel.Name);
}
```

The SUT for the test above is one layer (Controller):

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cfix1cq4pi6yayh2uau1.png)

As we can see, **Integration** tests cover wider SUT than **Unit** tests with similar amount of code.

### Bottom Line
Writing a proper Integration is challenging as it requires initial set up. Yet it pays off with time. Invest your time at the beginning and get a sense of stability about your code later.

Here is how you can ensure you’re writing an **Integration** test:

🗄️ Use a test instance of database, a test tenant in an external dependency etc.

🖥️ Use test servers instead of mocking and stabbing.

🐳 Use Docker for easier dependency management.

## Resources

1. My [example](https://github.com/alkondrashov/cars) of an **Integration** test. Refer to the README for instructions of how to run it.
2. I've discovered a nice Diagram editor: [Mermaid digram editor](https://mermaid.live/).