How to mock non-virtual methods in c++ with gtest?

1.1k Views Asked by At

Is there a clean and easy way to mock non-virtual methods in c++ with gtest ? Despite using the GoogleMock way that force you to re-declare your mocked class.

This feature is essential in my point of view to enable the full potential of BDD, TDD and mocking in c++. I'm using FakeIt currently but I'm still encountering those difficulties :

  • Testing code without having to use virtual methods
  • Testing legacy code without impacting the current code

Edit : I found Injector++ and isolate++ that seems to be great solutions but not cross-plateform.

1

There are 1 best solutions below

0
On

Mocking non-virtual classes has been a pain for me from the start, I wanted to mock a class (both virtual and non-virtual methods) without touching the production code, so no templatizing or creating interfaces for each class.
This is how you can do it.

The trick is to replace the class of interest with a mock class. So how to do it ?

Lets say you have a production class named Production and you want to test that class, but it depends on another class called Dependency which does not have an interface or virtual methods. You need to mock it in order to test Production class.

Within production.h after all include statements inject following code

#if TESTENV
    #include "DependencyMock.h"
    #define Dependency DependencyMock
#endif

So if TESTENV is defined and active, you will include the mocked version of the class and replace all usages of Dependency class in a file with a DependencyMock class.

DependencyMock.h will probably look something like this:

#pragma once
#include "Dependency.h"

class DependencyMock
{
public:
    void nonVirtualMethodToMock() {...};
    int methodToWrap() { return dep_.methodToWrap(); }
private:
    Dependency dep_;
};

You can mock any and all methods, but it might be easier and better to just wrap what you can.

Also there is minimum intrusion into production code .h file, and we are not really changing production code, we are only changing it when it is being tested.

So in my view only downside is that for this to work you need to recompile classes that you want to test in order to run the tests.

So this is the CmakeLists.txt example:

add_executable(testProduction  
    testProduction.cpp
    Production.cpp
    DependencyMock.cpp

)
target_link_libraries(testProduction PRIVATE
    ${PRODUCTION_DEPEND_LIBS}
    gtest_main
)
target_compile_definitions(testPoduction PRIVATE -DTESTENV=ON)

And you are good to go.

I don't know how this scales because I did not write that many tests but for now it is sufficient for me and by far the easiest way of all I have seen so far (I did not use any platforms like Isolator or Injector). So hope this helps :)