Unit tests code smells – Interacting Tests

Interaction between unit tests is a problem that sometimes sneaks in between our tests and goes unnoticed there for a long time. Once we add another test and unexpectedly tests that were previously green change to red, even though we are sure that we didn’t break anything that could cause that. To make it worse, running them in separation shows that they are fine again.

Most often, this situation occurs when we:

  • Add a new test,
  • Move test between different suites,
  • Change the name of the test,
  • Run tests in parallel.

The reason for this may be the tests interaction with each other by sharing the same fixture or using global resources, which are not properly cleaned after the test was performed.

These are sample tests that will depend on each other

[TestFixture]
public class TestSuite
{
    private readonly IModelProvider modelProvider = new ModelProvider();

    [Test]
    public void Should_BeEmpty()
    {
        // Act
        var sut = new ModelService(modelProvider);

        // Assert
        modelProvider.GetAll().Should().BeEmpty();
    }

    [Test]
    public void Should_AddItem()
    {
        // Arrange
        var model = new Model
        {
           Id = "030B4A82-1B7C-11CF-9D53-00AA003C9CB6",
           Name = "Model_030B4A82-1B7C-11CF-9D53-00AA003C9CB6"
        };

        // Act
        var sut = new ModelService(modelProvider);
        sut.Add(model);

        // Assert
        modelProvider.Get(model.Id).Should().NotBeNull();
    }
}

We test ModelService, which carries out CRUD operations. To do this, it uses a ModelProvider that stores the state with model objects. For a long time, the suite consisted of only 1 test, which checked if the ModelService is empty after creating it, so the created ModelProvider could be initialized once for this suite. During the next iterations, we added another test called Should_AddItem, which passes when run in isolation, but when we run all the tests in suite, the Should_BeEmpty test is red. I bet you already know what’s going on! ModelProvider is shared by both tests, so depends on which test runs first, Should_BeEmpty may be false negative. We can fix this very easily by creating a new ModelProvider for each test

[TestFixture]
public class TestSuite
{
    private IModelProvider modelProvider;

    [SetUp]
    public void SetUp()
    {
        modelProvider = new ModelProvider();
    }

    ...
}

This is a fairly simple example, I think a lot of people knew immediately what was up, but sometimes it takes a lot of dependencies to prepare a test, then we can easily miss that one of them is shared. It may happen that a bug goes unnoticed until a new test is created or changes are made to existing ones, causing a lot of surprise for developer.

Interaction between tests is not good due to:

  • Tests are no longer deterministic,
  • The order in which they are run can make a difference,
  • It is more difficult to trace the steps of the test execution and find the failing reason,
  • Adding another test or changing a suite may cause additional work for developer.

In my opinion, the biggest problem with this code smell is that it can stay unnoticed for a long time, and it tends to shows up when we least expect it and we don’t expect that we will have to spend a lot of extra time due to a small change in tests to get them back into shape.

The example uses the NUnit library. xUnit is more careful in these situations and creates a whole new object for each test but you can still fall into that code smell when using the IClassFixture<> interface. Due to the simpler syntax I used NUnit in this case.

This is part of the code smell in unit tests series. If the described problem happened to you, please share your story in the comments below. I also encourage you to follow this series, another code smell is coming soon!

1 thought on “Unit tests code smells – Interacting Tests”

  1. Pingback: dotnetomaniak.pl

Leave a Comment

Share via
Copy link
Powered by Social Snap