如何在单元测试中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
相关产品推荐
相关产品推荐

