Once more I get into a training session on unit testing, and once more I hear “It feels wrong to change my code just for testability.”
My immediate reaction was “because the design you have right now is so good, right?” (yes, I said it out loud).
Let’s break it down.
Good Design, Bad Design
Any design is a choice. All problems have multiple solutions, and the current design you have was the chosen one. It may also look like a giant god class (or a demon class, like in our subject). It’s like that because you (and others) have made design choices over weeks, months or years not to tidy it up. You may have excuses:
- I didn’t write this legacy code
- If I change it, it may break something else
- It’s an architecture created by someone else
- I don’t have time
All may be valid, and still – excuses. You, as the current caretaker of the legacy code, decide whether to continue with the current design or change it.
Once we’ve passed that, let’s assume you want unit tests around this code, because why was I invited in the first place?
The reason you want unit tests is to enjoy their benefits. First among them: The ability to change the code with confidence. Unit tests (and other kinds) raise your confidence about the status of your software. When you change your code for fixing bugs, adding features or just plain refactoring, you want to know things that worked, still do.
So now the question is: If you want unit tests (a wise choice), what are you willing to do to get them? Is changing the code part of the cost?
Again, it’s a matter of choice.
All code is testable. With power tools like Typemock or PowerMockito, we can mock whatever we want. Therefore, we can write unit tests around legacy code that’s packaged in any design. Or we can use less powerful tools and require to change the code in order to unit test and mock. There are always tradeoffs. Price, for example.
Here’s another: One of the problems I have with PowerMockito is that it sometimes throws a VerifyError (that’s unverified byte-code error, not the method-was-not-called error) which mere mortals don’t understand, and don’t know how to work around. So I’d rather persuade people to use regular Mockito than face unsolvable problems. And Mockito requires changing the legacy code, where the “It feels wrong” discussion started.
On the other side using the power tools and leaving the legacy code as-is is also a choice. If you built unit tests with PowerMockito or Isolator on crappy code, and leave the legacy code crappy even though now you can improve it, it’s a choice (a crappy one).
Tools don’t make people write better code. They don’t allow bad code to thrive either.
Your design. Your decision.