如何Mock对boost::posix_time::microsec_clock::local_time()的调用?
解决方案
首先明确之前直接Mock函数不生效的核心原因:代码中硬编码了对pt::microsec_clock::local_time()的直接调用,该函数是boost库的静态成员函数,默认编译场景下可能被内联优化,Mock框架无法拦截无虚函数接口的静态/全局函数调用。
方案1:依赖注入改造(最稳定,推荐使用)
通过抽象时间获取接口,将时间获取逻辑从业务代码中解耦,实现可Mock性,改造对原有生产逻辑无侵入。
步骤1:定义时间提供者抽象接口
#include <boost/date_time/posix_time/posix_time.hpp> namespace pt = boost::posix_time; class TimeProvider { public: virtual ~TimeProvider() = default; virtual pt::ptime getCurrentLocalTime() const = 0; };
步骤2:实现生产环境用的真实时间提供者
class RealTimeProvider : public TimeProvider { public: pt::ptime getCurrentLocalTime() const override { return pt::microsec_clock::local_time(); } };
步骤3:修改OEManager类,注入时间提供者
给OEManager增加TimeProvider类型的成员,构造函数默认注入真实时间提供者,不影响原有生产逻辑:
class OEManager { private: std::unique_ptr<TimeProvider> time_provider_; int sequence_id = 0; // 原有成员 public: // 构造函数默认使用真实时间提供者,生产环境无感知 explicit OEManager(std::unique_ptr<TimeProvider> provider = std::make_unique<RealTimeProvider>()) : time_provider_(std::move(provider)) {} std::string generateActionCommand(const char* cmd_type); // 其他原有方法 };
步骤4:修改generateActionCommand的时间获取逻辑
将原来直接调用boost接口的代码替换为调用注入的时间提供者接口:
std::string OEManager::generateActionCommand(const char* cmd_type) { std::string ret_msg; // 替换原有硬编码的boost调用 pt::ptime current_time = time_provider_->getCurrentLocalTime(); char timestamp[13]; snprintf(timestamp, 13, "%02d:%02d:%02d.%03d", current_time.time_of_day().hours(), current_time.time_of_day().minutes(), current_time.time_of_day().seconds(), // 微秒转毫秒,适配格式化逻辑 current_time.time_of_day().fractional_seconds() / 1000); ret_msg = timestamp; ret_msg.append ("," + std::to_string(sequence_id) + "," + cmd_type); return ret_msg; }
步骤5:编写Mock类和测试用例
用turtle-mock定义Mock时间提供者,即可自定义返回指定时间点,精确校验生成的字符串:
#include <turtle/mock.hpp> // 定义Mock类 MOCK_BASE_CLASS(MockTimeProvider, TimeProvider) { MOCK_CONST_METHOD(getCurrentLocalTime, 0, pt::ptime()); }; // 测试用例示例 BOOST_AUTO_TEST_CASE(test_generateActionCommand_timestamp_correct) { // 构造预期时间:2024-05-20 13:14:15.123 pt::ptime test_time(pt::date(2024,5,20), pt::time_duration(13,14,15, 123000)); auto mock_provider = std::make_unique<MockTimeProvider>(); // 设置mock返回指定时间 MOCK_EXPECT(mock_provider->getCurrentLocalTime).returns(test_time); // 注入mock对象构造OEManager OEManager manager(std::move(mock_provider)); // 假设sequence_id为1001,根据实际实现赋值 std::string result = manager.generateActionCommand("START"); // 直接精确比对结果,不需要正则校验 BOOST_CHECK_EQUAL(result, "13:14:15.123,1001,START"); }
方案2:链接期全局Mock(不推荐)
如果不想修改原有类结构,可以尝试全局Mock,但存在编译优化导致拦截失效的风险:
- 确保编译时关闭boost相关函数的内联优化,添加编译参数
-fno-inline等(不同平台参数不同) - 正确指定命名空间,用turtle的MOCK_FUNCTION定义mock:
MOCK_FUNCTION(pt::microsec_clock, local_time, 0, pt::ptime());
- 测试用例中设置该函数的返回值即可,但是这种方案在不同编译器、不同编译配置下稳定性很差,不建议生产测试使用。
内容的提问来源于stack exchange,提问作者Gionata Benelli
相关产品推荐
相关产品推荐

