Tuesday, June 4, 2013

Why Unit Testing Constructors and Properties is Necessary

I have come across developers in the past that see little value in Unit Testing things like Constructors and Property getters/setters. Some devs see these as fruitless exercises just to bump code coverage numbers. The point of some is that setters/getters don’t really do anything and that complex code does not belong in constructors. I agree, this should be the case but not always true. I frequently run across abuse on constructors and properties. We also can not guarantee that ongoing maintenance from new developers or other teams (in big software houses) will follow best practices. Of course the same argument can be said about maintaining Unit Tests, but if you have made it this far I am assuming we are an advocates of TDD and do not need to defend it.

So, I offer a couple of examples of why Unit Testing properties and constructors is necessary. These come from real-world scenarios and clients but have been renamed to protect the innocent. Both examples come from production code which is serving up millions of hits a day.

Unit Testing Constructors

public void MyObject(string property1) :
   this(property1, null){}

public void MyObject(string property1,
   SomeCustomObject property2)
{
   if(object.ReferenceEquals(null, property1))
      throw new ArgumentNullException(“property1”);

   if(object.ReferenceEquals(null, property2))
      throw new ArgumentNullException(“property2”);

   this.property1 = property1;
   this.property2 = property2;
}

Take a close look at the error handling in MyObject(string, string) and the values MyObject(string) passes into it. MyObject(string) will always throw an exception. I’ve seen this in production code in a public library. If the original dev would have unit tested the constructors this issue would have been caught before it was published. As it is now, consumers of a public API can unknowing use a constructor that will always fail.

Unit Testing Properties

public bool MyProperty
{
   get { return myProperty; }
   set
   {
      this.myProperty = value;

      if(myProperty)
         this.myOtherProperty = “Some Value”;
      else
         this.myOtherProperty = “Some Other Value”;
      }
   }
}

First of all, the code around myOther property should not be here. It violates the Single Responsibility Rule for good object oriented programing and should not pass a code review. But here it is, and this kind of thing happens often. Unit Testing this won't throw up a failed test or show some flaw in logic. However, Unit Testing this should throw some red flags - needing to validate another value when testing a Setter or Getter should be a Code Smell.

Now the argument for both examples are that they are examples of bad code - not bad Unit Testing. Agreed, they are examples of bad code. However, TDD will call these issues out before they are checked in.

These are pretty trivial examples and much more horrible examples do exist. Unit Testing helps us identified flawed logic and violations such as the Single Responsibility Rule which is commonly violated in my clients' code bases.  Unit Testing is not reserved only for complex methods but should be used for the mundane as well.

Best rule of thumb for Unit Testing I learned from a mentor:  If it can be Unit Tested - Unit Test it.