Min*_*ine 9 c++ unit-testing googletest gmock
如果一个接口有一个函数来创建一个删除了copy-ctor的对象,那么如何模拟这个函数呢?Gmock似乎在内部使用了对象的复制构造函数.
例如
// 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());
}
Run Code Online (Sandbox Code Playgroud)
编译错误说:
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));
Run Code Online (Sandbox Code Playgroud)
如果方法返回std::unique_ptr<T>,则错误也是相同的,因为std::unique_ptr<T>删除了copy-ctor.
所以我的问题是:如何模拟返回带有已删除副本的对象的方法?
我使用googletest V1.7,GCC 5.3.0,和Ubuntu 14.04.1.
在这里回答我自己的问题只是为了提供最新信息.
使用googletest 1.8.0或更高版本,它本身引入ByMove(...)并支持仅返回移动类型.
所以代码编译好了:
class MockMyInterface: public MyInterface{
public:
MOCK_METHOD0(GetUniqueTest, TTest());
}
Run Code Online (Sandbox Code Playgroud)
但是在运行时它抛出异常,因为gmock不知道如何返回默认值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.
Run Code Online (Sandbox Code Playgroud)
通过在mock类中设置默认操作,可以轻松解决此问题:
ON_CALL(*this, GetUniqueTest()).WillByDefault(Return(ByMove(TTest(0))));
Run Code Online (Sandbox Code Playgroud)
注意:std::unique_ptr<T>因为它没有,因为它有默认构造函数,nullptr unique_ptr默认返回a .
总而言之,如果使用googletest 1.8.0或更高版本,我们可以:
// 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))));
}
};
Run Code Online (Sandbox Code Playgroud)
参考:使用仅移动类型的模拟方法
如Mine的评论中所述,Google Test 1.8似乎支持模拟此类功能(文档)。
至于1.7我在这里找到了解决方案。
首先,创建一个实用程序类来包装不可复制的对象:
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));
}
Run Code Online (Sandbox Code Playgroud)
然后创建一个代理模拟:
class MockMyInterface : public MyInterface
{
public:
MOCK_METHOD0(GetUniqueTest_, Mover<TTest>());
TTest GetUniqueTest()
{
return std::move(GetUniqueTest_().get());
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3670 次 |
| 最近记录: |