Too simple to break

07 April 2006

Every now and then, as is my wont, I get to thinking about unit testing, most often in terms of test-driven development. However, I have been known to countenance unit tests outside of that methodology, but you have to ply me with a good meal and an excellent bottle of wine and turn off the tape recorder first, though.

Many times developers write a class using simple properties; that is, properties which have the standard one-line get and set blocks. Using VS2005 this is simple enough with the prop snippet expansion (and is even easier with CodeRush, of course).

class Foo {
  public int Age {
    get { return age; }
    set { age = value; }

Now the question arises: is it worth writing a unit test for this property? The simplest would probably be this code.

public void ShouldReadChangedAge() {
  Foo foo = new Foo();
  foo.Age = 49;
  Assert.AreEqual(49, foo.Age);

But is this worth it? I would argue that, no, it isn't. In fact, there is also a school of thought that says that writing this kind of property is not worth while either ("just use a public field, dude"), but I shall address that question later on.

The code that implements this property is, in essence, "too simple to break". Instead, we should concentrate our testing efforts on code that is more intricate and more likely to break, such as code with higher cyclomatic complexity. Writing bad code for a property with a one-line getter and setter is pretty hard to do without being obvious about it, and you'll notice the bug pretty quickly too. (The only real example I can think of from the top of my head is to use the wrong backing field.)

Note that I'm not saying that it is wrong to write such a test. All I'm saying is that you'll get more bang for the unit-testing buck by writing tests for a more complex method (or property for that matter). (Examples of properties that should be tested: one whose getter invokes a calculation to get the value to return, or one whose setter involves several side-effects such as updating other fields or performing other calculations.)

I'm sure a unit-testing purist would undoubtedly say that not having a test for this property means that the property is untested and therefore prone to failure. This is quite right, but note that using the tools we have at our disposal, you must really want to write bad code to get this kind of property wrong. Also, unit testing, no matter how hard we try, is never guaranteed to uncover all our bugs.

What we try and do with unit testing is to use our judgment and resources and time to discover and fix bugs as soon as possible in the project's lifetime. Bugs discovered early are almost free to fix. Bugs discovered later are much harder to fix and cost a lot more in terms of time and resources. So we try and balance our time and resources writing production code with the code that tests it. Too much time spent writing unit tests can be just as bad as too much time spent writing production code. In the first case, we are gaining greater confidence in our code at the expense of much greater schedule time, in the second case we are getting the real code written faster at the expense of having a nasty bug (or bugs) possibly to be discovered by our customers. We have to learn to balance this more tests versus less scheduled time trade-off.

In essence, I'd say don't bother testing code that's too simple to break. But certainly be prepared to defend your assertion that the code you're not testing really is too simple to break.

Free DevExpress Products – Get Your Copy Today

The following free DevExpress product offers remain available. Should you have any questions about the free offers below, please submit a ticket via the DevExpress Support Center at your convenience. We’ll be happy to follow-up.
There are various reasons to use getter and setter methods rather than a public field, but one often stated one is that at some later point you may need to do more work when you get or set (log something, check for a cached version of something, whatever) and you won't want to change your interface.

Well, if this is a valid reason, isn't it also a valid reason to write the unit test?  At what point, when adding functionality to a get or set method, do you say "OK, _now_ it's complicated enough to need a test"?  Seems like you're better off just including the test.  Maybe it can be generated with CodeSmith.
18 April 2006
Its interesting to view different perspectives. You might read that comment and immediately assume that I differ with your basic approach to unit testing and I feel I agree with you.

However, it seems to really matter on just what product is being designed. I focus on business products that invlove financial transactions, ledgers,  inventories, and payrolls. From my perspective, the unit testing becomes an entirely different animal compared to a designer of components or add-ins to Visual Studio itself.

I find the opposite scenario to be true quite often and developers commonly  overlook proper testing because of the same "apparent" simplicity. For example, I cannot count how many times a number such as sales price was allowed to be negative. The repercussions are huge, sales personnel (with no financial background) will often exploit such a "minor" flaw to "fix" a sales order and break fundamental accounting rules in the process.

Thus, for me, the "core" of the product must be clearly understood to make such decisions. The values for positioning elements on the screen or general appearance properties take a backset to the "data objects".

Thus, perspective and mission are the base for my unit testing. I find the most important question to be: what happens if this value is allowed to be "wrong"? (and actually knowing the answer is the key) Unfortunately, there is no equivelent "cyclomatic complexity" tool to help with such decisions.

25 April 2006
Chuck Sphar
I've been coming to similar conclusions lately as I think a lot about unit testing. I've been reading J.B. Rainsberger's JUnit Recipes (an excellent book on testing even if it's about Java and JUnit), and he also uses the phrase "too simple to break" (hence too simple to bother testing).

A corollary of this view is that you won't get, and shouldn't kill yourself seeking, 100% test coverage.
29 April 2006
J. B. Rainsberger
When you're mostly learning how to write tests, write more tests. When these get/set tests bore you, stop writing them. When not having those tests hurt you, resume writing them...

I find my sweet spot is covering the 85% of the system most difficult to test.
26 March 2007

Please login or register to post comments.