如何用mock-turtle mock外部库函数解决链接错误?
针对你遇到的undefined reference to 'send_conf'链接错误,本质是测试编译时未链接libdevice库,且A.cpp直接硬编码调用了该库函数。下面给你几个实用的解决思路:
方案一:用编译宏切换实际调用与Mock函数
这种方式无需大幅修改现有代码,通过预编译宏控制A.cpp调用的是实际库函数还是Mock函数:
- 修正并修改A.cpp,添加宏判断:
#include <libdevice.h> class A{ public: bool connect() { int myconf = 3; #ifdef TEST_MODE // 测试模式下调用mock的send_conf extern "C" int send_conf(int); #endif if(send_conf(myconf) == -1) { return false; } return true; } };
(注:原代码中public class A是C++语法错误,已修正为标准类定义)
编译测试代码时添加宏定义:
例如使用g++编译时,加上-DTEST_MODE参数,让A.cpp编译为调用mock版本的send_conf,无需链接libdevice库。测试代码保持原有Mock定义:
test_A.cpp中的MOCK_FUNCTION定义不变,编译测试时链接mock-turtle与Boost.Test库即可。
方案二:封装外部依赖为接口(更优雅的解耦方式)
若希望代码结构更灵活、易维护,可将外部库函数封装为抽象接口,让A类依赖接口而非直接调用库函数:
- 定义抽象接口类:
新建DeviceController.h文件:
class DeviceController { public: virtual ~DeviceController() = default; virtual int send_conf(int conf) = 0; };
- 实现生产环境的控制器:
新建RealDeviceController.cpp:
#include "DeviceController.h" #include <libdevice.h> class RealDeviceController : public DeviceController { public: int send_conf(int conf) override { return ::send_conf(conf); // 调用实际库的send_conf } };
- 修改A类,依赖接口:
修改A.cpp:
#include "DeviceController.h" class A{ private: DeviceController* controller; public: // 构造时注入控制器,生产环境传RealDeviceController,测试传mock A(DeviceController* ctrl) : controller(ctrl) {} bool connect() { int myconf = 3; if(controller->send_conf(myconf) == -1) { return false; } return true; } };
- 测试时Mock接口类:
用mock-turtle模拟DeviceController接口,修改test_A.cpp:
#include "DeviceController.h" #include "A.h" #include <mockturtle/mockturtle.hpp> #include <boost/test/unit_test.hpp> using namespace mockturtle; BOOST_AUTO_TEST_CASE(connect_test) { // 创建mock的DeviceController mock<DeviceController> mock_ctrl; MOCK_EXPECT(mock_ctrl.send_conf).once().with(3).returns(-1); // 注入mock对象到A类 A myA(mock_ctrl.get()); bool ret = myA.connect(); BOOST_CHECK_EQUAL(ret, false); }
这种方式彻底解耦了A类与外部库的依赖,测试时无需关心libdevice的存在,更符合面向接口编程思想。
方案三:利用链接优先级覆盖符号(快速临时方案)
若不想修改太多代码,可利用链接器的符号优先级,让mock的send_conf先被链接,覆盖实际库的符号:
确保Mock函数为C语言导出:
你的test_A.cpp已用extern "C"包裹MOCK_FUNCTION,这一步没问题(libdevice的send_conf应为C语言导出)。调整编译链接顺序:
编译时先链接test_A.o再链接A.o,例如:
g++ -c A.cpp -o A.o g++ -c test_A.cpp -o test_A.o -I/path/to/mockturtle -I/path/to/boost g++ test_A.o A.o -o test_A -lboost_unit_test_framework -lmockturtle
链接器会优先从test_A.o找到send_conf符号,不会再去libdevice中查找。但这种方式依赖链接顺序,稳定性较差,适合临时测试场景。
内容的提问来源于stack exchange,提问作者Gionata Benelli

