As applying unit-test to some C code, we run into a problem that some static function can not be called at the test file, without modifying the source code. Is there any simple or reasonable way to overcome this problem?
-
Possible duplicate of [How do I test a class that has private methods, fields or inner classes?](https://stackoverflow.com/questions/34571/how-do-i-test-a-class-that-has-private-methods-fields-or-inner-classes) – Raedwald Dec 14 '17 at 12:48
-
4Definitely not a duplicate of a question that must be for C++ or some other OO language since C does not have classes, private methods, fields or inner classes. – Jonathan Leffler Feb 14 '20 at 15:44
12 Answers
I have a test harness. In dire cases - like trying to test a static function, I use:
#include "code_under_test.c"
...test framework...
That is, I include the whole of the file containing the function under test in the test harness. It is a last resort - but it works.

- 730,956
- 141
- 904
- 1,278
-
-
5@BhupeshPant: What don't you understand? If a function is `static`, it is not accessible outside the translation unit (roughly, source file) where it is defined. The solution in the answer ensures that the function to be tested is included in with the code that tests it by copying the source code to be tested into the file that tests it via the `#include "code_under_test.c"` directive. The compiler sees the code to be tested and the code that does the testing all as a single translation unit, so the test code can call the static function, something which would otherwise be impossible. – Jonathan Leffler Nov 12 '14 at 06:38
-
I got it! Thanks for your prompt reply! why cannot we add the wrapper functions based on our conditional compilation type. – Bhupesh Pant Nov 12 '14 at 07:21
-
-
If your unit test is written and compiled as C, it should be okay. If your unit test is written and compiled as C++ (e.g. boost unit test) and you include a C file as in the example above, which in turn includes a C++-aware header, things can get complicated. I have no better solution, though. – Sascha Aug 04 '15 at 07:57
-
5This causes a problem for me when `code_under_test.c` contains both static and non-static functions, and is linked together with my test file. The non-static functions are then defined twice. – Joost Apr 13 '17 at 08:15
-
1@Joost: It's difficult to see how this can cause doubly-defined symbol errors unless you link the object code from the 'code under test' file twice, once through the code that includes it, and once for the ordinary build. If the file defines all the external symbols as usual and the regular object file is built into a library, the symbols that the object file defines will be ignored because they're already satisfied — whether that's a dynamic (shared) library or a static library. If you list object files in the linker command line, then you must omit the object file for the code under test. – Jonathan Leffler Apr 13 '17 at 21:21
Can you give more information as to why you can't call the function?
Is it not available because it's private to a .c file? If so, you're best bet is to use conditional compilation that allows for access to the function in order to allow for other compilation units to access it. For example
SomeHeaderSomewher.h
#if UNIT_TEST
#define unit_static
#else
#define unit_static static
#endif
Foo.h
#if UNIT_TEST
void some_method
#endif
Foo.cpp
unit_static void some_method() ...

- 733,204
- 149
- 1,241
- 1,454
-
1I like this hack out. The only trade off is to leave some strange token like `unit_static` in productive code. – shen Jan 29 '21 at 05:17
For unit tests, we actually have the test code within the source file itself and we conditionally compile it in when testing. This gives the unit tests full access to all functions and file-level variables (static or otherwise).
The unit tests themselves are not static - this allows us to call the unit tests from a single super-test program which unit tests all compilation units.
When we ship the code, we conditionally compile out the unit tests but this isn't actually necessary (if you want to be certain you're shipping exactly the same code you tested).
We've always found it invaluable to have the unit tests in the same place as the code you're testing since it makes it more obvious that you need to update the tests if and when the code changes.

- 854,327
- 234
- 1,573
- 1,953
-
3I do that when the unit test is small enough to fit. When the unit tests become bigger than the source under test, I resort to separate test programs, which can either link with the object (when only using the external dependencies) or use the trick in my answer when playing with static functions. – Jonathan Leffler Feb 27 '09 at 04:02
No - you cannot directly test a static function without modifying the source at least a little (that is the definition of static in C - that it cannot be called from a function in a different file).
You could create a separate function within the test file that just calls the static function?
For example:
//Your fn to test
static int foo(int bar)
{
int retVal;
//do something
return retVal;
}
//Wrapper fn
int test_foo(int bar)
{
return foo(bar);
}
We usually don't test our static functions directly, but rather ensure that the logic they perform is adequately tested by different tests of the calling function.

- 18,873
- 12
- 63
- 78
-
8That's not really unit testing if you don't test functions directly. – Raffi Khatchadourian Aug 24 '12 at 14:21
If you are under Unix environment you can include in test file additional header yourheader_static.h
with declarations of your static functions and translate obj file code_under_test.o
through objdump --globalize-symbols=syms_name_file
to globalize local symbols. They will be visible as if they are non-static functions.

- 228
- 3
- 6
#define static
This is a very bad idea. If you have a variable declared local to a function, it changes the behavior of the function. Example:
static int func(int data)
{
static int count = 0;
count += data;
return count;
}
You could call the function from the unit test, as func() would be exported, however the basic functionality of the code would be modified.
--kurt

- 61
- 1
- 1
static functions are essentially helper functions to the public (i.e. exposed) functions. So IMO, your unit tests should call the public interface with inputs that exercise all the paths in the static function.
The output (return values / side effects) of the public function should be used to test the effect of the static.
This means you need to have appropriate stubs to 'catch' these side effects. (e.g. if a function calls file IO, you need to provide stubs to override these file IO lib functions). The best way to do this by making each test suite a seperate project/executable and avoid linking to any external lib functions. You can mock even C functions, but it's not worth the effort.
Anyway, this is the approach I've used so far and it works for me. Good luck

- 616
- 1
- 5
- 25
-
3Yet the whole point of bottom up testing is that you _don't_ need to "call the public interface that exercise all the paths in the static function". Otherwise it's like while testing a car you also check every single nut and bolt matches its specifications. Better to test the nuts and bolt production separately, and if that is OK you simply check the car drives correctly. Not sure I explained that well... – Razzle Dec 29 '20 at 12:57
-
@Razzie, I get your point. I guess it's where you draw the line of abstraction. For me, with unit testing, I treat inspection of the nut as a unit test and the whole car as an integration test. In this context, static functions would be the material composition of the nut. Testing static functions would require invasive probes that pollute the source code (like drilling holes in the nut) – Dushara Dec 29 '20 at 20:58
-
Interesting idea, but I don't see the need to treat static functions as 'not software, but material'. Static functions (and macros) in C are the simplest 'units' - right at the bottom of 'bottom up testing'. At the simplest they are the easiest to 'unit test': Pass a set of input arguments and check the output args and any return value. Ideally these tests would be kept close to the code itself, like a 'self test' button on an appliance you buy in a store. – Razzle Dec 30 '20 at 13:26
Just to add to the accepted answer by Jonathan Leffler, and elaborate on other's mention of a wrapper function:
- Create a test source file, as in test_wrapper_foo.c, where foo.c is the original.
- In test_wrapper_foo.c:
#include "foo.c" // Prototype int test_wrapper_foo(); // wrapper function int test_wrapper_foo() { // static function to test return foo(); }
Assuming that the static function foo in foo.c has prototype: int foo(void);
build test_wrapper_foo.c through your makefile instead of foo.c (note that this will not break any dependencies on functions in foo.c by other external functions)
In your unit test script, call test_wrapper_foo() instead of foo().
This approach leaves the original source intact, while giving you access to the function from your test framework.

- 1
- 1

- 466
- 4
- 8
-
However, you will compile `foo.c` twice this way. Once for the original and another time when included in the wrapper. – LeSpocky May 18 '21 at 13:29
All the above suggested answers (except a few) suggest conditional compilation which requires modification to source. As such that shouldn't be an issue, it just would add clutter (just for testing). Rather you can do something like this.
Say your function to be tested is
static int foo(int);
You make another header file called testing_headers.h which will have the contents -
static int foo(int);
int foo_wrapper(int a) {
return foo(a);
}
Now while compiling your c file for testing you can force include this header from the compiler options.
For clang and gcc the flag is --include
. For Microsoft C compiler it is /FI
.
This will require absolutely 0 change to your c file and you will be able to write a non static wrapper to your function.
If you don't want a non static wrapper, you can also create a non static global function pointer initialised to foo.
You can then call the function using this global function pointer.

- 33
- 5

- 8,993
- 3
- 26
- 49
You could add a non-static function to call the static function, then call the non-static function.
static int foo ()
{
return 3;
}
#ifdef UNIT_TEST
int test_foo ()
{
if (foo () == 3)
return 0;
return 1;
}
#endif

- 14,495
- 5
- 33
- 67
-
-
Yes, it modifies the source, but doesn't remove the "static" from foo. Otherwise, the answer is pretty much that you can't call a static from the outside. I took a liberty. – Paul Beckingham Feb 27 '09 at 03:44
If you're using Ceedling and trying to use the #include "code_under_test.c" method, the test build will fail because it will automatically try to build "code_under_test.c" once when #included and also because it's the target of the test.
I've been able to get around it by a slight modification to the code_under_test.c code and a couple of other changes. Wrap the whole code_under_test.c file with this check:
#if defined(BUILD)
...
#endif // defined(BUILD)
Add this to your test harness:
#define BUILD
#include "code_under_test.c"
Add the BUILD
define to your Makefile or project config file:
# Makefile example
..
CFLAGS += -DBUILD
..
Your file will now build from your environment and when included from your test harness. Ceedling will now not be able to build the file a second time (ensure your project.yml file does NOT define BUILD).

- 11
- 2
There are 2 ways to do this.
Include the c source file into the unit testing source file, so the static method now is in the scope of unit testing source file and callable.
Do a trick:
#define static
in the head of unit testing source file.
It will convert keyword static
to "nothing" or I can say, it removes static
from your c source code.
In some unit testing tool, we can use config option "pre-processor" to do this trick, just put in the config:
static=
The tool willl convert all static
keyword to "nothing"
But I must say, using these ways make the static
method (or variable) loses the specific meaning of it.

- 5,889
- 2
- 20
- 44
-
2Suddenly exposing a lot of functions and variables that were declared static at file scope could lead to conflicts that should not occur. More seriously, suddenly converting variables that were declared static at function scope (inside a function) to non-static typically completely wrecks the functions. Thus, the `#define static /* as nothing */` trick is not reliable. – Jonathan Leffler Sep 07 '15 at 15:41
-
Yes, you are right. It is just a trick in case we had considered what we need to test, just the content of static function or all the things relate to it. – Van Tr Sep 08 '15 at 11:34
-
1Interestingly, the `#define static /*as nothing*/ ` is just what cmocka (the unit testing framework evolved from Google's cmockery) recommends (which is what gave me second thoughts about using it) – hmijail Mar 30 '16 at 17:16