Refactoring and Tests, Strange Partners in Bed
FAQ: Can we REFACTOR when we don‘t have tests (automated unit and/or acceptance/functional)?
Automated unit and acceptance/functional tests are always very important. But does that mean one cannot refactor without them?
Let‘s consider what happens if we just refactor code without having any automated tests. You run the risk of breaking working code (well, we are not too sure if it is working or not. But let‘s assume it was working). The bigger risk is you won‘t know the code is broken till regression testing. Consider yourself lucky if you find it out in the regression cycle. Most of the times, these errors surface straight away in production.
So the FEAR of introducing bugs while making internal changes to the code, builds a horror in people‘s mind. This horror keeps us away from changing simple things in the code. At times, I was scared to even rename local temp variables.
Certainly this fear will kill a person. So it does not make any sense refactoring the code without any automated tests, without any ways of checking whether what we did was correct or not. So does it mean if there are no tests we cannot refactor?
I would say, WE CAN.
How? Read on…
1. Build some courage and confidences
2. Every time you touch a piece of existing code, either to fix a bug or to enhance it, you must understand the code. Refactoring can help you a lot to do so. (Catch 22?)
3. Take a small piece of code; look at it from a black box tester‘s point of view. See what it is trying to do. Given some input what is the expected output.
4. Write a unit test for what you have understood. Run the test and check if it passes.
5. Every time a unit test passes you know you understand the code better. Go on adding small unit tests and make sure all of them pass.
6. Once you feel you have covered all the scenarios and you have unit tests for each of these scenarios. You must have a better understand of the code and an automated unit test suit ready for that small method or code.
7. When all the tests are passing you are in the right position to refactor the code for better understanding and communication. To make the code easier to understand and communicate better, you need to simplify the code using the various refactoring techniques. This is when you do the magic. Refactor.
In this fashion, iteratively over a period of time, you will build a better test harness around your code giving you more confidence to refactor rigorously. Once you have built some confidence in the code, you can do some trivial refactoring like extract method, rename, introduce explaining variable, pull up method/variable, etc without really having unit tests.
Having automated unit tests is a must, but is it sufficient to rigorously refactor? I feel much more comfortable having an automated functional/acceptance test suit running all the time. I would like to do a bunch of refactoring and then validate them against an automated functional test suit. So I know the code is working at unit and functional level.
In this whole process, please understand the importance of automated test suits. You cannot achieve the same effect with manual tests.
Bottom-line: Where there is a will, there is a way.