If an interface has a function to create an object with deleted copy-ctor, how to mock this function? Gmock seems to use the object's copy constructor internally.
E.g.
// The object with deleted copy-ctor and copy-assignment
class TTest
{
public:
TTest() = delete;
TTest(const TTest&) = delete;
TTest& operator=(const TTest&) = delete;
TTest(TTest&&) = default;
TTest& operator=(TTest&&) = default;
explicit TTest(int) {
}
};
// My interface to mock
class MyInterface
{
public:
virtual ~MyInterface() {}
virtual TTest GetUniqueTest() = 0;
};
// The mock
class MockMyInterface: public MyInterface{
public:
MOCK_METHOD0(GetUniqueTest, TTest());
}
The compile error says:
gmock/gmock-spec-builders.h:1330:20: error: use of deleted function 'TTest::TTest(const TTest&)'
T retval(value_);
...
gmock/gmock-actions.h:190:52: error: use of deleted function 'TTest::TTest(const TTest&)'
internal::BuiltInDefaultValue<T>::Get() : *value_;
...
gmock/internal/gmock-internal-utils.h:371:71: error: use of deleted function 'TTest::TTest(const TTest&)'
*static_cast<volatile typename remove_reference<T>::type*>(NULL));
If the method returns std::unique_ptr<T>
, the error is the same since std::unique_ptr<T>
has deleted copy-ctor as well.
So my question is: how to mock such methods that return objects with deleted copy-ctors?
I'm using googletest v1.7, GCC 5.3.0, and Ubuntu 14.04.1.
Answer my own question here just to provide updated information.
With googletest release 1.8.0 or above, it introduces ByMove(...)
and supports return move-only types natively.
So the code compiles OK:
class MockMyInterface: public MyInterface{
public:
MOCK_METHOD0(GetUniqueTest, TTest());
}
But in run time it throws exception because gmock does not know how to return default TTest
:
C++ exception with description "Uninteresting mock function call - returning default value.
Function call: GetUniqueTest()
The mock function has no default action set, and its return type has no default value set." thrown in the test body.
This can be easily workaround by setting a default action in the mock class:
ON_CALL(*this, GetUniqueTest()).WillByDefault(Return(ByMove(TTest(0))));
Note: For std::unique_ptr<T>
it's OK because it has default constructor, a nullptr
unique_ptr
is returned by default.
So putting all together, if using googletest 1.8.0 or above, we can do:
// My interface to mock
class MyInterface
{
public:
virtual ~MyInterface() {}
virtual TTest GetUniqueTest() = 0;
virtual std::unique_ptr<int> GetUniqueInt() = 0;
};
// The mock
class MockMyInterface: public MyInterface{
public:
MOCK_METHOD0(GetUniqueTest, TTest());
MOCK_METHOD0(GetUniqueInt, std::unique_ptr<int>());
MockMyInterface() {
ON_CALL(*this, GetUniqueTest())
.WillByDefault(Return(ByMove(TTest(0))));
}
};
Reference: [Mocking Methods That Use Move-Only Types] (https://github.com/google/googletest/blob/master/googlemock/docs/cook_book.md#mocking-methods-that-use-move-only-types)
As mentioned in the comments by Mine, Google Test 1.8 seems to support mocking such functions (documentation).
As for 1.7 I've found a solution here.
First, create an utility class to wrap non-copyable objects:
template <typename T>
class Mover
{
public:
Mover(T&& object)
: object(std::move(object)),
valid(true)
{
}
Mover(const Mover<T>& other)
: object(const_cast<T&&>(other.object)),
valid(true)
{
assert(other.valid);
other.valid = false;
}
Mover& operator=(const Mover& other)
{
assert(other.valid);
object = const_cast<T&&>(other.object);
other.valid = false;
valid = true;
}
T& get()
{
assert(valid);
return object;
}
const T& get() const
{
assert(valid);
return *object;
}
private:
T object;
mutable bool valid;
};
template <typename T>
inline Mover<T> Movable(T&& object)
{
return Mover<T>(std::move(object));
}
and then create a proxy-mock:
class MockMyInterface : public MyInterface
{
public:
MOCK_METHOD0(GetUniqueTest_, Mover<TTest>());
TTest GetUniqueTest()
{
return std::move(GetUniqueTest_().get());
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With