DEV Community

Cover image for Write an Integration test, not a Unit test
Alex Kondrashov
Alex Kondrashov

Posted on

Write an Integration test, not a Unit test

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:

[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);
}
Enter fullscreen mode Exit fullscreen mode

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

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

[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);
}
Enter fullscreen mode Exit fullscreen mode

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

Image description

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 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.

Discussion (7)

Collapse
ecyrbe profile image
ecyrbe • Edited on

First of all,
even if i do not agree with the message of your article, it's a well written one and explains clearly how to test WEB APIs as a whole , so thanks you.

Now on the part a disagree with, here is my point of view.
Integration tests are costly, e2e tests are even more.

I would always recommend unit testing first unless it's not possible (design issues that force to do integration tests).
When developping a feature, you can do unit tests within your workflow (TDD). Which allow for early bug fixing and early refactoring.

It's impossible to do the same with integration testing since you need to have developped a huge part of your system before even considering it.

And even then, how can you be confident where is the issue when you have integration errors?

You have no unit tests, the problems you'll face could be in one part of a pretty Big system.. And it may even not be an integration issue... You'll have a hard time debugging and fixing.
Integration tests are there to check integration issues, not check your code has no bugs. Unit tests are here for that.

Thanks for reading.

Collapse
carlovo profile image
Carlo van Overbeek

I guess the truth is somewhere in the middle. TDD can be done on integration tests as well. Also, on unit tests you usually have to mock out stuff, but what are you going to mock if you haven't yet decided on the implementation? In the end, the test design choice of a good developer beats a static rule of what tests to write first.

That being said, the best developer experience I ever had was on a project where I had to extend integration tests and then build functionality for it. Some unit test were there as well, but had only been build in the start of the project. Newer parts were not unit tested. When the bigger picture of the project became clear the shift was made from unit test to integration test driven design. I think I'm going to advocate this flow as well if I'm at a new project inception.

Collapse
kondrashov profile image
Alex Kondrashov Author

I had similar experience where I would TDD with integration tests. Worked well

Collapse
kondrashov profile image
Alex Kondrashov Author

Thanks for the comment and for reading my post.

I do agree with you that Integration testing requires more time setting up than Unit testing. I also do agree that with Integration Tests you will spend more time debugging and locating the exact place in the code that errored out. Yet, the Pros will outweigh the Cons.

Unit testing might give you confidence in one layer, say a Service layer. However when you run the Controller, Service and Repository together - there is no proof that it's all working.

You might re-use a lot of your setup across different Integration tests. Once you spend time setting it up for one test, you will most likely save time setting it up for other tests.

Obviously it might happen that Unit testing is better for a given project than Integration test, but my post was largely targeted to general CRUD web services where you would get the most benefits with Integration testing.

Loved reading through your comment!

Collapse
varian97 profile image
Varian Caesar

When the deadline approaching, I agree with you that integration tests come first. But personally I think this is come with one major cost, either your integration test will become very detailed (because it tries to test things that should be tested in unit test) or your integration test not cover much use cases (because you skip the unit tests that should test various things, like edge case for that function/class/whatever).

At the end of the day, the main important thing is to also include time to create tests (both unit and integration tests) into your project deadline estimation. Nice article by the way

Collapse
kondrashov profile image
Alex Kondrashov Author

Thanks for your feedback.

Regarding very detailed integration test: I came across this problem before. To solve it I've added a new Integration test per each use case. This helped me to keep my tests not too detailed but cover as much functionality as possible.

Collapse
chris79 profile image
Christine Barber

This is very interesting content! I have thoroughly enjoy reading your points and have come to the conclusion word that you are right about many of them. You are great! Word Hurdle dordle