How to cover legacy code with unit tests
In one of my firmware projects, I needed to display QR Codes onto a display.
I found reasonably good code which I could reuse, but unfortunately, this code was not covered with unit tests, so doing any modification to it, was risky. This is a path I no longer want to go.
So the solution was simple : add unit tests to the existing code, so I could refactor it with peace of mind. Here is a step-by-step example.
Testing the end result
I generated a few different QR Codes with the original library and scanned them with a dedicated scanner as well as my phone, and they all worked. So I assumed the library was working more or less OK. This means I could use these examples as test-vectors to test that at any stage of refactoring, the refactored library still generates the same output as the original one. Looking at the test-coverage of those first tests, I could compose a set of test-vector-QR Codes that covered most of the scenarios. (size aka. 'version', error-correction-level, contents-type, ...)
Testing the internals
The above tests, give me some reassurance during refactoring, but the end-to-end test is still a monolithic, large one and it would better to have many smaller tests.
While reading Thonky's QR Code Tutorial, I learned that to generate a code, you need to follow a sequence of steps :
领英推荐
So it made sense to try to build tests around each of those steps. In fact, in the existing code, I found that each step was implemented using a few functions, so the next step was to try to isolate all those functions and unit test them.
Conclusion
In just a few hours time, the unit testing approach allowed me to dissect the code, understand how it worked and make it more robust and more readable. All this without ever losing the grip on solid ground of a proven, working library.
Try it and you'll never go back to how you did it before.