The title says it all. My company is reusing a legacy firmware project for a microcontroller device, written completely in plain C.

There are parts which are obviously wrong and need changing, and coming from a C#/TDD background I don't like the idea of randomly refactoring stuff with no tests to assure us that functionality remains unchanged. Also, I've seen that hard to find bugs were introduced in many occasions through slightest changes (which is something which I believe would be fixed if regression testing was used). A lot of care needs to be taken to avoid these mistakes: it's hard to track a bunch of globals around the code.

To summarize:

  • How do you add unit tests to existing tightly coupled code before refactoring?
  • What tools do you recommend? (less important, but still nice to know)

I am not directly involved in writing this code (my responsibility is an app which will interact with the device in various ways), but it would be bad if good programming principles were left behind if there was a chance they could be used.

2 Answers 2


Grab a copy of Working Effectively With Legacy Code by Michael Feathers. It is meant to deal with such situations. Even though it is focused more on OO languages such as C++ and Java, I believe it may still help you a lot.

Looks like part of it (or an early draft article) is even available for free here.

  • +1, thanks. But, I believe I am fairly good at refactoring OO code with more OO code. What I don't know is how to test procedural code, and refactor procedural code with less coupled procedural code.
    – vgru
    Aug 25, 2011 at 8:19
  • @Groo, the book is not about refactoring per se. It is about how to transform a bunch of spaghetti code without any unit tests into a bunch of (somewhat less spaghetti) code well covered with unit tests. Such code is hard to test, so you need to refactor first in order to make it testable; however, as you too mentioned, refactoring without unit tests is risky, so it is a catch 22 situation. The book guides you how to make the smallest, safest changes to the code which enable you to cover it with unit tests, thus subsequently start refactoring it in earnest. Aug 25, 2011 at 8:27
  • That book is a good suggestion and it covers C along with OO languages.
    – ThomasW
    Jan 11, 2012 at 0:02

For techniques, probably the Michael Feathers book in Péter Török's answer will be pretty comprehensive. If you don't want to go to the book, I suggest a three-step process:

  1. examine the non-testable code, and duplicate small parts of that code's functionality into testable functions. It's important that the new functions have behavior that's obviously equivalent to the function you're trying to duplicate - I'm not actually advocating writing unit-tests around the legacy code, so you need to be very careful, and limit your scope, in order to maintain confidence in the refactoring.
  2. write unit tests around those new functions.
  3. modify the original code to call the new functions.

Repeat this process a few times, and you should find the quality of the legacy code base has increased significantly.

As far as tools go, note that C++ can call into C, so any C++ unit-testing framework can be used to test C code. For example, we're using CPPUnit to unit-test a bunch of C code in our project.

  • +1 thanks for the tips and the CPPUnit link.
    – vgru
    Aug 25, 2011 at 11:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.