zoukankan      html  css  js  c++  java
  • 白盒测试之gmock入门篇

    一、gmock是什么

    gmock是google公司推出的一款开源的白盒测试工具。gmock是个很强大的东西,测试一个模块的时候,可能涉及到和其他模块交互,可以将模块之间的接口mock起来,模拟交互过程。其作用就类似白盒测试中的打桩的概念。

    下面简单的说说打桩在白盒测试中的重要性:

    1、比如银行业务,需要测试业务模块。此时,不可能去操作真实的数据库,并且搭建新的数据库可能比较复杂或者耗时。那么就可以用gmock将数据库接口地方打桩,来模拟数据库操作。

    2、比如要测试A模块,必过A模块需要调用B模块的函数。如果B模块还没有实现,此时,就可以用gmock将B模块的某些接口打桩。这样就可以让A模块的测试继续进行下去。

    3、比如网关设备,在用gtest测试device模块的时候,必须有真实的设备才能让测试进行下去。如果用gmock模拟一套sdk接口,那么无需真实的设备也能让测试进行下去。(本条仅限公司内部阅读)

    二、gmock如何获取

    gmock是google的开源工具,google的官网上是可以下载源码的。不过公司内部员工可以去0.2上去取,在“研发质量部”的文件夹下。gmock的最新版本是1.7.0。下载下来的压缩包名称为“gmock-1.7.0.zip”。解压后,如下:

    仔细观察发现,压缩包里面有gtest的文件夹,该文件夹里面就是gtest的源码。因为大部分情况下,gmock是配合gtest来做白盒测试的。关于gtest的工程相关介绍请查看本博客其他文章。

    本文暂时讨论windows下的gmock编译,工程相关的文件在msvc的文件夹中。msvc文件夹下又分为2005和2010文件夹,分别是用VS2005和VS2010建立的工程。

    用VS2010打开工程,然后直接编译。编译通过后,会得到gmock.lib,gmock_maim.lib,gmock_test.ext三个文件。其中gmock.lib就是我们所需要的库文件,其他两个工程本文暂不做阐述。

    三、gmock的第一个demo

    我们暂且模拟银行转账系统。银行转账系统涉及到数据库两个操作,首先要通过银行卡ID找到账户信息(包括账户余额等),然后在通过计算,将转账后的金额写入到转账双方。这样就完成了简单的银行转账业务。

    下面我们来mock(模拟)数据库的查询账户和写入金额的两个方法,定义一个头文件AccountManager.h :

    // AccountManager.h 
     // the interface of external services which should be mocked 
     // 需要被mock的服务接口
     #pragma once 
    
     #include <string> 
    
     #include "Account.h" 
    
     class AccountManager 
     { 
     public: 
         //通过账户号,找到对应的用户
        virtual Account findAccountForUser(const std::string& userId) = 0; 
        //更新用户的信息这里
        virtual void updateAccount(const Account& account) = 0; 
     }; 

    AccountManager是需要被mock(模拟)的类。其中findAccountForUser(找到对应用户)和updateAccount(更新账户信息)是本次转账要mock的两个方法。注意,此处的两个方法用的是纯虚函数。因为这两个方法无需实现,测试的时候程序会走到mock出来的函数中,即使实现, 也不会被调用到。

    下面通过gmock来mock(模拟)AccountManager的两个方法:

     // MockAccountManager, mock AccountManager with googlemock 
     class MockAccountManager : public AccountManager 
     { 
     public: 
        MOCK_METHOD1(findAccountForUser, Account(const std::string&)); 
    
        MOCK_METHOD1(updateAccount, void(const Account&)); 
     }; 

    类MockAccountManager是继承数据库DB方法类AccountManager的。其中MOCK_METHOD1为gmock的宏定义。头文件中还有其他类似宏定义,如MOCK_METHOD0,MOCK_METHOD2...

    MOCK_METHOD#1(#2, #3(#4) )

    #2是你要mock的方法名称!#1表示你要mock的方法共有几个参数,#4是这个方法具体的参数,#3表示这个方法的返回值类型。很简单不是?!

    // Account.h 
     // basic application data class 
     #pragma once 
    
     #include <string> 
    
     class Account 
     { 
     private: 
        std::string accountId;  //账号
         
        long balance;           //存款 呃 还是叫余额吧
    
     public: 
        Account(); 
    
        Account(const std::string& accountId, long initialBalance); 
    
        //消费
        void debit(long amount); 
    
        //收入
        void credit(long amount); 
    
        //获取存款
        long getBalance() const; 
    
        //获取账号
        std::string getAccountId() const; 
     }; 

    上面这个类是为了方便模拟转账业务构造的一个账户类。类Account有debit(消费)、credit(收入)、getBalance(获取存款)和getAccountId(获取账号)四个方法。

    // A facility class acts as an external DB 
     class AccountHelper 
     { 
     private: 
        std::map<std::string, Account> mAccount; 
        // an internal map to store all Accounts for test 
    
     public: 
        AccountHelper(std::map<std::string, Account>& mAccount); 
    
        void updateAccount(const Account& account); 
    
        Account findAccountForUser(const std::string& userId); 
     }; 
    
     AccountHelper::AccountHelper(std::map<std::string, Account>& mAccount) 
     { 
        this->mAccount = mAccount; 
     } 
    
     void AccountHelper::updateAccount(const Account& account) 
     { 
        this->mAccount[account.getAccountId()] = account; 
     } 
    
     Account AccountHelper::findAccountForUser(const std::string& userId) 
     { 
        if (this->mAccount.find(userId) != this->mAccount.end()) 
            return this->mAccount[userId]; 
        else 
            return Account(); 
     } 

    上面这个类,扮演着数据库的就角色。mock(模拟)出来的方法,都将用该类的函数替代实现。

    下面,我们来写一个测试用例来看看gmock的神奇作用。

    // Test case to test AccountService 
     TEST(AccountServiceTest, transferTest) 
     { 
        std::map<std::string, Account> mAccount; 
        mAccount["A"] = Account("A", 3000); 
        mAccount["B"] = Account("B", 2000); 
        AccountHelper helper(mAccount); 
    
        MockAccountManager* pManager = new MockAccountManager(); 
    
        // specify the behavior of MockAccountManager 
        // always invoke AccountHelper::findAccountForUser 
         // when AccountManager::findAccountForUser is invoked 
        EXPECT_CALL(*pManager, findAccountForUser(testing::_)).WillRepeatedly( 
            testing::Invoke(&helper, &AccountHelper::findAccountForUser)); 
    
        // always invoke AccountHelper::updateAccount 
        //when AccountManager::updateAccount is invoked 
        EXPECT_CALL(*pManager, updateAccount(testing::_)).WillRepeatedly( 
            testing::Invoke(&helper, &AccountHelper::updateAccount)); 
    
        AccountService as; 
        // inject the MockAccountManager object into AccountService 
        as.setAccountManager(pManager); 
    
        // operate AccountService 
        as.transfer("A", "B", 1005); 
    
        // check the balance of Account("A") and Account("B") to 
        //verify that AccountService has done the right job 
        EXPECT_EQ(1995, helper.findAccountForUser("A").getBalance()); 
        EXPECT_EQ(3005, helper.findAccountForUser("B").getBalance()); 
    
        delete pManager; 
     } 

    首先,声明一个类MockAccountManager的实例pManager,在声明一个实现类AccountHelper实例helper。EXPECT_CALL的作用是将调用pManager方法替换成实现类helper的对应方法。此处,将pManager的findAccountForUser方法替换成helper的findAccount方法,将pManager的updateAccount方法替换成helper的updateAccount方法。

    最后,再用gtest的断言机制EXPECT_EQ来判断结果。

  • 相关阅读:
    HDU 5273 Dylans loves sequence 暴力递推
    HDU 5285 wyh2000 and pupil 判二分图+贪心
    HDU 5281 Senior's Gun 贪心
    HDU 5651 xiaoxin juju needs help 逆元
    HDU 5646 DZY Loves Partition
    HDU 5366 The mook jong
    HDU 5391Z ball in Tina Town 数论
    HDU 5418 Victor and World 允许多次经过的TSP
    HDU 5642 King's Order dp
    抽屉原理
  • 原文地址:https://www.cnblogs.com/peisy/p/4462506.html
Copyright © 2011-2022 走看看