Poor man’s unit tests for C (and maybe C++)

Developing software is mostly about tradeoffs.

Make the software easy to use by getting rid of advanced features? Make the software featureful but harder to use?

Make the software comfortable to develop for but invest a lot of time setting up frameworks and maintaining them? Or make the software a bit less comfortable to work on, but avoid spending a bunch of learning/maintaining the frameworks?

Well, it’s all up to you, and I have a strong belief that people shouldn’t have strong beliefs about this! Er, okay.

Let’s say you want to add a couple tests (b.c) for individual static functions hidden in a .c file somewhere (a.c). Well, you can’t access those static functions from other .c files. Put the tests in the .c file? Some people would call it ugly. You could also write a script that concatenates the source file and test file and compiles that instead! Bit messy. You can’t have multiple main() functions, etc. But have you ever considered making the “static” keyword disappear using the C preprocessor? It works! And it can be messy too because it’ll make your static variable non-static. Great. But there are cases where that doesn’t matter, especially when we’re just trying to run some unit tests. Here’s a minimum example:

a.c

#include <stdio.h>

static void a()
{
    printf("Hi :,\n");
}

b.c

void a(); // prototype

int main(int argc, char **argv)
{
    a();
}
$ cc -o foo a.c b.c
/usr/bin/ld: /tmp/ccpspoxC.o: in function `main':
b.c:(.text+0x15): undefined reference to `a'
collect2: error: ld returned 1 exit status
$

It doesn’t work, duh. Because a() is static.

And now we’re going to make static disappear and it’ll work, so you can put all your tests in what we called b.c:

$ cc -Dstatic= -o foo a.c b.c
$ # no errors

If you don’t have control over the code base you are working on but still want some quick tests, this hack may be useful.

Leave a Reply

Your email address will not be published. Required fields are marked *