Possible Duplicate:
Best practices for retrofitting legacy code with automated tests
I’ve been working on a project in Flex for three years now without unit testing. The simple reason for that is the fact that I just didn’t realize the importance of unit testing when being at the beginning of studies at university. Now my attitude towards testing changed completely and therefore I want to introduce it to the existing project (about 20000LOC).
In order to do it, there are two approaches to choose from:
1) Discard the existing codebase and start from scratch with TDD
2) Write the tests and try to make them pass by changing the existing code
Well, I would appreciate not having to write everything from scratch but I think by doing this, the design would be much better.
What would be your approach?
1
Rewriting from scratch just so you can have automated tests is silly – you have a codebase that (mostly) works, and you probably can test it (just not automatically). A rewrite, even with all the tests in the world, introduces extra risk, and it always takes longer than expected. So don’t do that.
Writing tests to achieve 100% coverage in one go is also silly, because it means you are halting on-going development to implement something which doesn’t add any value yet. In most situations, this is unacceptable. Further, writing tests for code that already works and doesn’t need changing has little benefit other than verifying that it does indeed work (but if it’s running in production, you better be pretty sure about that already).
The best way to go, IMO, is to add tests as you go. That is, for every change you make, apply the following steps:
- See whether existing tests sufficiently describe the current functionality.
- If necessary, add tests to capture the current functionality of that particular part / module / class / function / … Verify that they pass.
- Refactor existing code if necessary.
- Modify the tests to reflect the intended new behavior.
- Modify the code to make the tests pass.
- Refactor.
Steps 4 through 6 are just basic TDD; the only addition is that you retroactively add tests as needed before you start the actual TDD cycle.
If you follow this procedure, and the tests you add in step 2 are sufficient, the codebase will gradually move towards full test coverage.
Of course, if you are going to rewrite anyway, for different reasons, then going TDD right from the start is probably a good idea.
1
Legacy code is working code, it has been tested in the wild. The worst thing you can do it throw it away and replace it with new code. Even with the best new code (with TTD ect) will have occasional bugs.
What I would recommend it every time you hit a bug you create a unit test around that functionality. Its not much extra work when your fixing things anyway and will mean the more buggy areas will get unit tests first.
Well, I would appreciate not having to write everything from scratch but I think by doing this, the design would be much better.
This is a very wrong assumption. Testing has nothing to do with design. You need to understand the benefits of TDD in more details.
Ideally if you have a stable working product which do not require any change, test cases will not help you. Automated tests only help you with re-factoring or feature addition.
For an existing project, the best way is to analyse the change (re-factoring / feature / bug-fix) and then write test cases for only that code.
EDIT: I do no accept the fact that testing impacts. but even when it does, we have the problem of ends-means reversal. Design should be bases on problem domain, and not on testing . TDD is just a means to achieve the end, which in this case is solving the problem in hand.
3