- Combination Testing, which gets you to full test coverage, just by reinspect which paths are not taken,
- Code Coverage as Guideance, which helps you to find the bits that you have not yet considered, and
- Provable Refactorings like automatic code transformations, which help you to be sure that you don’t break the code.
I have to admit that I am not yet fully convinced of this approach; however, it surely is a very useful first way to get at a (larger) legacy code base.
I have used a similar, albeit less formal, way to approach a larger legacy algorithm that I rewrote, and found it useful to inspect the existing behaviour with unit tests; sadly, I did not scaffold the infrastructure to keep the unit tests around, as the development environment was not very unit-test-friendly. It did make the approach manageable, but at some point I feel it to be necessary to add some functional knowledge to it.