问题
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.
回答1:
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());
}
}
回答2:
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)
来源:https://stackoverflow.com/questions/42505119/how-to-mock-methods-return-object-with-deleted-copy-ctor