My Octopress Blog

A blogging framework for hackers.

Test Code Quality

I’ve been meaning to write about this for awhile, but it always seems so contentious for some reason. I’m sure we’ve all seen the worst examples before. I once opened up a 5,000 line unit test of a Spring MVC controller. It got this bad because every bit of setup was cut and paste into each new test function. Of course, it should have been a sign to the original author that refactoring was needed when there was that much setup required in the first place. But it still begs the question: What level of quality should be expected of test code?

I’ve worked with lots of great developers that would see so much as a line of duplication and take it upon themselves to drop everything, including the donut in their hand, to remove it from code. However, when it comes to test code, that same developer would shrug their shoulders and say: ‘It’s only test code’. I just don’t get this. If lack of reuse and duplicate code would cause an aneurysm in normal code, why is it acceptable in test code? For that matter, why would the way you treat test code be any different at all?

When we write unit tests, it’s code we intend to last just as long as the class it’s testing, or at least until the assumptions we made about the code have changed. And given how slowly some companies could change even those basic assumptions, that could mean never. Testcode still needs to be easy to maintain, and easy to understand.

Here’s some of the reasoning I’ve heard:

I don’t want to make the unit test complicated, it should be easy to understand the intention


If abstractions and code reuse done properly can make code easier to understand, why would the same not apply to test code? How would duplication between two unit test classes aid in the clarity of the individual test?

Unit tests should be completely isolated from each other


I’ll agree to this in principle. But I think it can be taken too far. Unit tests should be able to be run side effect free. You should be able to run each individual test by itself, or with any number of other unit tests without the existence or absence of such tests causing failures. However, this has nothing to do with sharing abstractions with each other, or reusing the same setup data if more than one class under test uses the same domain objects. As long as you’re creating new instances in your test classes, and not accessing them through stateful static calls, there should be no issue.

Modifying one test to pass shouldn’t cause another to break


This is a tricky one that has bitten me numerous times before. If you create some kind of abstraction, such as some type of a builder to create a set of test data for multiple tests, you run the risk of breaking a lot of tests if you change something in the builder to make one pass. It can be extremely disheartening to watch the unit test you were working with pass, only to see hundreds of test failures when you run the entire build.

However, despite the pain this has caused me in the past, doesn’t this seem like a normal coding problem? Maybe it’s coupling/cohesion, or demeters law, or any other random law. There’s probably a perfectly well known refactoring mechanism to make this test code easier to modify without side affects. There is no reason not to apply them to your unit test code as well.

Now though, there comes the dirty part, that only an ‘Enterprise’ developer will know the unfortunate reality of. What if your test code looks nothing like your real code, but there’s nothing really wrong with it except it breaks many of the largely nonsensical ‘coding standards’ put in place by some type of ‘governing body’? What if *gasp* its better as a result?

Comments

Dokemion
When you are trying to learn java you have to under go training.