首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 單元測試實戰:打樁測試與 Google Mock 完整指南

     編輯:C++ 入門

問題背景

單元測試的核心挑戰:被測函數內部依賴外部資源(資料庫、網路服務、硬體介面等)。若不隔離依賴,測試將變得緩慢、不穩定、難以構造邊界條件。

典型場景:

class DataGetter {
    Client* m_ptr_client;
public:
    bool Run() {
        std::string data;
        bool ret = m_ptr_client->GetData(data); // 依賴 TCP 協議從服務端獲取數據
        // ... 處理 data ...
        return ret;
    }
};

直接測試 Run() 需啟動真實服務端、構造網路環境,極不現實。

打樁核心原理

利用 C++ 多態機制:將依賴抽象為介面(虛函數),運行時注入測試專用的「樁」實現,替換真實依賴。

  1. 確保依賴方法為 virtual(或抽象介面類)。
  2. 繼承依賴類,重寫目標方法,返回預設測試數據。
  3. 構造時注入樁對象替換真實依賴。

手動打樁實現

// 真實依賴介面
class Client {
public:
    virtual ~Client() = default;
    virtual bool GetData(std::string& data) = 0;
};

// 手寫樁類
class StubClient : public Client {
    std::string presetData_;
    bool presetResult_;
public:
    StubClient(std::string data, bool result) : presetData_(std::move(data)), presetResult_(result) {}
    bool GetData(std::string& data) override {
        data = presetData_;
        return presetResult_;
    }
};

// 測試代碼
TEST(DataGetterTest, Run_ReturnsTrue_WhenDataValid) {
    DataGetter getter;
    getter.m_ptr_client = new StubClient("valid_data", true); // 注入樁
    EXPECT_TRUE(getter.Run());
    delete getter.m_ptr_client;
}

Google Mock 框架實戰

Google Mock (gMock) 是業界標準 C++ Mock 框架,自動生成 Mock 類,支援期望值設定、參數匹配、動作序列等高級功能。

基本用法


#include "client.h"
#include <gmock/gmock.h>

class MockClient : public Client {
public:
    MOCK_METHOD(bool, GetData, (std::string&), (override));
};

期望值設定與行為控制


TEST(DataGetterTest, Run_HandlesMultipleCalls) {
    auto mockClient = std::make_unique<MockClient>();
    DataGetter getter;
    getter.m_ptr_client = mockClient.get(); // 注入 Mock

    // 設定期望:呼叫 2 次,第 1 次返回成功與數據,第 2 次返回失敗
    EXPECT_CALL(*mockClient, GetData(testing::_))
        .Times(2)
        .WillOnce(testing::DoAll(
            testing::SetArgReferee<0>("first_response"),
            testing::Return(true)))
        .WillOnce(testing::DoAll(
            testing::SetArgReferee<0>("second_response"),
            testing::Return(false)));

    EXPECT_TRUE(getter.Run());  // 第 1 次呼叫
    EXPECT_FALSE(getter.Run()); // 第 2 次呼叫
}

常用 Matcher 與 Action

分類常用語法說明
參數匹配_匹配任意值
Eq(value) / StrEq("str")精確匹配
Ge(10), Lt(5)範圍匹配
Ref(variable)匹配引用參數
返回動作Return(value)返回固定值
SetArgReferee<N>(value)設定第 N 個引用參數值
Invoke(callable)呼叫自定義函數/lambda
Throw(exception)拋出異常
調用次數Times(n)確切 n 次
AtLeast(n) / AtMost(n)至少/至多 n 次
AnyNumber()任意次數

最佳實踐總結

  • 依賴倒置:高層模組不應依賴低層模組,雙方依賴抽象介面。
  • 構造函數注入:優先透過構造函數傳入依賴,而非 setter,確保對象創建即完整。
  • 測試行為而非實現:驗證輸出結果與副作用,避免過度檢查內部調用細節。
  • 命名規範:MethodName_Scenario_ExpectedResult,如 GetData_NetworkTimeout_ReturnsFalse。
  • 避免測試邏輯過複雜:單元測試應簡單、快速、獨立、可重複執行。

參考資源

  • Google Mock 官方文檔:github.com/google/googletest
  • 《Effective C++》條款 18:介面設計易於正確使用,難以誤用
  • 《單元測試的藝術》第 3 章:使用 Mock 物件隔離依賴
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved