清单 8. 待测试的程序逻辑
// 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.cpp #include "Account.h" Account::Account() { } Account::Account(const std::string& accountId, long initialBalance) { this->accountId = accountId; this->balance = initialBalance; } void Account::debit(long amount) { this->balance -= amount; } void Account::credit(long amount) { this->balance += amount; } long Account::getBalance() const { return this->balance; } std::string Account::getAccountId() const { return accountId; } // AccountManager.h // the interface of external services which should be mocked #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; }; // AccountService.h // the class to be tested #pragma once #include <string> #include "Account.h" #include "AccountManager.h" class AccountService { private: AccountManager* pAccountManager; public: AccountService(); void setAccountManager(AccountManager* pManager); void transfer(const std::string& senderId, const std::string& beneficiaryId, long amount); }; // AccountService.cpp #include "AccountService.h" AccountService::AccountService() { this->pAccountManager = NULL; } void AccountService::setAccountManager(AccountManager* pManager) { this->pAccountManager = pManager; } void AccountService::transfer(const std::string& senderId, const std::string& beneficiaryId, long amount) { Account sender = this->pAccountManager->findAccountForUser(senderId); Account beneficiary = this->pAccountManager->findAccountForUser(beneficiaryId); sender.debit(amount); beneficiary.credit(amount); this->pAccountManager->updateAccount(sender); this->pAccountManager->updateAccount(beneficiary); } |
清单 9. 相应的单元测试
// AccountServiceTest.cpp // code to test AccountService #include <map> #include <string> #include <gtest/gtest.h> #include <gmock/gmock.h> #include "../Account.h" #include "../AccountService.h" #include "../AccountManager.h" // MockAccountManager, mock AccountManager with googlemock class MockAccountManager : public AccountManager { public: MOCK_METHOD1(findAccountForUser, Account(const std::string&)); MOCK_METHOD1(updateAccount, void(const Account&)); }; // 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(); } // 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; } // Main.cpp #include <gtest/gtest.h> #include <gmock/gmock.h> int main(int argc, char** argv) { testing::InitGoogleMock(&argc, argv); // Runs all tests using Google Test. return RUN_ALL_TESTS(); } |