Mocking

Intro

Mocking is one of those concepts that, once you understand it, fundamentally changes the way you test software. Without mocks, writing robust and flexible tests becomes cumbersome.

I still remember the first time I used Python’s mock module—it was like unlocking a superpower. Suddenly, I could test edge cases, simulate failures, and isolate units like never before.

But when I transitioned to C development, I was surprised to see many libraries and teams skipping mocks entirely. Why? C doesn’t include mocking tools out of the box—but that doesn’t mean mocking is impossible. In fact, GCC and Clang give us powerful mechanisms like __attribute__((weak)) and linker wrappers (--wrap) that make mocking both possible and elegant.

This post explores those two techniques and shows how to use them effectively.

Mocking in C with weak and wrap Techniques

Every C project I've worked on used GCC or Clang as the compiler. These compilers support something called function attributes. These are special keywords that give the compiler additional information about how to treat functions—they can influence code generation, optimization, and linking behavior.

One particularly useful attribute is weak:

The weak attribute causes the declaration to be emitted as a weak symbol rather than a global. This is primarily useful in defining library functions which can be overridden in user code...

In other words, using the weak attribute allows us to override a function with a mock version at compilation time.

The second mechanism is linker-based wrapping. It allows you to define a wrapper for a symbol during linking. However, it has a limitation: you can't wrap a function defined in the same compilation unit as the code calling it. For example, if file A.c defines two functions—a() and a_nested()—and a() calls a_nested(), you won’t be able to mock a_nested() via wrapping since it's in the same file.

According to the ld documentation:

Use a wrapper function for symbol. Any undefined reference to symbol will be resolved to `__wrap_symbol`. Any undefined reference to `__real_symbol` will be resolved to symbol. This can be used to provide a wrapper for a system function. The wrapper function should be called `__wrap_symbol`. If it wishes to call the system function, it should call `__real_symbol` ...

By passing -Wl,--wrap=foo to GCC, we can mock the foo() function.

Using the weak Attribute

Define a weak function in your application code:

void my_function(void) __attribute__((weak));

void my_function(void) {
    printf("Weak implementation of my_function.\n");
}

Then, in your test code, provide a "strong" override:

void my_function(void) {
    printf("Mocked implementation of my_function.\n");
}

Compile both files together using GCC or Clang. The strong version from the test will override the weak one.

Using the wrap Linker Technique

In your test code:

void __real_my_function(void);

// Wrapper function
void __wrap_my_function(void) {
    printf("Mocked implementation of my_function.\n");
    __real_my_function();
}

During compilation, add the following flag:

gcc -Wl,--wrap=my_function ...

This causes references to my_function to point to __wrap_my_function, while __real_my_function still refers to the original.

Comparison: weak vs wrap

Feature weak wrap
Simplicity ✅ Easy to use ⚠️ Requires linker flags
Flexibility ⚠️ Limited to internal files ⚠️Limited to external files
Portability ✅ ️ GCC/Clang only ✅ ️ GCC/Clang only

Conclusion

Both of these techniques give you powerful tools to mock nearly any function in your C projects. If you're looking for a practical utility that wraps all of this into a small library, check out my project here: c_minilib_mock.

Published:

Last updated:

Category: C

Comments

Leave a comment