Introduction

If done well unit testing adds value to the systems you are building. Much like code which runs on your production environment and your users interact with needs looking after so do unit tests. Unit tests like all code needs maintenance, refactoring and keeping relevant. If unit tests aren’t looked after then they can accrue technical debt like any code.

Unlike system code if unit tests become too much of a hindrance they just get commented out or deleted as developers see them as too time consuming with no benefit.

A good way to keep unit tests clean and up to date is to have them well structured. Much like your production system code you are testing should be well architected the tests should be thought about and well structured as well. This includes restructuring and refactoring as required.

Arrange, Act, Assert

For unit tests part of this is adhering to the Arrange, Act, Assert, or AAA, structure. This helps developers setup and structure the unit tests in a specific way and make it clear where code should go.

[Fact]
public void MyTest_Method()
{
    // Arrange


    // Act


    // Assert
}

As you can see from the above the first thing I do when creating a new unit test is add in the comments to define the lines between the 3 areas. This helps me structure my thinking to how to layout my test. It also makes it clear what each section is trying to establish. On many occasion I have seen quite unstructured tests which do something, assert the change, do something else and then assert something more. Now I’m not saying this doesn’t happen. Sometimes it does and sometimes you’re unable to remove this complexity but for the majority of the time setting up a unit test should follow this pattern. You can also see it as a time where you probably need to refactor the tests as they are doing too much.

Remember the Single Responsibility Principle can apply to unit tests as well as production code.

Arrange

This is likely the largest part of the test. You want to setup the test data which is required to execute the System Under Test. You need to setup the dependencies, whether mocks, fakes, stubs etc. as well as the input scenario data.

You usually start off setting up the arrange phase by hand but this can soon get out of hand. One of the largest frustrations of developers is if they change the constructor signature of class which is being tested. This will instantly break all the tests which have been setup manually. This is one of the most common reasons I’ve seen why tests are ignored or commented out. If this is the case then either the class is doing too much and needs refactoring and/or the test needs refactoring to use some tools for automatically setting up the System Under Test. This will allow refactoring with less friction. At least then if the test fails it’s the functionality that has changed not just the test setup.

Act

This should, for a majority of the time, be one line of code. The action or process you are testing. This may or may not have a return value. But this should be the only code being executed in the act section.

Assert

We need to check the system has done what we expect. This is another contentious area of unit testing around how much should you assert. The sanctimonious in the testing world say each test should have 1 and only 1 assertion. I disagree. Assert what you’re testing for. If the thing you are testing for requires multiple assertions then assert them.

What are the other benefits of adding in the comments to the tests? As discussed it helps on initial writing of the tests to make sure you are putting the right construct in the correct place. But also it gives other developers, not just junior developers, in your code base guidance around what you are trying to portray in the test. With minimal cognitive load you can see where something needs updating or changing or where you expect something to be.

Conclusion

Over the years I have been through a number of stages with my interactions with unit testing. I’ve been at the “these don’t help” phase. I’ve been at the “they don’t build while I change this so I’ll just comment them out” phase. But I’ve also seen the absolute power of good well written unit tests. Ones which stop regression bugs. Ones which prove bugs and help you solve them. Ones which make sure all the rest of the functionality continues as before while you fix said bug.

If you look after them; they will look after you.

And remember like with everything in development … “It depends”!

Any questions/comments then please contact me on Twitter @WestDiscGolf