Today and during the coming couple of weeks, I’ll be writing on topics that are all somewhat connected to each other. They all are going to be about long-term consequences of our decisions in software development.

This is the first email in that short series, and it’s about the cost of code.

1. The question

This email is inspired by a question I received to one of my Pluralsight courses. Here’s the condensed version of it:

You mentioned that simple one-line properties are too trivial and are not worth testing.

But in larger or longer-running projects, someone could tweak them for a hack or fix. Is it correct to assume that their behavior will never change?

Writing unit tests for these one-liners is trivial, and takes only a minute for each one.

Doesn’t the confidence that no one will accidentally break your code by tweaking setters and getters justify writing the extremely simple unit tests?

That’s a great question. I’d like to split it in two parts. Let’s talk about this one first:

Is it correct to assume that their behavior will never change?

There’s no need for such an assumption. You can test this code as soon as it becomes complex enough.

This is where code coverage tools become useful. If you read my Unit Testing book, you might remember how I described code coverage as an insufficient metric for determining the quality of your tests.

This is true (I haven’t changed my opinion), but code coverage metrics are still useful in some scenarios. One of them is seeing which parts of your code are tested and which are not.

With such tools, as soon as you introduce complexity (i.e branching) in those simple properties, you will see that some of that complexity is untested.

[Enable Images]

Here for example I’m using NCrunch that shows which lines are covered with tests (green dots) and which aren’t (black dots).

These black dots are a clear sign that you need to consider testing the new complexity (the guard clause).

2. Long-term vs short-term costs of the code

Now, to the second part of the question:

Writing unit tests for these one-liners is trivial, and takes only a minute for each one.

Doesn’t the confidence that no one will accidentally break your code by tweaking setters and getters justify writing the extremely simple unit tests?

Writing such tests is easy indeed. But that’s not the main reason why I advocate against it. The cost here is two-fold:

  • Writing such a test

  • Maintaining it throughout the project lifetime

Between these two components, the second part is much more important than the first.

Writing a code is a one-off activity, you only need to do it once.

On the other hand, reading and maintaining the code is a continuous process. The costs of that process add up over time. Consider all these activities that become more lengthy when you introduce new tests:

  • Refactoring tests when you refactor the underlying code

  • Running tests on each code change

  • Dealing with false alarms raised by the tests

  • Spending time reading tests when you’re trying to understand how the underlying code behaves

If it sounds like a lot of work, that’s because it is. Hence, you should pay very close attention to what tests you allow in your test suite. It’s better to not write a test at all than to write a low-value test, even if that test itself is simple.

Note that this guideline is true for all your code, not just tests. You read code much more often than you write it, and so all your code should be optimized for reading, not writing it.

--Vlad

https://enterprisecraftsmanship.com


Enjoy this message? Here are more things you might like:

Workshops — I offer a 2-day workshop for organizations on Domain-Driven Design and Unit Testing. Reply to this email to discuss.

Unit Testing Principles, Patterns and Practices — A book for people who already have some experience with unit testing and want to bring their skills to the next level.
Learn more »

My Pluralsight courses — The topics include Unit Testing, Domain-Driven Design, and more.
Learn more »