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

C++中如何mock std::localtime以适配GTest单元测试需求

方案1:依赖注入改造(优先推荐)

这是最干净、跨平台兼容的方案,不需要依赖编译器特性,还能提升整体代码的可测性。

  1. 先封装一层时间获取的抽象接口,替代直接调用系统API
class ITimeProvider {
public:
    virtual ~ITimeProvider() = default;
    virtual time_t getCurrentTime() const = 0;
    virtual tm* getLocalTime(const time_t* time) const = 0;
};

// 生产环境用的默认实现
class SystemTimeProvider : public ITimeProvider {
public:
    time_t getCurrentTime() const override {
        return time(nullptr);
    }
    tm* getLocalTime(const time_t* time) const override {
        return localtime(time);
    }
};
  1. 修改原业务代码,将时间提供者作为参数注入,默认用系统实现,不影响原有调用逻辑
    假设你原代码在某个函数内,改造后示例:
// 默认参数用系统时间提供者,生产代码调用不需要传参
void yourBusinessFunc(const ITimeProvider& timeProvider = SystemTimeProvider{}) {
    time_t now = timeProvider.getCurrentTime();
    tm *currentTime = timeProvider.getLocalTime(&now);
    HelperClass helper({(uint8_t)currentTime->tm_mday,(uint8_t)(1+ currentTime->tm_mon),
                        (uint16_t)(currentTime->tm_year+1900),
                        (uint8_t)currentTime->tm_hour,
                        (uint8_t)currentTime->tm_min,(uint8_t)currentTime->tm_sec});
    // 原有后续逻辑
}
  1. 用GMock实现Mock类,编写测试用例
#include <gmock/gmock.h>
class MockTimeProvider : public ITimeProvider {
public:
    MOCK_METHOD(time_t, getCurrentTime, (), (const, override));
    MOCK_METHOD(tm*, getLocalTime, (const time_t*), (const, override));
};

TEST(HelperClassTest, TimeParamParseCorrect) {
    MockTimeProvider mockProvider;
    // 构造测试用的固定时间:2024-05-20 13:14:00
    tm testTm = {0};
    testTm.tm_mday = 20;
    testTm.tm_mon = 4; // 系统tm的月份从0开始计数
    testTm.tm_year = 2024 - 1900; // 年份从1900开始计数
    testTm.tm_hour = 13;
    testTm.tm_min = 14;
    testTm.tm_sec = 0;
    time_t testTime = mktime(&testTm);

    // 设置mock预期返回值
    EXPECT_CALL(mockProvider, getCurrentTime()).WillOnce(testing::Return(testTime));
    EXPECT_CALL(mockProvider, getLocalTime(testing::Eq(&testTime))).WillOnce(testing::Return(&testTm));

    // 注入mock调用业务逻辑
    yourBusinessFunc(mockProvider);
    // 这里补充你对HelperClass输出结果的断言即可
}

方案2:链接期打桩(适合不能修改原业务代码的场景)

如果你的原代码没法做依赖注入改造,可以用GCC/Clang的链接替换特性打桩系统函数:

  1. 编译测试程序时加链接参数:
    -Wl,--wrap=time,--wrap=localtime
  2. 在测试代码中实现wrap替换函数,用全局变量控制返回值
extern "C" {
// 声明真实系统函数
time_t __real_time(time_t* t);
tm* __real_localtime(const time_t* t);

// 全局mock控制变量,测试前赋值,测试后重置
time_t g_mockTimeVal = 0;
tm* g_mockLocalTimeRet = nullptr;

time_t __wrap_time(time_t* t) {
    if (g_mockTimeVal != 0) {
        if (t) *t = g_mockTimeVal;
        return g_mockTimeVal;
    }
    return __real_time(t);
}

tm* __wrap_localtime(const time_t* t) {
    if (g_mockLocalTimeRet != nullptr) {
        return g_mockLocalTimeRet;
    }
    return __real_localtime(t);
}
}
  1. 测试用例直接修改全局控制变量即可指定返回值,用完记得重置避免影响其他用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:27:01