6

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?

Jeffrey
  • 63
  • 6
  • you need to show (at least excerpts of) the part where you define method1 and how you #include the various headers into the sources – TemplateRex Aug 31 '16 at 18:14
  • @TemplateRex added includes. method1 is just any old method in the driver1.c file with a declaration in the driver1.h file. – Jeffrey Aug 31 '16 at 18:19
  • you can't add another `method1()` in driver2.cpp and link it together with driver2.cpp into the test driver. If you want to mock, you should tell CMake not to compile driver1.cpp as a dependency for test_driver2.cpp – TemplateRex Aug 31 '16 at 18:29
  • And how would one go about doing that? – Jeffrey Aug 31 '16 at 18:32
  • 1
    Why can't you have two different builds, one that includes the problematic header and one that doesn't? Inclusion of the header can be controlled by make. – 2501 Aug 31 '16 at 18:33
  • @2501, the problem is that this is a much bigger network of drivers and tests that I'm working with and it would be nice to have a general solution that can work for this example above because this is what I am having problems with. Also, including the header is not the problem, it's the double definition, although it seems as if we're on the right track so far. – Jeffrey Aug 31 '16 at 18:37

1 Answers1

3

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.

TemplateRex
  • 69,038
  • 19
  • 164
  • 304
  • Thanks! I'll add the ability for my python build script to just run all executables in the directory instead of just tests.exe, so that I can have multiple builds, like 2501 mentioned. Will come back with +1's and accepted answers if I can get this change in. – Jeffrey Aug 31 '16 at 18:41
  • +1 Works great! The thing that I was missing was just having multiple compilation units for each test, which is much easier than trying to get them all into one. – Jeffrey Aug 31 '16 at 19:18
  • @Jeffrey great to have been of help – TemplateRex Aug 31 '16 at 19:24