概述
Mock的定义:
在单元测试、模块的接口测试时,当一个模块需要依赖另外一个或几个类,而这时所依赖的类还没有开发好,这时就可以定义Mock对象来模拟那些类的行为。也就是自己实现一个假的依赖类,对这个类的方法想要什么行为就可以有什么行为,想让这个方法返回什么结果就可以返回什么样的结果。(便捷的模拟对象的方法。)
gmock 依赖C++多态机制进行工作,只有虚函数才能被mock, 非虚函数不能被mock, 这一点告诉我们,如果想要在代码中使用gmock类的设计中,最好采用接口隔离,对于c++来说也就是采用纯虚类型,因为c++本身没有接口类型。
当一个文件中多个方法需要调用一个未完成或者做单元测试时,就需要将这个未完成或者使用比较麻烦的虚方法Mock,因为不希望为了执行单元测试,专门搭建一个服务器与XXXClient交互,成本太高。注意:只需要Mock这个被调用的虚方法,调用方法不需要Mock,如果没有返回值可以使用SetArgReferee<0>(),参数从0开始。
For example:
MOCK_METHOD5(Send, void(const String&,const string&,std::vector<string>&,ncOSSResponse&,int));
std::vector<ncFileVersionInfo> versions;
ncFileVersionInfo info1;
info1.versionId = _T("1");
info1.fileName = _T("zgh.txt");
info1.editorName = _T("zgh");
ncFileVersionInfo info2 = info1;
versions.push_back (info1);
versions.push_back (info2);
// 构造http内容
JSON::Array jArray;
for (size_t i = 0; i < versions.size (); ++i) {
JSON::Object jsonO;
jsonO.insert (make_pair (JSON_MOVE (string ("rev")), JSON_MOVE (JSON::Value (toSTLString (versions[i].versionId)))));
jsonO.insert (make_pair (JSON_MOVE (string ("name")), JSON_MOVE (JSON::Value (toSTLString (versions[i].fileName)))));
jsonO.insert (make_pair (JSON_MOVE (string ("editor")), JSON_MOVE (JSON::Value (toSTLString (versions[i].editorName)))));
jArray.push_back (jsonO);
}
JSON::Object json;
json.insert (make_pair (JSON_MOVE (string ("versions")), JSON_MOVE (jArray)));
string content;
content.reserve (64);
JSON::Writer::write (json, content);
ncOSSResponse test;
test.body = content;
EXPECT_CALL(*_ClientMock, Send(_, _, _, _, _))
.WillOnce(SetArgReferee<3>(test));
GMock的特性:
google mock是用来配合google test对C++项目做单元测试的。它依赖于googletest
轻松创建mock类,支持丰富的匹配器和行为,支持有序、无序、部分有序的期望行为的定义,多平台的支持
使用流程:
引入你要用到的GMock名称。除宏或其他特别提到的之外所有GMock名称都位于testing命名空间之下,建立模拟对象(mock_object)
EXPECT_CALL(mock_object,method(matcher1,matcher2,...))
.With(multi_argument_matcher)
.Times(cardinality)
.InSequence(sequences)
.After(expectations)
.WillRepeatedly(action)
.RetiresOnSaturation();
EXPECT_CALL 声明一个调用期待,就是我们期待这个对象的这个方法按照什么样的逻辑去运行。
mock_object mock对象
Method mock对象中的mock方法,他的参数可以通过matchers规则去匹配
With 多个参数的匹配方式指定
Times 表示这个方法可以被多次调用
InSequence 指定函数执行的顺序,他是通过同一序列中声明期待的顺序确定的
After 指定某个方法只能在另一个方法之后执行
WillOnce 表示执行一次方法时,将执行其参数action的方法,一般用Return方法,用于指定一次调用的输出
WillRepeatedly 表示一直调用一个方法时,将执行其参数action方法,需要注意他和WillOnce的区别,WillOnce时一次,WillRepeatedly时一直。
RetiresOnSaturation 用于保证期待调用不会被相同的函数的期待所覆盖
EXPECT_CALL(mock_object,method(_,_)) 表示有两个参数
下划线(_),它是通配符,就是对任何输入参数都按之后要求执行
Google Mock的使用(例子):
class User
{
public:
virtual User() {}
virtual ~User() { }
public:
virtual bool Login(const std::string& username,const std::string& password) = 0; //登录
virtual bool Pay(int money) = 0; //支付
virtual bool Online() = 0; //是否登录
};
注意:析构函数必须虚函数,方法也的定义为纯虚函数
业务模块:用户登录,并且发起支付行为
class Biz
{
public:
void SetUser(User *user)
{
_user = user;
}
std::string Pay(const std::string& username,const std::string& password,int money)
{
std::string ret;
if(!_user)
{
ret = "pointer is null.";
return ret;
}
if(!_user->Online())
{
ret = "logout status.";
//尚未登录,要求登录
if(!_user->Login(username,password))
{
//登录失败
ret += "login error";
return ret;
}
else
{
//登录成功
ret += "login success.";
}
}
else
{
//已登录
ret += "login status.";
}
if(!_user->Pay(money))
{
ret += "Pay error.";
}
else
{
ret += "Pay success.";
}
return ret;
}
private:
User* _user;
};
这段逻辑的口语描述就是:我们先看看用户登录了没,如果没有登录则要求用户登录。如果登录失败,则直接返回;如果登录成功,则执行支付行为。最后将流程的状态输出。
class TestUser :public User
{
punlic:
MOCK_METHOD2(Login,bool(const std::string&,const std::string&));
MOCK_METHOD1(Pay,bool(int));
MOCK_METHOD0(Online,bool());
};
MOCK_METHOD #1(#2,#3(#4))
#1是要Mock的方法有几个参数
#2是要Mock的方法名称
#3是要Mock的方法的返回值
#4是要Mock的方法的具体参数
TEST(TestUser , User)
{
TestUser test_user;
EXPECT_CALL(test_user, Online()).WillRepeatedly(Return(false));
EXPECT_CALL(test_user, Login(StrNe("admin"), _)).WillRepeatedly(Return(true));
EXPECT_CALL(test_user,Pay(_)).Times(5).WillOnce(Return(true)).WillOnce(Return(true)).WillRepeatedly(Return(false));
Biz biz;
biz.SetUser(&test_user);
string user_ret = biz.pay("user", "", 1);
cout << "test ret value: " << user_ret << endl;
user_ret = biz.pay("user", "", 1);
cout << "test ret value: " << user_ret << endl;
user_ret = biz.pay("user", "", 1);
cout << "test ret value: " << user_ret << endl;
}
第6行我们使用Times函数,它的参数5表示该函数期待被调用5次,从第6次的调用开始,返回默认值。Times函数后面跟着两个WillOnce,其行为都是返回true。这个可以解读为第一次和第二次调用Pay方法时,返回成功。最后的WillRepeatedly表示之后的对Pay的调用都返回false。
再来一个gmock的简单实例:
#include <gtet/gtest.h>
#include <gmock.gmock.h>
using namespace testing;
class A
{
public:
int set(int num)
{
value = num;
return num;
}
int get()
{
return value;
}
int value;
};
class MockA : public A
{
public:
MOCK_METHOD1(set,int(int num));
MOCK_METHOD0(get,int());
};
TEST(Atest,getnum)
{
MockA m_A;
int a = 10;
EXPECT_CALL(m_A,set(_))
.WillRepeatedly(Return(a));
int k = m.A.set(200));
EXPECT_EQ(10,K);
}
int main(int argc,char *argv[])
{
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}
最后
以上就是敏感书本为你收集整理的理解使用GMock的全部内容,希望文章能够帮你解决理解使用GMock所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复