Category Archives: Clean Code

10 Golden Rules for Unit Tests

There are some rules of thumb I encourage my team to follow when writing unit tests and they are as follows:

1. System under test should be clearly defined.  A variable naming convention I have personally adopted is “sut” to stand for “system under test”.

2.  Each test should abide by the AAA principle of Arrange, Act and Assert.  There should be a clear demarcation between these three different aspects of a test.

3.  As part of the Arrange phase, all dependencies of the system under test should be clearly defined, and mocks used where to abstract away external dependencies, whenever possible. Also, always best to mock via interfaces instead of abstract base classes. No container registrations here and no hidden dependency injection into the system under test.

4.  As part of the Arrange phase, all additional dependencies such as file names or configuration items should be explicit and clearly defined. Avoid depending on external entities which will not guarantee consistency in your test results such as webservices, etc.

5.  During the Acting phase, it should be clear which of the APIs of the system under test is being exercised and this method being exercised should typically return a response.

6.  Assertion should be based upon the response of the method acted upon from the previous phase.  Assert the response is what you expect.  Avoid asserting that the method under test was called.  For example, this is a good assertion:

// arrange
var sut = new ResourceController();

// act
var result = sut.GetResource(new Dictionary()).ToList();
// assert
Assert.AreEqual(2, result.Count); 
Assert.AreEqual("Kanata", result[0].AdditionalProperties["placeofservicetypename"]); 

Assuming the same entities defined in the Arrange section above,

resourceCacheMock.Verify(sut => sut.GetResources(new Dictionary().....)

The latter does not guarantee we get the correct results but rather the fact that some other resource was invoked, which means we need to know internally how sut.GetResource works.

8.  Minimize the number of asserts in a test.  I would not say a test should be restricted to one assert as this is an artificial constraint which breaks down too often.  Instead, I would advocate for a minimalist approach, encouraging developers to ensure to think about splitting a test if the number of asserts is greater than 3 for example.

9.  Keep tests small or digestable.  It should be relatively straight forward to look at a test and determine what it is doing.  If a colleague cannot decipher the purpose of a test within a couple of minutes, it is overly complex or doing too much.

10.  Test names should be clearly indicate what the test is trying to accomplish.

Advertisements

Yet another practical pocket guide on writing clean code

Being a big proponent on crafting beautiful, robust and maintainable code, I have read several books and articles on the subject.  One of my favorite resources is a book titled “Clean Code” by Robert C. Martin.

I would propose that such a resource be readily available in the company library and would even go as far as advocating for every software engineer joining the company to either have read this book or is required to read this book as part of the on-boarding process.

In summary what is clean code:  Code which mostly abides by the SOLID principles of software design.  In my own words.

Methods should have a single responsibility.  It is better to have a class with many small methods that have a class with a small number of large methods.

Methods should not be overly long. A well known and acceptable measure is that a method should not span the entire code editor space in Visual Studio, when viewed over a 15″ laptop monitor.  For example, this is a long method:

On the otherhand, this is a nice, short and terse method:

Methods should return early if possible.  This avoid too many nested iffs.  For example, consider the following method which takes in input object of some sort

   private void InitializeActionMethods()
        {
            if (_configurationManager.Configuration == null)
            {
                Logger.Warn("Some configuration is not defined.");
                return;
            }

We fail fast and early.  In contrast, we could written the code like this:

   private void InitializeActionMethods()
        {
            if (_configurationManager.Configuration =! null)
            {
                // continue
            }

This creates a code base with too many nested-iffs which is hard to read and maintain.

Method names and variables should clearly indicate purpose.  I often say code is a story.  Write code as if you are writing a story.  Books with shorter paragraphs are more engaging than books with longer paragraphs.  I often see developers naming variables using acronyms instead of taking the time to craft out descriptive variable names. Again, if code is a story, we need to clearly identify the characters.

Entities themselves should have single responsibility.  This one is also easy to violate.  I have seem some very large and weird looking classes over the years.  I have also seen classes that are almost impossible to refactor and unit test as it is composed of a collection of large, deeply nested methods with a large number of inter-dependencies.  Keep classes small.  I have told my devs that is is better to have a code base with thousands of small entities that one with a small number of large entities.  The former system, if well organized, is easily to reason with, maintain, modular and robust.

Entities should have dependencies passed to them.  The term coined for this is dependency injection or inversion of control.  I always get confused here but the idea is for a factory to construct a car, it needs to have all of its dependent bits, such as assembly line, etc.  These must be explicit and defined up front.

Unit test, unit tests and more unit tests. I cannot emphasize this enough but any component in the system should have an associated unit test which is concise.  There are well documented strategies for crafting awesome unit test but they should abide by the AAA principle of Arrange, Act and Assert.  Google this. Also, make these test very easy to follow.  All dependencies should be arranged or created up front.  if you are resolving entities from some container somewhere, which includes configuring some sort of logger, which requires some additional piece of configuration somewhere, you probably need to step back and rethink your tests and class design.

Code should be closed for modification and open for extension, as stated in the Open/Closed Principle, code should be easy to extend but closed for modification.  This is a tough one but think if it this way.  If you start creating code with long switches, then it is time to sit back and think of some patterns to use.

Code should be robust against anomalies but at the same time need not be overly micro-optimized.  Beautiful code means that it is easy on the eye, easy on the mind, free flowing, yet robust against extremities.  This includes excellent exception handling and logging.

Happy Coding.