Gtest/Gmock探究(一)-- 经典示例代码

来源:互联网 发布:易语言整人源码大全 编辑:程序博客网 时间:2024/06/05 20:40

接下来几篇文档记录,打算探究一下Google C++的单元测试框架Gtest/Gmock.
    · 先给出经典初识Gtest框架的代码(AccountMangerTest)
    · 紧接着探究TEST宏原理
    · 随着是Gmock的MOCK_METHODX系列宏的探究
代码结构:
    这里写图片描述
    首先,准备gmock的源代码(我这里是gmock-1.7.0),并且按照官方文档编译通过。

补充gmock的编译:
    cd gmock-1.7.0
    ./configure && make

    其次,将我们的代码文件夹命名为AccountManagerTest,与gmock-1.7.0在同一级目录(代码目录结构如上图所示)。下面列出我们的测试代码文件内容,以及编译和运行方法:

// Account.h#pragma once#include <string>using namespace std;class Account {private:    string m_strAccountId;    long m_nBalance;public:    Account() : m_strAccountId(""), m_nBalance(0) {;}    Account(const string &initAccountId, long initialBalance) : m_strAccountId(initAccountId), m_nBalance(initialBalance) {;}    bool isNil() {        return m_strAccountId == "";    }    void debit(long amount) {        m_nBalance -= amount;    }    void credit(long amount) {        m_nBalance += amount;    }    long getBalance() const {        return m_nBalance;    }    string getAccountId() const {        return m_strAccountId;    }    void SetId(const string &id) {        m_strAccountId = id;    }}; 
// AccountManager.h#pragma once#include "Account.h"class AccountManager {public:    virtual Account findAccountForUser(const string &userId) = 0;    virtual void updateAccount(const Account &account) = 0;}; 
// AccountService.h#pragma once#include <string> using namespace std;#include "Account.h" #include "AccountManager.h" class AccountService { private:    AccountManager* pAccountManager; public:    AccountService();    void setAccountManager(AccountManager* pManager);     bool withdraw(const string &id, long amount);     void topup(const string &id, long amount);    void transfer(const string& senderId, const string& beneficiaryId, long amount); };
// AccountService.cpp#include "AccountService.h"AccountService::AccountService() {    pAccountManager = NULL;}void AccountService::setAccountManager(AccountManager *pManager) {    pAccountManager = pManager;}void AccountService::transfer(const string &senderId, const string &beneficiaryId, long amount) {    Account sender = pAccountManager->findAccountForUser(senderId);    Account beneficiary = pAccountManager->findAccountForUser(beneficiaryId);    sender.debit(amount);    beneficiary.credit(amount);    pAccountManager->updateAccount(sender);    pAccountManager->updateAccount(beneficiary);}bool AccountService::withdraw(const string &id, long amount) {    Account owner = pAccountManager->findAccountForUser(id);    if (owner.isNil()) {        return false;    }    owner.debit(amount);     pAccountManager->updateAccount(owner);    return true;}void AccountService::topup(const string &id, long amount) {    Account owner = pAccountManager->findAccountForUser(id);    if (owner.isNil()) {        owner.SetId(id);    }    owner.credit(amount);     pAccountManager->updateAccount(owner);}
// AccountHelper.h#include "Account.h"#include <map>using namespace std;class AccountHelper {private:    map<string, Account> m_mapAccounts;    // an internal map to store all Accounts for testpublic:    AccountHelper(map<std::string, Account> &mAccount);    AccountHelper() {;}    void updateAccount(const Account &account);    Account findAccountForUser(const std::string &userId);}; 
// AccountHelper.cpp#include "AccountHelper.h"AccountHelper::AccountHelper(std::map<std::string, Account> &mAccount) {    m_mapAccounts = mAccount;}void AccountHelper::updateAccount(const Account &account) {    m_mapAccounts[account.getAccountId()] = account;}Account AccountHelper::findAccountForUser(const std::string &userId) {    if (m_mapAccounts.find(userId) != this->m_mapAccounts.end())         return this->m_mapAccounts[userId];    return Account();} 
// MockAccountManager.h#include "AccountManager.h"#include "gtest/gtest.h"#include "gmock/gmock.h"class MockAccountManager : public AccountManager {public:    MOCK_METHOD1(findAccountForUser, Account(const string&));    MOCK_METHOD1(updateAccount, void(const Account&));}; 
// main.cpp#include "AccountHelper.h"#include "MockAccountManager.h"#include "AccountService.h"TEST(AccountServiceTest, transferTest) {    map<std::string, Account> mapAccounts;    mapAccounts["A"] = Account("A", 3000);    mapAccounts["B"] = Account("B", 2000);    AccountHelper helper(mapAccounts);    MockAccountManager *pManager = new MockAccountManager();    EXPECT_CALL(*pManager, findAccountForUser(testing::_))        .Times(2)        .WillRepeatedly(testing::Invoke(&helper, &AccountHelper::findAccountForUser));    EXPECT_CALL(*pManager, updateAccount(testing::_)).WillRepeatedly(        testing::Invoke(&helper, &AccountHelper::updateAccount));    AccountService as;    as.setAccountManager(pManager);    as.transfer("A", "B", 1005);    EXPECT_EQ(1995, helper.findAccountForUser("A").getBalance());    EXPECT_EQ(3005, helper.findAccountForUser("B").getBalance());    delete pManager;}TEST(AccountServiceTest, topupTest) {    AccountHelper helper;    MockAccountManager *pManager = new MockAccountManager();    EXPECT_CALL(*pManager, findAccountForUser(testing::_))        .WillRepeatedly(testing::Invoke(&helper, &AccountHelper::findAccountForUser));     EXPECT_CALL(*pManager, findAccountForUser("B"))        .WillRepeatedly(testing::Invoke(&helper, &AccountHelper::findAccountForUser));    EXPECT_CALL(*pManager, findAccountForUser("A"))        .WillRepeatedly(testing::Return(Account("A", 5)));     EXPECT_CALL(*pManager, updateAccount(testing::_)).WillRepeatedly(        testing::Invoke(&helper, &AccountHelper::updateAccount));    AccountService as;    as.setAccountManager(pManager);    as.topup("B", 1005);    as.topup("A", 5);     EXPECT_EQ(10, helper.findAccountForUser("A").getBalance());    EXPECT_EQ(1005, helper.findAccountForUser("B").getBalance());    delete pManager;}int main(int argc, char **argv) {    ::testing::InitGoogleMock(&argc, argv);    return RUN_ALL_TESTS();}
# Makefile.linux# Makefile for Mr.H CSDN blog - Do a research on Gtest/Gmock 2017.12.14# Make command to use for dependenciesMAKE=makeRM=rmMKDIR=mkdir# Only "Debug" version for testCFG=Debug## Configuration: Debug#ifeq "$(CFG)" "Debug"OUTDIR=DebugOUTFILE=$(OUTDIR)/testCFG_INC=-I../gmock-1.7.0/include -I../gmock-1.7.0/gtest/include CFG_LIB=-lpthread -lc -lm -lrt -lgtest -lgmock -L ../gmock-1.7.0/lib/.libs \    -L ../gmock-1.7.0/gtest/lib/.libs CFG_OBJ=COMMON_OBJ=$(OUTDIR)/AccountHelper.o $(OUTDIR)/AccountService.o $(OUTDIR)/main.o OBJ=$(COMMON_OBJ) $(CFG_OBJ)ALL_OBJ=$(OUTDIR)/AccountHelper.o $(OUTDIR)/AccountService.o \    $(OUTDIR)/main.o -lpthread -lc -lm -lrt -lgtest -lgmock -L ../gmock-1.7.0/lib/.libs \    -L ../gmock-1.7.0/gtest/lib/.libs COMPILE=g++ -c   -g -o "$(OUTDIR)/$(*F).o" $(CFG_INC) $<LINK=g++  -g -o "$(OUTFILE)" $(ALL_OBJ)# Pattern rules$(OUTDIR)/%.o : %.cpp    $(COMPILE)# Build rulesall: $(OUTFILE)$(OUTFILE): $(OUTDIR)  $(OBJ)    $(LINK)    -cp Debug/test ./$(OUTDIR):    $(MKDIR) -p "$(OUTDIR)"# Rebuild this projectrebuild: cleanall all# Clean this projectclean:    $(RM) -f $(OUTFILE)    $(RM) -f $(OBJ)# Clean this project and all dependenciescleanall: cleanendif

说明:
    这里只给出linux上的编译运行方式(代码使用标准STL库,所以Windows上也能运行,编译方法大家自己研究)
    编译: make -f Makefile.linux
    运行:./test
    输出:

[==========] Running 2 tests from 1 test case.[----------] Global test environment set-up.[----------] 2 tests from AccountServiceTest[ RUN      ] AccountServiceTest.transferTest[       OK ] AccountServiceTest.transferTest (0 ms)[ RUN      ] AccountServiceTest.topupTest[       OK ] AccountServiceTest.topupTest (0 ms)[----------] 2 tests from AccountServiceTest (0 ms total)[----------] Global test environment tear-down[==========] 2 tests from 1 test case ran. (0 ms total)[  PASSED  ] 2 tests.
原创粉丝点击