A very simple mocking strategy for straight C

In keeping with my “you really can unit test anything” position, here’s a simple strategy for injecting mocks into straight C code. It’s ultra dumb. I’m sure you could come up with it yourself but here it is for you. If you don’t like the context bit (so you can mock the method in just one file) then get rid of it. But I found it to be helpful.

---------- mocks.h#ifndef NDEBUG
// trigger this if not debug (could use any criteria you like)
#define C_MOCKS_ENABLED 1
#endif
#ifdef C_MOCKS_ENABLED
#define C_MOCK_DEF(context, api) __typeof(__typeof(api) *) mockptr_##context##api = &api;
#define C_MOCK_REF(context, api) extern __typeof(__typeof(api) *) mockptr_##context##api;
#define C_MOCK_SET(context, api, mockapi) (mockptr_##context##api = &mockapi)
#define C_MOCK_RESET(context, api) (mockptr_##context##api = &api)
#define C_MOCK_USE(context, api) (*mockptr_##context##api)
#else
#define C_MOCK_DEF(context, api)
#define C_MOCK_REF(context, api)
#define C_MOCK_SET(context, api, mockapi)
#define C_MOCK_RESET(context, api)
#define C_MOCK_USE(context, api) api
#endif
---------- subject.hvoid PrintTheThing(void);---------- subject.c#include <stdio.h>
#include "mocks.h"
#include "subject.h"
// these compile into nothing in the NDEBUG build
C_MOCK_DEF(subject, puts);
#define puts C_MOCK_USE(subject, puts)
void PrintTheThing()
{
puts("The thing");
}
---------- subject_test.c --- only works in debug build#include <stdio.h>
#include <string.h>
#include <assert.h> // or whatever testing thing
#include "mocks.h"
#include "subject.h"
C_MOCK_REF(subject, puts);// good enough for a dumb demo.
int correct;
static int mock_puts(const char *foo)
{
correct = !strcmp(foo, "The thing"); // dumbest mock ever
return 0;
}
void PrintTheThing_Test()
{
C_MOCK_SET(subject, puts, mock_puts);
PrintTheThing(); assert(correct); C_MOCK_RESET(subject, puts);
}

Under the test conditions the real “puts” is never called. It could have been anything. The macros use the modern typeof() construct to create a pointer of the correct type given the method you want to mock.

It’s very effective and still boils away to nothing when not in the debug build.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store