Mock Non-Virtual Method C++ (Gmock)

Mock non-virtual method C++ (gmock)

It means you will have to templatize your production code. Using your example:

CSumWind class definition:

class CSumWnd : public CBaseWnd
{

private:
bool MethodA()
};

Mocked CSumWnd class definition:

class MockCSumWnd : public CBaseWnd
{

private:
MOCK_METHOD(MethodA, bool());
};

Production class which have to be tested with mocked class CSumWind. Now it becomes templated to provide using CSumWind class in production code and MockCSumWnd class in tests.

template <class CSumWndClass>
class TestedClass {
//...
void useSumWnd(const CSumWndClass &a);

private:
CSumWndClass sumWnd;
};

Instantiation of TestedClass in production:

TestedClass <CSumWnd> obj;

Instantiation of TestedClass object in test executable:

TestedClass <MockCSumWnd> testObj;

How to mock Non-virtual Methods in concrete classes using gmock?

Define dependencies(The random generator here) as local variables are not recommended, it's much harder to do dependencies injection(Or it won't be possible), so I change the functions Rng_t into template function and pass the Rng as a parameter.

In practice to construct a random generation may be heavy work, it needs to initialize its internal status, to construct it every time we call the function flipCoin is waste.

The non-virtual function can be mocked, one most commonly used strategy is to use the template, here we make the class CoinFlipper's member function as a template function, then we can test the dependency with our MockRng.

Be aware that for the template function, we need to define the member function in the header file.

coinflipper.h:

#pragma once
#include "rng.h"

class CoinFlipper {
public:
enum Result { HEADS = 0, TAILS = 1 };

template <typename Rng_t>
Result flipCoin(Rng_t& rng) {
const double val = rng.generate(0.0, 1.0);
return (val < 0.5) ? HEADS : TAILS;
}
};

The test file part, MockRng doesn't inherit anything now. And the test member function we use here has the type CoinFlipper::flipCoin<MockRng>. For production code: we use the type CoinFlipper::flipCoin<Rng>

//#include "mockrng.h"

#include "coinflipper.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

class MockRng {
public:
MOCK_METHOD2(generate, double(double, double));
};

TEST(CoinFlipper, ShouldReturnHeadsIfRandValueIsLessThanProbability) {
MockRng rng;
EXPECT_CALL(rng, generate(::testing::DoubleEq(0.0), ::testing::DoubleEq(1.0)))
.Times(::testing::Exactly(1))
.WillOnce(::testing::Return(0.25));

CoinFlipper coinFlipper;
auto result = coinFlipper.flipCoin<MockRng>(rng);
EXPECT_EQ(CoinFlipper::HEADS, result);
}

See related question here:

Mock non-virtual method C++ (gmock)

The official document:

https://chromium.googlesource.com/external/github.com/google/googletest/+/refs/tags/release-1.8.0/googlemock/docs/CookBook.md

Mocking a non-virtual function using Google Mock?

Possible way without virtual:

struct MySub
{
int sub(int c, int d) const { return c - d; }
};

template <typename Sub>
class baseclassT : public Sub
{
public:
int add(int a, int b) {
return (a + this->sub(a, b));
}
};

using baseclass = baseclassT<MySub>; // For prod

And then, for test:

class MockSub {
public:
MOCK_METHOD2(sub, int(int a, int b));
};

TEST(sample_test, testmain)
{
baseclassT<MockSub> mo;
int c = 12;
int d = 4;
EXPECT_CALL(mo, sub(c, d)).WillOnce(testing::Return(8));
EXPECT_EQ(mo.add(c, d), 20);
}

How to mock a class with both virtual and non-virtual methods using Google Mock?

(1) Is it possible to mock a class with mixed virtual/non-virtual types?

Yes, it is, but you have to take care. In the mocked class, override only virtual methods.

The mock should look like this :

struct Time_Device_Mock : public Time_Device_Interface
{
MOCK_CONST_METHOD1( set_time, bool(time_sample const &) );
MOCK_CONST_METHOD1( get_time, bool(time_sample *) );
MOCK_CONST_METHOD1( register_is_connected_notification, bool(irig_callback_t) );
};

(2) What method should be used (if question 1 is true) to mock this class, (If question 1 is false) what could be used instead?

This question is a bit weird. You said that non-virtual methods are private, therefore you can not access them. That leaves only option to use virtual methods.

That means, create an instance of the mocked class, and pass it to object which is supposed to use it. The method is called dependency injection, and there are several ways to inject dependency.

Mocking class with no virtual methods

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.


Related Topics



Leave a reply



Submit