Monday, December 20, 2010

A case for testing getters, setters and properties.

Conventional wisdom suggests that getters and setters (a.k.a. properties) are simple enough that testing them is unnecessary unless some branching logic has been introduced. This is advocated in any number of books on the subject of unit testing. This is what I thought as well. After all, most properties simply assign and retrieve a value without any manipulation.

Today I discovered a reason that may make it worth while to test even these. I spend most of my time working with legacy code. Often times I am uncomfortable making changes without the safety of a test harness so I'll take advantage of automatic test generation to create skeleton tests from production code that I can fill in as I work.

The tool I use for this isn't terribly smart. It just creates a class of test cases for each public method it finds in the production class its given. Each test case calls each method but leaves the Assertion up to the developer to fill in.

I had just created a new test harness from a production class I needed to modify. I ran the tests without any changes, meaning no checks were being done. I fully expected the tests to succeed since the framework I was using didn't consider an assertion-less test to be a failure. I was amazed when it did in fact fail.

The reason for the failure was a stack overflow caused by a getter returning the value of the property it was as a backing function for rather than the value of the backing field. This of course resulted in an endless recursion that quickly exhausted the call stack. This bug had never turned up in production because this was a base class that wasn't used directly and all descendant classes overrode that particular getter.

This subtle bug is more likely to happen in languages like C#, Object Pascal and Python (and several others) which hide the getter and setter calls behind a more friendly syntax that allows them to be assigned like public fields.

MyObject.PropertyValue = 123;

So even before any of the tests were verifying results they had already uncovered a bug in one of the simplest operations possible.