Reputation: 714
I want to mock the following method Ctrl::Do(const Handler& handler)
to throw an exception.
Ctrl
stores a weak pointer to Handler
class Ctrl
{
std::weak_ptr<Handler> _handler;
// ...
};
And a reference of which gets passed to Ctrl::Do()
struct CtrlMock : public Ctrl
{
CtrlMock(std::weak_ptr<Handler> handler) : Ctrl(handler) {}
MOCK_METHOD(void, Do, (const Handler& handler), ());
// ...
void Handling()
{
if (std::shared_ptr<Handler> handlerSptr = _handler.lock())
{
try
{
Do(*handlerSptr); // mock this method to throw an exception
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
}
};
But I get the error indicating the call never happens due to function mismatch.
GMOCK WARNING:
Uninteresting mock function call - returning directly.
Function call: Action()
NOTE: You can safely ignore the above warning unless this call should not happen. Do not suppress it by blindly adding an EXPECT_CALL() if you don't mean to enforce the call. See https://github.com/google/googletest/blob/main/docs/gmock_cook_book.md#knowing-when-to-expect for details.
example.cpp:90: Failure
Actual function call count doesn't match EXPECT_CALL(ctrlMock, Do(HandlerMatcher(std::ref(*handlerMock))))...
Expected: to be called once
Actual: never called - unsatisfied and active
HandlerMock
is a Handler
, and _handler
does store a weak reference to HandlerMock
. Unless
there's object slicing under the hood happening causing a function
mismatch. Is there something I am missing here?Handler
doesn't get invoked.operator==
from Handler
, the MATCHER fails.
Any way I could only have it inside the HandlerMock
? I want to remove since it was added solely for the test purpose.Full code (sample)
// --------- Handler ------------
struct Handler
{
// Ideally wouldn't want to have an comparison operator within the
// main class (given it's solely for test purposes!), and rather in HandlerMock
bool operator==(const Handler& other) const
{
std::cout << "== operator called\n"; // doesn't get printed
return true;
}
virtual void Action() const = 0;
};
struct HandlerMock : public Handler
{
// bool operator==(const HandlerMock& other) const // this fails!
// {
// return true;
// }
MOCK_METHOD(void, Action, (), (const override));
};
// --------- Ctrl ------------
class Ctrl
{
std::weak_ptr<Handler> _handler;
public:
Ctrl(std::weak_ptr<Handler> handler) : _handler(handler) {}
void Handling()
{
if (std::shared_ptr<Handler> handlerSptr = _handler.lock())
{
try
{
Do(*handlerSptr); // mock this method to throw an exception
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
}
void Do(const Handler& handler) // mock this method to throw an exception
{
std::cout << ">>>> Handler.Action <<<<\n";
handler.Action(); // should not enter here since we mock'd Do() function
}
};
struct CtrlMock : public Ctrl
{
CtrlMock(std::weak_ptr<Handler> handler) : Ctrl(handler) {}
MOCK_METHOD(void, Do, (const Handler& handler), ());
};
// --------- TEST STUFF ------------
MATCHER_P(HandlerMatcher, handler, "")
{
return arg == handler;
}
ACTION(MyThrowException)
{
throw std::invalid_argument("Some exception thrown!");
}
TEST(UtClass, Test)
{
auto handlerMock = std::make_shared<HandlerMock>();
CtrlMock ctrlMock {handlerMock};
// mocking CtrlMock::Do() to throw an exception
// however the mock function call doesn't happen!
EXPECT_CALL(ctrlMock, Do(HandlerMatcher(std::ref(*handlerMock))))
.Times(1)
.WillRepeatedly(MyThrowException());
ctrlMock.Handling();
}
Upvotes: 1
Views: 652
Reputation: 6142
You need to mark Ctrl::Do()
as virtual
, so that when Ctrl::Handling()
is calling Ctrl::Do()
it actually ends up calling CtrlMock::Do()
. Also compare the documentation on how to mock methods.
class Ctrl
{
// ...
virtual void Do(const Handler& handler) // mock this method to throw an exception
{
std::cout << ">>>> Handler.Action <<<<\n";
handler.Action(); // should not enter here since we mock'd Do() function
}
};
Regarding the operator==
: It really depends on what you want to do. From the code I guess what you really want is to match the handlerMock
by its address. For this, you can simply use testing::Ref
:
EXPECT_CALL(ctrlMock, Do(testing::Ref(*handlerMock)))
.Times(1)
.WillRepeatedly(MyThrowException());
and remove the HandlerMatcher
completely. Full example on godbolt.
Otherwise, if you do not want to compare addresses but rather the objects' values, I think it would be weird that a Handler
cannot be compared but a HandlerMock
can; i.e. at first sight it does make sense to have operator==
coupled with Handler
. In any case, you can of course always define the comparison operator==
outside of Handler
in your test code.
Upvotes: 2