This page shows how to mock virtual functions using BonoboMock.
Note: In optimized builds (e.g., CMake build types
RelWithDebInfoorRelease), the compiler may inline functions, preventing BonoboMock from intercepting calls. See Function inlining for this limitation and the available mitigations using the optimization macros and CMake helper.
Note: If your project uses C++03,
autois unavailable. Use explicitbsl::shared_ptr<GMock<...>>types instead. See Explicit Mock Object Types.
Note: On Itanium ABI compilers (GCC, Clang) with C++11 or later,
BONOBO_MOCKauto-detects virtual functions — you can useBONOBO_MOCKinstead ofBONOBO_MOCK_VIRTUALand it will resolve the function address correctly. The examples below useBONOBO_MOCK_VIRTUALbecause it works on all compilers, including SunPro and C++03.
Contents:
The examples in this section use BONOBO_MOCK_VIRTUAL to mock public virtual functions.
Note:
BONOBO_MOCK_VIRTUALrequires the class to have a default constructor (no arguments). For classes without a default constructor, useBONOBO_MOCK_VIRTUAL_ONinstead, which accepts an existing object instance to extract the virtual function address.
Let’s define a class BaseClass that has 2 pure virtual functions. Another class SampleClassVirtual, derives from BaseClass and implements the 2 virtual public member functions. virtual_function is a non-const function and const_virtual_function is const:
class BaseClass {
public:
virtual int virtual_function(int& out, int in) = 0;
virtual int const_virtual_function(bool) const = 0;
};
class SampleClassVirtual : public BaseClass {
public:
virtual int virtual_function(int& out, int in) {
out = in;
return 0;
}
virtual int const_virtual_function(bool in) const {
if (in) {
return 10;
}
return -10;
}
};
To demonstrate that BonoboMock can intercept virtual member function calls on objects the test does not control, we define two free functions that create their own instance of SampleClassVirtual and call the virtual member functions:
int virtual_member_wrapper(int in) {
int out = 0;
SampleClassVirtual obj;
BaseClass *base_ptr = &obj;
int rc = base_ptr->virtual_function(out, in);
if (rc) {
return -1;
}
if (out == 100) {
return 1;
}
return 0;
}
int const_virtual_member_wrapper() {
const SampleClassVirtual obj;
const BaseClass *base_ptr = &obj;
return base_ptr->const_virtual_function(false);
}
TEST(Virtual, Mock_virtual) {
#ifdef BSLS_COMPILERFEATURES_FULL_CPP11
auto mock = BONOBO_MOCK_VIRTUAL(&SampleClassVirtual::virtual_function);
#else
bsl::shared_ptr<GMock<int(void*, int&, int)> > mock =
BONOBO_MOCK_VIRTUAL(&SampleClassVirtual::virtual_function);
#endif
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(_, _, _))
.Times(1)
.WillOnce(Return(-1));
SampleClassVirtual obj;
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(&obj, _, _))
.Times(1)
.WillOnce(Return(-2));
int out = 0;
EXPECT_EQ(-2, obj.virtual_function(out, 1));
EXPECT_EQ(-1, virtual_member_wrapper(1));
mock->restore();
EXPECT_EQ(0, obj.virtual_function(out, 1));
EXPECT_EQ(0, virtual_member_wrapper(1));
}
For virtual_function, we pass its address to BONOBO_MOCK_VIRTUAL (a special macro for virtual functions), which returns a mock object that manages the mocking.
After creating the mock object, we define expected behavior using BONOBO_MOCK_FUNCTION. Because virtual_function takes 2 arguments, we can match the matcher parameter to specific arguments or match anything using _.
You may wonder why BONOBO_MOCK_FUNCTION takes 3 matcher parameters while virtual_function only expects two. This is because for class member function mocking, the first argument of BONOBO_MOCK_FUNCTION is always the pointer to the class object. You can pass a specific object’s pointer or _ to match any object.
In this example, the first EXPECT_CALL is telling BonoboMock to return -1 for any object of SampleClassVirtual with any arguments, except for the test cases defined in the second EXPECT_CALL, which return -2 when the specific object obj is called.
Because the first EXPECT_CALL uses _ as the first argument (the instance pointer), it matches calls on all instances — including the object created inside virtual_member_wrapper, which the test does not have direct access to. The second EXPECT_CALL uses &obj as the first argument, so it matches calls only on that specific instance.
If you need to stop mocking in the middle of the unit test, you can use mock->restore() to revert to the default behavior.
The mock object will automatically restore the mocking when it goes out of scope.
TEST(Virtual, Mock_virtual_const) {
#ifdef BSLS_COMPILERFEATURES_FULL_CPP11
auto mock = BONOBO_MOCK_VIRTUAL(&SampleClassVirtual::const_virtual_function);
#else
bsl::shared_ptr<GMock<int(const void*, bool)> > mock =
BONOBO_MOCK_VIRTUAL(&SampleClassVirtual::const_virtual_function);
#endif
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(_, _))
.Times(1)
.WillOnce(Return(100));
const SampleClassVirtual obj;
const BaseClass* ptr = &obj;
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(&obj, _))
.Times(1)
.WillOnce(Return(200));
EXPECT_EQ(200, ptr->const_virtual_function(true));
EXPECT_EQ(100, const_virtual_member_wrapper());
mock->restore();
EXPECT_EQ(10, ptr->const_virtual_function(true));
EXPECT_EQ(-10, const_virtual_member_wrapper());
}
For const_virtual_function, everything remains the same except the explicit type uses const void* instead of void* for the object pointer.
Because BonoboMock needs to fetch the address of a virtual function through a real object, BONOBO_MOCK_VIRTUAL requires the class to have a default constructor. For classes that don’t meet this requirement, we have a new macro BONOBO_MOCK_VIRTUAL_ON. The code below is almost the same as the example above; the only difference is BONOBO_MOCK_VIRTUAL_ON. BONOBO_MOCK_VIRTUAL_ON will use an object that you provide in your test to identify the location of the function. The object can be, but does not have to be, the same object as one in your actual test - it’s sufficient to create a dummy object for this purpose that’s otherwise unused.
// Abstract base class without default constructor
class BaseClass {
public:
BaseClass(int x) : m_x(x) {}
virtual int virtual_function(int& out, int in) = 0;
virtual int const_virtual_function(bool) const = 0;
protected:
int m_x;
};
// The SampleClassVirtual class contains virtual member functions for us to mock.
// Also no default constructor
class SampleClassVirtual : public BaseClass {
public:
SampleClassVirtual(int x) : BaseClass(x) {}
virtual int virtual_function(int& out, int in) {
out = in;
return m_x;
}
virtual int const_virtual_function(bool in) const {
if (in) {
return 10;
}
return -10;
}
}
// This function will be used to demonstrate that BonoboMock can intercept
// virtual member function calls on objects the test does not control.
int virtual_member_wrapper(int in) {
int out = 0;
SampleClassVirtual obj(0);
BaseClass *base_ptr = &obj;
int rc = base_ptr->virtual_function(out, in);
if (rc) {
return -1;
}
if (out == 100) {
return 1;
}
return 0;
}
TEST(VirtualOnInstance, Mock_virtual) {
// Mock the virtual function `virtual_function`.
// To correctly mock virtual function, we need to use the specific derived class here.
// this object is used to extract the address and is otherwise unused
SampleClassVirtual instance(0);
#ifdef BSLS_COMPILERFEATURES_FULL_CPP11
auto mock = BONOBO_MOCK_VIRTUAL_ON(instance, &SampleClassVirtual::virtual_function);
#else
bsl::shared_ptr<GMock<int(void*, int&, int)> > mock =
BONOBO_MOCK_VIRTUAL_ON(instance, &SampleClassVirtual::virtual_function);
#endif
// Defined the 2nd mocked function for `virtual_function`.
// BONOBO_MOCK_FUNCTION is taking any input and mocking any object.
// Return -1.
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(_, _, _))
.Times(1)
.WillOnce(Return(-1));
SampleClassVirtual obj(0);
// Defined the 1st mocked function for `member_function`.
// BONOBO_MOCK_FUNCTION is taking any input and the specific object `obj`.
// Return -2.
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(&obj, _, _))
.Times(1)
.WillOnce(Return(-2));
int out = 0;
EXPECT_EQ(-2, obj.virtual_function(out, 1));
EXPECT_EQ(-1, virtual_member_wrapper(1));
// Optionally tell BonoboMock to stop mocking, use the original sample_function.
// Otherwise when the mock goes out of scope the behavior will be automatically restored.
mock->restore();
EXPECT_EQ(0, obj.virtual_function(out, 1));
EXPECT_EQ(0, virtual_member_wrapper(1));
}
You cannot pass a protected member function pointer directly to BONOBO_MOCK_VIRTUAL because it is inaccessible from test code. The workaround is to create a derived helper class that exposes the pointer through a public static method.
Note:
BONOBO_MOCK_VIRTUALrequires the class to have a default constructor (no arguments). For classes without a default constructor, useBONOBO_MOCK_VIRTUAL_ONinstead, which accepts an existing object instance to extract the virtual function address.
class BaseClassProtected {
protected:
virtual bool protected_virtual_function(bool) = 0;
};
class SampleClassProtected : public BaseClassProtected {
public:
bool call_protected_virtual(bool in) {
return protected_virtual_function(in);
}
protected:
virtual bool protected_virtual_function(bool in) {
return !in;
}
};
// Derived helper that exposes the protected function pointer
class Helper : public SampleClassProtected {
public:
typedef bool(Helper::*func_type_virtual)(bool);
static func_type_virtual get_virtual_func() {
return &Helper::protected_virtual_function;
}
};
TEST(Protected, Mock_virtual_protected) {
#ifdef BSLS_COMPILERFEATURES_FULL_CPP11
auto mock = BONOBO_MOCK_VIRTUAL(Helper::get_virtual_func());
#else
bsl::shared_ptr<GMock<bool(void*, bool)> > mock =
BONOBO_MOCK_VIRTUAL(Helper::get_virtual_func());
#endif
SampleClassProtected obj;
EXPECT_CALL(*mock, BONOBO_MOCK_FUNCTION(_, _))
.Times(1)
.WillOnce(Return(true));
EXPECT_TRUE(obj.call_protected_virtual(true));
mock->restore();
EXPECT_FALSE(obj.call_protected_virtual(true));
}
For non-virtual protected function mocking details, see Mock Protected Functions.
Private virtual functions are mocked using the same BONOBO_MOCK_PRIVATE_* macros as non-virtual private functions. See Mock Private Functions for the full recipe.
You can find additional examples among the unit test files for the library under tests/unit/.