In a previous article I described how to get started testing C++ code with the Google Test framework. In this article I’m going to share a few tips and tricks for testing C code.

So what’s the big deal, isn’t it just the same as C++?

Well yes, in a way it is, but as always the devil is in the details. Here are some of the challenges we face when trying to test procedural code:

We can’t create an instance of the code under test. This means that we can’t easily get a fresh object with initialized data for every test.

The dependencies are hardcoded. This means we can’t use dependency injection techniques to mock/fake the module dependencies.

We can’t use Polymorphism to break the dependencies

So that only leaves us with the two dependency-breaking tools available in the language: the preprocessor and the linker.

Things to watch out for

Static initialization: You need to be able to reset your data to a known state before running each test case. It is the only way to isolate your tests from each other.Global variables: Is you module accessing a global variable? You need to provide a fake implementation for this.Hardware Access: In embedded systems we often have memory mapped hardware register access. You most definitely don’t want to be dereferencing from random memory addresses in your tests. A good antidote to this is to define a generic function to get the address for a given register. You can then define a version of this function for testing purposes.

An example

So how does that look in practice? Suppose we have a make-believe embedded software application for controlling a device:

How do we approach testing this nastyness?

There are some challenges to testing code of this nature, but there are also methods we can use overcome them.

Infinite loops: these guys will destroy your ability to test effectively. The best approach is to move the body of any infinite loop into it’s own function call.

Dangerous Code: what you do on hardware in production can be dangerous to do in a testing environment. In this example we have a hardware access of memory mapped IO address. There are three ways we can deal with dilemma:

change the address we dereference,

change the function we call (at link time)

hide the function we call during testing using #ifdefs and provide a test fake (this is the approach I have taken here)

Incompatible Function Names: You can’t link two main functions. You need to hide one…

Static Memory: This can really hurt the independence of your tests. You really ought to re-initialize all of your static data for each test case, and thankfully there is an easy way to achieve this. All the major testing frameworks have a concept of a test fixture which allows you to call a SetUp function before execution of each test case. Use this to initialize your static data. Remember: independent tests are good tests!

The General Testing Pattern

1. Define fake functions for the dependencies you want to stub out
2. If the module depends on a global (gasp!) you need to define your fake one
3. include your module implementation (#include module.c)
4. Define a method to reset all the static data to a known state.
5. Define your tests

That’s all well and good, but what about <difficult thing>?

Interrupts. This is a special case of the last point, but it is the same issue all developers come across when going multi-threaded.

Bit-correct operations. If you are running 24-bit code on a 32-bit architecture you will not see the exact same behavior for various overflow, underflow, bit-shifting and arithmetic operations.

I can’t possibly test this! Well, there are some classes of code that simply cannot be tested using the unit testing methodology. In my experience however, it is an extreme minority of most code bases that this applies to. The secret is to factor out impossible-to-test-code as much as possible so you don’t pollute the rest of the codebase.

Summary

Testing C code is hard. Testing legacy C code is even harder. But with the limited dependency-breaking language features we have in C (the linker and the preprocessor) we can accomplish quite a lot.

33 responses to “Unit Testing C code with the GoogleTest framework”

Do you think googletest is suitable for testing C, or do you think there are more appropriate ones? I know googletest certainly can be used to create unit tests for C, but I don’t know if the extra work to jerry it is worth it, compared to one designed originally for C.

I think it really depends on the situation. If you have a project that is completely C then it would probably be a better idea to use a framework written in C. On the other hand, if you have a project with both C and C++ googletest might be best.

For me, I would go for googletest anyway because I really value some of the extra features it comes with (for instance it is really easy to integrate with the hudson CI server, and the ability to choose which tests are run at runtime).

My limited experience is that unit testing C code not designed to be tested is a walk in the park compared to it’s C++ equivalent. I work on rather low-level mixed C/C++ software. With the C parts it is normally feasible to isolate a reasonable subset of procedures and break their dependencies with linker and pre-processor as you say. With massive C++ classes with many dependencies (including two COM variants) I find the added dependency-breaking tools available fall far short of compensating for the additional pain.

Re testing timing and interrupt issues, I have nasty thoughts involving unit tests designed to run inside valgrind’s helgrind tool.

We just recently are starting a testing project for embedded C code,
and we are in the phase were we have to select a testing framework. We
are really looking to use googletest as our framework, but we have
encountered an issue which maybe you can suggest a solution, or
already have seen the problem and can help us, or maybe just point me
to any link that can suggest a starter.

Here it is,

We have separate modules, some of them requires using mocks. We know
we can make the mocks manually, but we were thinking to use some sort
of usefull tool provided for google test. I´ve read about google
mocks, but unfortunately they are developed in C++, and we cant use it
if we are developing and testing pure C code – it would require to
change a lot of stuff on the original code, which for testing purposes
we are not allowed to touch.

So, my question is, does someone already have encountered this
problem? Is there any mock solution that google test provide for C
pure? Does anybody has some link that I can read regarding this?

Every help would be much appreciated, dont hesitate to ask for more
information if it is needed in order for you to give a better help on
this topic.

It is easy to use, just download a header file into your project and you can create mocks with one line of code. At the moment it doesn’t handle const parameters but I am working on supporting it now.

I know others have used a framework called CMock which I believe is good but we didn’t use it because it needs to run before the build to parse your header files and generate the mock code. IT also requires ruby. If this isn’t an issue for you then it might be worth evaluating also.

I realize that this thread is a bit old, but if you’re looking to use CMock you probably don’t want to mess with GoogleTest. You’ll want to use the Ceedling ecosystem that includes Unity (unit test assertions), CMock (mocking framework) and Ceedling (automatic test discovery and mock generation).

And thanks Mike for all your great work! Looking forward to trying FFF at some point. I saw a talk of yours on YouTube (https://www.youtube.com/watch?v=DcFe6cEvnGQ) that really resonated with me. I also started in “professional software development.” Sadly, there is a lot of the embedded community that still operates this way. Glad to see people like you out there pushing for improvement!

Hi Mike! Great Blog! I’ve got a question to the example in this article.
Is there a reason for including the module implementation (myapp.c) into the testcode? Isn’t it more practicable to compile this module separately and link both objects (test.o and myapp.o) together? What are the Pro’s and Con’s?

Hi I am currently looking out for some good unit test framework for Embedded C programs. I have a doubt in Using google C++ test framework. I want to know whether can we test the inter OS communication methods using this framework like Message queues between two threads or between two process in embedded board? or is it basically limited to unit testing only?

It really depends on your situation, but googletest is designed as a unit testing framework. I have used it in the previous projects for Hardware in the loop testing, but always the test suite would run off target. For testing in target I think that a developing a custom testing strategy is the only choice.

Hi Mike,
My company has been using googletest for a few years now and we really like it. I have recently started a new C project and wanted to use googletest. After figuring out that googlemocks would not work I found your fff framework. The fff is working great. Thanks. One question. Why do you use ASSERT_EQ() and not EXPECT_EQ() in your example tests?

Hi Rob,
Both ASSERT* and EXPECT* do the same thing in regards to the test, the only difference is what happens if an assertion fails. With an ASSERT failure it immediately stops execution of further tests, however with an EXPECT failure it will continue executing after a failure. The advice is to prefer EXPECT except when it is critical that execution stop (so I could have used it here). Look at this stackoverflow question for more info:http://stackoverflow.com/questions/2565299/using-assert-and-expect-in-googletest
Cheers,
Mike

Your example supplies a inline test double (myapp_do_dangerous_io()). I would be interested in an example using seams .. where the test double lives elsewhere or multiple test doubles can be defined depending upon compile time switches. If one has legacy SUTs that cannot be changed as a religious requirement, I don’t see getting away from seams.

Also, the jump from C++ to C and back requires some addressability problems to be solved – like reinstantiating a this pointer used by Setup() at the very least.

Finally, the mocks for testing examples (and the examples themselves) are so simplistic as to generate major cynicism. It’s not that complicated mocks won’t work, we just never see examples using them and that in itself is a problem.

Hi Mike,
i have import your project from GitHub and create a “Run Configuration” using GoogleTest (Eclipse Kepler). But i don’t know, how to run the tests without using:
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();

Hi Mike,
I have buid googletest in eclipse. In the Release directory is only gtest.lib and i don`t know how to build gtest_main.lib.
To build the gtest.lib I only use gtest_all.cc. If I put an include gtest_main.cc into gtest_all.cc there is no success and if i put gtest_main.cc into the project there is build an gtest_main.o but no lib.
Sry…but i can’t find any solutions on google.

Hi, I was working on a very big C project, which we must test and leaders decided to do it with gtest. Maybe it is a mistake but one of my colleagues and me were assigned to that and have to test very high level functions with a lot of references. The
extern “C” {
void tested_func_prototype(void);
}
declaration in test source works fine in one occasion: Don’t forget to reference libraries with all the functions the tested function calls. You will need to specify only the tested function. Funcs that it calls are within a library linked to compilation of the test program.