Thursday, November 06, 2008

Legacy Tests

In Working Effectively with Legacy Code, Michael Feathers states that, for him, "legacy code is simply code without tests". As he says it himself, he has "gotten some grief for this definition". I can understand why.

I have come to deal with some legacy code monsters recently and came to realize that this code had tests written for it. So could it be that this code was not legacy after all?

After a closer inspection, the truth finally came out:
  • the test coverage is very low (less than 30%),
  • the tests explore counter-intuitive paths (for example, just the unhappy ones),
  • the tests themselves are monstrous (created in what looks like a copy/paste spree),
  • they overuse mocks in a lax manner (many are not verified at tear down),
  • they do not verify the complete state after execution (no validation of indirect outputs like request and session attributes),
  • and, corollary of the legacy framework the code targets (EJB 2), full correctness can only be proven when deployed in an application container.
I immediately thought of chapter 9 of Uncle Bob's Clean Code, where he advocates that unit tests should be written with the same care than for actual code. The tearful hours I spend refactoring these tests so I can then refactor the code they are supposed to exercise, are a good testimony to this imperious necessity. Keep tests clean!

Else you will end up with nearly worthless legacy tests.