Jeffrey Jeffrey - 3 months ago 17
C Question

CppUTest Unit Testing Framework Multiple Definition Exception

I will try to make this a purely minimal example to be as applicable to as many people as possible as well as protect any sort of code sharing that might violate an NDA. Hope this is okay!

I am using CppUTest and CppUMock (compiling with gcc/g++ and makefiles created with CMake) in conjunction with Gitlab Continuous Integration software to create a unit testing environment for future commits and release of software. However, I have run into a bit of a problem. Let's say I have the following folder setup (that I have minimal ability to change, other than the contents of the /tests folder):

+-- src
+-- driver1.c
+-- driver2.c
+-- inc
+-- driver1.h
+-- driver2.h
+-- tests
+-- test_driver1.cpp
+-- test_driver2.cpp
+-- main.cpp
+-- cmakelists.txt


The CMakeLists file will contain including of the inc folder, compilation of the src folder, and compilation of the tests folder. However, let's say that driver2.c relies on methods defined by driver1.c. This is fine if there is no mocking setup because you can just test the results of calls to driver2's methods normally. However, say that I want to mock driver1's method1 function so that I can check that driver2 calls method1 correctly (using CppUMock). This would usually be fine, if driver1 wasn't being compiled, but adding something like so to the test_driver2.cpp file:

void method1(int n) {
mock().actualCall("method1").withParameter("n", n);
}


Will cause a collision with the actual method1 in driver1.c with a linker error like so:

CMakeFiles/Tests.dir/.../src/driver1.c:(.text+0x11d): multiple definition of 'method1'
CMakeFiles/Tests.dir/.../src/test_driver2.cpp:(.text+0x0): first defined here


As per request of the commenter, here is what the include structure is like:

driver1.c includes driver1.h (obviously)
driver2.c includes driver2.h (obviously)
driver2.h includes driver1.h (for calling method1)
test cpp files include their respective .h files
(test_driver1.cpp -> driver1.h and test_driver2.cpp -> driver2.h)


method1 is declared in driver1.h and defined in driver1.c. I am not able to edit these files.

I'm happy to add details as requested.

What is the best way to get around this mocking issue?

Answer

If you want to mock method1 from driver1.h, just add the mocked definition in a separate mock_driver1.cpp and then in your CMakeLists.txt:

add_executable(target1 test_driver1.cpp driver1.cpp)
add_executable(target2 test_driver2.cpp driver2.cpp mock_driver1.cpp)

Once you are done mocking, replace the mock_driver1.cpp dependency with driver1.cpp.

This all assumes you have a separate executable for each test driver.

However, if you want to have one big main program where all drivers are linked together, then you cannot have both the real method1 and the mocked method1 co-exist together. For that, I'd recommend wrapping the mocked method1 in a namespace mock or something like that, and only call mock::test1 in test_driver2.cpp.