理解使用GMock

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();
}

 

 

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
gmock-1.7.0是Google Mock的一个版本。Google Mock是Google针对C++语言开发的一个mocking框架,用于帮助开发人员编写单元测试。该框架可以生成用于测试C++类的mock对象,使开发人员能够模拟对象的行为,以便更轻松地进行单元测试。 gmock-1.7.0包含了Google Mock的全部功能和特性。它提供了丰富的语法和工具,以便开发人员可以方便地创建和管理mock对象。通过使用gmock-1.7.0,开发人员可以模拟类的方法和行为,使测试更具可读性和易于理解gmock-1.7.0还提供了丰富的断言和验证功能,用于验证mock对象在测试期间的调用和行为。它可以捕获和比较方法的参数和返回值,以及记录方法的调用次数和顺序。这些功能使得开发人员能够更精确地验证代码的行为,从而更好地理解和解决潜在的问题。 除了基本的mocking功能外,gmock-1.7.0还提供了Mocking Cookbook,其中包含了一些常见的测试场景和解决方案。这些场景包括模拟私有方法、模拟全局函数、在测试中使用多个实例和对虚函数进行模拟等。通过参考Mocking Cookbook,开发人员可以更快地了解如何使用gmock-1.7.0来解决各种测试问题。 总而言之,gmock-1.7.0是Google Mock的一个重要版本,它提供了强大的mocking功能和详细的测试验证工具。通过使用gmock-1.7.0,开发人员可以更轻松地编写高质量的C++单元测试,从而提高软件质量和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值