You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单元测试中Mock第三方库的httplib::Client类?

如何Mock第三方具体类(如httplib::Client)

针对第三方库提供的具体类(无法直接继承Mock的场景),最通用且可靠的方案是使用适配器模式:通过自定义抽象接口封装第三方类的行为,让业务代码依赖抽象而非具体实现,这样就能像Mock自定义接口一样完成测试。

步骤1:定义自定义抽象接口

根据业务实际用到的httplib::Client方法,提取对应的纯虚函数接口(只封装业务需要的方法,无需覆盖第三方类的全部功能):

#include <optional>
#include <string>
#include "httplib.h"

class IHttpClient {
public:
    virtual ~IHttpClient() = default; // 必须定义虚析构函数
    virtual std::optional<httplib::Response> Get(const std::string& path) = 0;
    virtual std::optional<httplib::Response> Post(const std::string& path, 
                                                  const std::string& body, 
                                                  const std::string& content_type) = 0;
};

步骤2:实现适配器类

创建适配器类继承IHttpClient,内部封装httplib::Client实例,将接口方法转发给实际的第三方类调用:

class HttplibClientAdapter : public IHttpClient {
private:
    httplib::Client client_;
public:
    // 构造函数传递第三方类所需的初始化参数
    HttplibClientAdapter(const std::string& host, int port) 
        : client_(host, port) {}

    std::optional<httplib::Response> Get(const std::string& path) override {
        auto res = client_.Get(path);
        return res ? std::optional<httplib::Response>(*res) : std::nullopt;
    }

    std::optional<httplib::Response> Post(const std::string& path, 
                                          const std::string& body, 
                                          const std::string& content_type) override {
        auto res = client_.Post(path, body, content_type);
        return res ? std::optional<httplib::Response>(*res) : std::nullopt;
    }
};

步骤3:修改业务类依赖抽象接口

让业务类依赖IHttpClient而非直接依赖httplib::Client,通过依赖注入传递实例:

class MyBusinessClass {
private:
    std::shared_ptr<IHttpClient> http_client_;
public:
    MyBusinessClass(std::shared_ptr<IHttpClient> client) 
        : http_client_(std::move(client)) {}

    bool fetchData() {
        auto res = http_client_->Get("/api/data");
        // 业务逻辑:判断请求是否成功
        return res.has_value() && res->status == 200;
    }
};

步骤4:测试时Mock自定义接口

使用测试框架(如Google Test/Mock)MockIHttpClient,模拟第三方类的行为:

#include <gmock/gmock.h>
#include <gtest/gtest.h>

class MockHttpClient : public IHttpClient {
public:
    MOCK_METHOD(std::optional<httplib::Response>, Get, 
                (const std::string& path), (override));
    MOCK_METHOD(std::optional<httplib::Response>, Post, 
                (const std::string& path, const std::string& body, const std::string& content_type), 
                (override));
};

TEST(MyBusinessClassTest, FetchData_Success) {
    // 创建Mock实例
    auto mock_client = std::make_shared<MockHttpClient>();
    
    // 模拟Get请求返回成功响应
    httplib::Response mock_res;
    mock_res.status = 200;
    
    EXPECT_CALL(*mock_client, Get("/api/data"))
        .WillOnce(testing::Return(std::optional<httplib::Response>(mock_res)));
    
    // 初始化业务类并执行测试
    MyBusinessClass business(mock_client);
    ASSERT_TRUE(business.fetchData());
}

补充说明

  • 如果第三方类本身设计为可继承(包含虚函数),可以直接继承它创建Mock类,但这种情况在第三方库中很少见(多数具体类不会开放虚接口),因此适配器模式是更通用的选择。
  • 适配器类只需要封装业务实际用到的方法,避免不必要的代码冗余。

内容的提问来源于stack exchange,提问作者Cashif Ilyas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 22:50:09