1

I have just started to use google mock for unit testing production code. The classes I want to mock have no virtual methods inside. From reading a little on google mock, is it not possible to mock a class like this? Bear in mind I don't want to make any changes to the source.

class Test
{
    Test(void);
    virtual ~Test() {}
    Add();
};

int Test::Add()
{
    return 1;
}

class MockTest : public Test
{
public:
    MOCK_METHOD0(Add,int(void));
};
tech 1990
  • 23
  • 7

1 Answers1

1

There may be a way, but it's not as nice as the simple way of overriding a virtual function.

First, if the function is not virtual and is inline, you're likely out of luck. When the compiler saw a call to obj.Add() or ptr->Add(), the fact the function is not virtual means it didn't need to worry about the possibility some function other than Test::Add() might need to be the one actually called. So it most likely either directly inlined the code from the definition of Add, in which case replacing it is near impossible, or it put a weakly-linked copy of the Test::Add() into the same object file as the function calling it. In that second case, you might be able to replace it using linker tricks, depending on the platform you're using - until later the compiler switches to deciding to inline it after all.

If it's just the class Test you don't want to modify, but you're okay with changing the code that uses Test as a dependency and will be tested by the unit test, you could do template dependency injection. But the question sounds like you probably don't want to modify that code either.

Now assuming the function is not inline, and is defined in some file "Test.cpp", and the class is polymorphic (which it is in the example because of the virtual destructor) you can replace all the definitions from that file, to make them act as though they were virtual even if they're not:

  1. Write the Google Mock class as usual, with the functions you want to be able to detect mocked.

    #include "Test.hpp"
    #include <gmock/gmock.h>
    
    class MockTest : public Test
    {
    public:
        MOCK_METHOD0(Add, int());
        MOCK_CONST_METHOD0(Print, void());
    };
    

(I've added a const method to the example, to show how to deal with them also.)

  1. In the same unit test code, write definitions for the mocked functions like this.

    int Test::Add()
    {
        if (auto* mock = dynamic_cast<MockTest*>(this))
            return mock->Add();
        // Next comes what to do if the code ever calls Add on
        // a Test which is not actually a MockTest. This could
        // be a stub implementation, an actual implementation, or
        // could intentionally terminate, throw, or note a gtest error.
        ADD_FAILURE() << "Test is not a MockTest";
        return 0;
    }
    
    void Test::Print() const
    {
        if (auto* mock = dynamic_cast<const MockTest*>(this)) {
            mock->Print();
            return;
        }
        ADD_FAILURE() << "Test is not a MockTest";
    }
    

You may also need to write at least stubs for other definitions in the Test.cpp file to make the linker happy. This doesn't necessarily mean they would actually get called or otherwise used.

  1. When linking the unit test, make sure the real Test.cpp file is NOT provided. If it's normally part of a library, you may need to list out the other files from that library on the command line. This might lead to dependency order issues and/or circular dependency issues. GNU's linker has "-Wl,--start-group ... -Wl,--end-group" to deal circular link issues by repeatedly trying some objects and/or libraries in a loop until as much as possible has been resolved; I'm not sure about other systems.
aschepler
  • 70,891
  • 9
  • 107
  • 161