Unit Testing Is Boring

Unit testing is really really boring. It is waste of time and productivity, writing unit-tests is hard, takes long and might require time-taking refactorings to the code for it to be unit-testable. Regression testing is anyway a lot more effective in finding mistakes. Besides, unit testing provides very little value as it doesn’t tell anything about the quality of the software. Adding unit tests to code which has already been proven working by functional testing is just stupid.

That may sound a bit exaggerated, but I’m almost serious here. There are times when adding unit tests is really waste of time. There’s a lot of code which is hard or near impossible to unit test properly. But the last part about code being proven working by functional testing is in my opinion bullshit. Functional testing tests functionality and can prove that desired functionality has been achieved, but it cannot prove that the code does what the developer intended it to do. And no matter how much functional tests you add on top of your software, it doesn’t make the code any more maintainable.

Let me tell you  how I define testing and unit testing.

Testing gives quality information about software. Qualities being e.g. functionality, usability, reliability, performance etc. We do testing in order to determine the current quality level of a certain software. This information can be further used to make decisions e.g. whether to release the software now or later (or never which is a brilliant decision in some cases).

Unit testing does not give you any quality information about the software or it’s functionality, but it does give you information about the  quality the code. There is a difference. Unit testing, if done properly, can prove that the code does exactly what the developer intended it to do. Of course there might be mistakes made when deciding what the code should do, but that’s a different story. Unit testing also makes code easier to maintain and further develop.

To be able to unit test code, the code needs to be unit testable. This usually also means the code is cleaner (clean as in Clean Code) which makes it easier to understand and change the code. And when the code is covered with good set of unit tests, it is also safe to change the code. Every code written has a price. There’s a price to develop the code, but there’s (often even larger) price to maintain the code. Clean code which is covered with unit tests has a smaller price tag than code which is not that clean and/or is not covered with unit tests.

Adding unit tests to code is boring. This is true. And if the code will not be further developed, it is complete waste of time as well. Unit tests do not add much (or any) value when written afterwards, specially if long time has passed since the code to be tested was written. As said, adding unit tests to code which was not written to be unit testable in the first place is laborious and often requires big refactorings to be made before unit testing can take place. And as there are no unit tests to cover poor developer’s ass, those refactorings might break things really badly. Luckily there are good old books to help in tasks like this. Do read Martin Fowler’s Refactoring and Michael C. Feather’s Working Effectively with Legacy Code.

So, this far we’ve learned that unit tests often don’t add any value, are difficult to write and the whole thing is also really boring. Forget unit tests completely? No, I’ve found a nice solution which you’ve probably heard earlier as well. It’s called test-first programming or test-driven development (TDD). I personally like most the term red/green/refactor. After I learned to do TDD (as if I meant it) I’ve enjoyed writing code a lot more. Nowadays I don’t often get to write code, but when I do, I use TDD and I love it.

And even if you didn’t like TDD or don’t want to try it (if this is so, I’d like to know why), you can still add the unit tests while you’re writing your code. Then you must think about unit testability before you write the first line of production code. Code design must be done so that adding unit tests is easy.

As a final note, consider Martin Fowler’s words and think about this the next time you’re writing code:

Whenever you are tempted to type something into a print statement or a debugger expression, write it as a test instead.

Advertisements

On Unit Test Coverage and Code Complexity

A team lead approached me asking what should they define as minimum unit test coverage percentage and code complexity metrics. I had to think about my answer a bit and came up with following, which I think is worth sharing to others as well.

Unit-test Coverage %

The more good unit tests there is covering the code, the easier it will be to read, understand and change the code later on. Excellent answer to the question of what should the coverage be can be found from StackOverflow: http://stackoverflow.com/questions/90002/what-is-a-reasonable-code-coverage-for-unit-tests-and-why

If you still insist on having a target percentage, I’d personally recommend to aim for 100%, which is achievable if you use strict TDD. By strict I mean following the Red-Green-Refactor pattern with discipline. There’s a good presentation about this on InfoQ: http://www.infoq.com/presentations/TDD-as-if-You-Meant-It.

Being more reasonable, specially if you already existing code base, you might set the target to 70-80%. Keep in mind though not to stare at the numbers only! Bad tests also give you high coverage but not much confidence or easier refactoring. For this as well, there’s an excellent article available: http://www.sustainabletdd.com/2011/12/lies-damned-lies-and-code-coverage.html

Code Complexity

Code complexity  figure tells quite well how easy it is to read and change the code. It also affects unit testability as smaller methods are generally easier to unit test. I’d aim for cyclomatic complexity of less than 10 per method. More complex code usually contains more bugs as well, so if you find some parts of the code to be more complex, do focus your testing efforts on that area.

We have one project where we have set up our Jenkins job so that it becomes unstable if the amount of complex methods grows. This project now has average method complexity of 5.25. Still there is one methods with high complexity (23 in fact) and about 50 methods of medium level of complexity (10-20).

There might be a good reason for high complexity number e.g. an event handler with a long switch clause. While this might be avoided with polymorphism (see http://sourcemaking.com/refactoring/replace-conditional-with-polymorphism), but this might also make the code more difficult to maintain.

Summary

It’s good to early enough think about code maintainability and the speed of development in the future. Unit test coverage and code complexity are factors which affect those a lot. Other things worth investing to are code reviews as a standard practice and pair programming. Both work as fast feedback cycles to catch not only defects but also code which is difficult to maintain.

In the end it’s up to you and your Product Owner to decide how much do you invest in code quality. Code which is simple, produced with TDD and covered with good unit tests is cheaper to maintain in the future. On the other hand, if these factors are not taken in account, it’s like taking a loan from the bank. You’ll manage a long time by just paying the interest, or parts of that, but eventually you need to start paying back the debt as well. Or take another loan.

It’s more likely that you will produce Clean Code when you have proper measures in place to early detect code going bad. Also worth to note is that you should always aim for writing as less code as possible. A nice article on this subject: http://mikegrouchy.com/blog/2012/06/write-less-code.html