I am writing some test units using googletest and googlemock and I am stuck in a problem related to C++11 smart pointers and polymorphism.
Suppose you have those classes:
class A {
public:
virtual void doThings() {...};
};
class B {
private:
B(std::unique_ptr<A> a): a_(std::move(a)) {}
std::unique_ptr<A> a_;
};
I want to test class B
and so I create a mock for A
and pass it in constructor:
class MockA: public A {
public:
virtual ~MockA() {}
MOCK_METHOD0(doThings, void());
};
TEST(...) {
auto ma = std::make_unique<MockA>();
B b(std::move(ma));
// Set expectation on mock
// call B method
}
The problem is this:
- the mock in moved inside
B
instance and so expectation verification throws exception becausema
is null.
My first attempt to solve it has been to change B
as follows:
class B {
private:
B(std::unique_ptr<A>& a): a_(a) {}
std::unique_ptr<A>& a_;
};
Now B
handles unique pointer references and does not use std::move
. The test also changed (no more use of std::move
):
TEST(...) {
auto ma = std::make_unique<MockA>();
B b(ma);
// Set expectation on mock
// call B method
}
Now the code does not compile because (if I understand correctly the error) references are not polymorphic (the unique pointer of MockA
cannot be casted to unique pointer of A
).
Am I missing any basics about smart pointers? Or is this the expected behaviour with unique pointers and so I have to rethink my classes (maybe using shared pointers)?
B
. If it is destroyed, any pointer or reference in the test code will be dangling, and interacting with it is UB. Passing byunique_ptr
is a transfer of ownership,B
gets to decide how long theA
lives.A
, but rather a reference of typestd::unique_ptr<A>
. A type ofstd::unique_ptr<MockA>
can't be passed by reference to astd::unique_ptr<A>
, because onestd::unique_ptr
is not a derivative of the other. (they're distinct types) The reason it "works" in your original code is because a brand newstd::unique_ptr<A>
got created from the temp that you passed into the constructor - andstd::unique_ptr
is designed to do that.