I have a class MyClass
which I want to mock in 2 parameterized tests where I have 2 operator *= methods: 1 for an MyClass
object and one for a double.
The class looks as follows:
Header:
class MyClass {
private:
int value;
public:
MyClass(int _value=0);
~MyClass();
int operator *=(const MyClass &other);
int operator *=(const double other);
Implementation:
MyClass::MyClass(int _value){
value = _value;
}
MyClass::~MyClass(){}
int MyClass::operator*=(const MyClass &other){
value *= other.value;
}
int MyClass::operator*=(const double other){
value *= double;
}
Now I want to mock this in 2 parameterized tests so I can give any input to the mock and check if the correct overloaded mock-method is called. But I don't care what the exact input values are for the method calls, only that the correct method is called.
So basically I want to combine the following EXPECT_CALLs since the first is ambiguous since there are 2 implementations:
EXPECT_CALL(mymock, multiplication_assignment_operator(_))
.Times(1)
.WillOnce(Return(30));
with:
// The ??? in the following line is the question I have.
EXPECT_CALL(mymock, multiplication_assignment_operator(Matcher<MyClass&>(???)))
.Times(1)
.WillOnce(Return(30));
// Note: For the double implementation this is Matcher<double>(???).
But I can't find a way to define a Matcher for a type where it only matches the type and skips the value like '_' does.
I already googled around but did not find a solution, hence my question here.
/EDIT/ Added minimal reproducible example as requested by 273K. Probably contains lots of details which I assumed were not directly needed for the question hence I did not listed these implementations before. It can be that I now copied / pasted / anonymized (I'm not allowed to show the actual code, so have to make it generic) too much ;-)
/EDIT 2/ We use gmock 1.10 (yes I know old, but that is the version the company I'm working for is using).
Mock for MyClass - Header:
#ifndef MOCK_MYCLASS_MOCK_CXX_HPP
#define MOCK_MYCLASS_MOCK_CXX_HPP
#include "gmock/gmock.h"
#include "MyClass.h"
namespace MyNameSpace
{
class MyClass_MockImplNotSetException : publ std::exception
{
public:
virtual const char* what() const throw();
};
class IMockMyClass
{
public:
virtual ~IMockMyClass();
static IMockMyClass* getTestDouble();
virtual int operator*=(const MyNamespace::MyClass & other) const = 0;
virtual int operator*=(const double other) = 0;
};
class InternalMockIMockMyClass : public IMockMyClass
{
protected:
InternalMockIMockMyClass();
public:
virtual ~InternalMockIMockMyClass();
static IMockMyClass* getTestDouble();
MOCK_METHOD(int, multiplication_assignment_operator, (const MyNameSpace::MyClass &));
MOCK_METHOD(int, multiplication_assignment_operator, (const double));
virtual int operator*=(const MyNameSpace::MyClass & other) { return multiplication_assignment_operator(other); }
virtual int operator*=(const double other) { return multiplication_assignment_operator(other); }
};
typedef ::testing::NiceMock<InternalMockIMockMyClass> MockMyClass;
typedef ::testing::StrictMock<InternalMockIMockMyClass> StrictMockMyClass;
#endif // MOCK_MYCLASS_MOCK_CXX_HPP
Mock for MyClass - CPP file:
#include "MyClass_mock.hpp"
#include <iostream>
namespace MyNameSpace
{
const char* MyClass_MockImplNotSetException::what() const throw()
{
return "No mock implementation is set to handle MyClass functions";
}
static InternalMockIMockMyClass *p_IMockMyClass = nullptr;
IMockMyClass::~IMockMyClass()
{
}
InternalMockIMockMyClass::InternalMockMyClass()
{
p_IMockMyClass = this;
}
InternalMockIMockMyClass::~InternalMockIMockMyClass()
{
p_IMockMyClass = nullptr;
}
IMockMyClass* InternalMockIMockMyClass::getTestDouble()
{
IMockMyClass* pSelected = p_IMockMyClass;
if (p_IMockMyClass == NULL)
{
std::cerr << "ERROR: No mock implementation is currently available to handle "
<< "calls to MyClass functions. Did you forget to construct "
<< "MockMyClass mock in your test?" << std::endl;
throw MyClass_MockImplNotSetException();
}
return pSelected;
}
MyClass::MyClass(int_value)
{
}
MyClass::~MyClass()
{
}
int MyClass::operator*=(const MyNameSpace::MyClass & other)
{
int operator_result = InternalMockIMockMyClass::getTestDouble()->operator*=(other);
return operator_result;
}
int MyClass::operator*=(const double other)
{
int operator_result = InternalMockIMockMyClass::getTestDouble()->operator*=(other);
return operator_result;
}
}
And a simplified test SUT (system under test):
Header:
#ifndef SUT_MY_CLASS_H
#define SUT_MY_CLASS_H
#include "MyClass.hpp"
class SUT_MyClass {
public:
SUT_MyClass(const MyNameSpace::MyClass &_val);
~SUT_MyClass();
int multiply_and_assignment_values(const SUT_MyClass &other);
int multiply_and_assignment_values_other_type(const double other);
private:
MyNameSpace::MyClass val;
};
#endif
Implementation:
#include "SUT_MyClass.hpp"
SUT_MyClass::SUT_MyClass(const MyNameSpace::MyClass &_val){
val = _val;
}
SUT_MyClass::~SUT_MyClass(){
}
int SUT_MyClass::multiply_and_assignment_values(const SUT_MyClass &other) {
return val *= other.val;
}
int SUT_MyClass::multiply_and_assignment_values_other_type(const double other) {
return val *= other;
}
And finally unparameterized tests , which I want to transform in parameterized tests (I did not strip the unneeded gmock using statements):
#include "gtest/gtest.h"
#include "gmock/gmock.h"
/* Mock includes */
#include "MyClass_mock.hpp"
/* SUT include */
#include "SUT_MyClass.hpp"
#include "iostream"
#include <sstream>
/* gtest/mock using statements. Refer to gtest/gmock documentation for more info */
using ::testing::Test;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Return;
using ::testing::SetArgPointee;
using ::testing::ReturnRef;
using ::testing::Matcher;
using ::testing::Ref;
class Test_SUT_MyClass : public ::testing::Test
{
protected:
MyNameSpace::MockMyClass mockMyClass;
virtual void SetUp()
{
}
virtual void TearDown()
{
}
};
TEST_F(Test_SUT_MyClass, operator_multiplication_assignment_mocked)
{
/* Arrange (pre-conditions and inputs */
SUT_MyClass v1(MyNameSpace::MyClass(10));
SUT_MyClass v2(MyNameSpace::MyClass(3));
MyNameSpace::MyClass expected(3); // Only needed for the unparameterized test
EXPECT_CALL(mockMyClass, Multiplication_assignment_operator(Matcher<const MyNameSpace::MyClass&>(Ref(expected))))
.Times(1)
.WillOnce(Return(29)); // 29 so we can check that the mock was used
/* Act (on the SUT) */
int return_value = v1.multiply_and_assignment_values(v2);
/* Assert (that the expected results have occurred) */
EXPECT_EQ(29, return_value);
}
TEST_F(Test_SUT_MyClass, operator_multiplication_assignment_other_type_mocked)
{
/* Arrange (pre-conditions and inputs */
SUT_MyClass v1(MyNameSpace::MyClass(10));
double v2=3.0;
double expected=3.0; // Only needed for the unparameterized test
EXPECT_CALL(mockMyClass, Multiplication_assignment_operator(expected))
.Times(1)
.WillOnce(Return(31)); // 31 so we can check that the mock was used
/* Act (on the SUT) */
int return_value = v1.multiply_and_assignment_values_other_type(v2);
/* Assert (that the expected results have occurred) */
EXPECT_EQ(31, return_value);
}
Found the solution: Instead of Matcher
I have to use A
. Thus:
EXPECT_CALL(mockMyClass, Multiplication_assignment_operator(A<const MyNameSpace::MyClass&>()))
.Times(1)
.WillOnce(Return(29));
Does it for the first test case and
EXPECT_CALL(mockMyClass, Multiplication_assignment_operator(A<double>()))
.Times(1)
.WillOnce(Return(31));
For the 2nd.