Cmocka使用问题:如何mock通过函数指针调用的外部函数
Cmocka模拟结构体函数指针调用的方案
因为你的代码中是通过结构体成员的函数指针发起调用,不是直接调用全局外部函数,所以不需要用-Wl,--wrap的链接劫持方案,直接绑定自定义mock函数到对应函数指针即可,配合Cmocka原生的参数校验、返回值预设能力完成测试,具体实现步骤如下:
步骤1:定义和目标函数签名完全匹配的mock函数
要保证mock函数的返回值、入参个数和类型和原init函数指针的定义完全一致,示例代码:
#include <stdarg.h> #include <stddef.h> #include <setjmp.h> #include <cmocka.h> // 假设原init函数指针的签名为 INT32 (*init)(dev_t *dev),mock函数签名要完全对齐 INT32 mock_dev_init(dev_t *dev) { // 可选:校验传入的dev参数是否符合测试预期 check_expected(dev); // 返回测试用例中预设的mock返回值 return mock_type(INT32); }
步骤2:编写测试用例,绑定mock函数到结构体的函数指针
在测试用例中构造被测shell实例依赖的dev、ops结构体,将mock函数赋值给ops->init指针,再预设测试参数和返回值即可执行测试,以下是测试初始化失败场景的示例:
static void test_shellInit_dev_init_fail(void **state) { // 构造测试所需的各结构体实例 shell_t test_shell = {0}; dev_t test_dev = {0}; // 绑定mock函数到init函数指针 dev_ops_t test_ops = { .init = mock_dev_init }; // 组装指针关系,和被测代码的访问链路保持一致 test_shell.dev = &test_dev; test_dev.ops = &test_ops; // 预设mock函数的入参预期和返回值 expect_value(mock_dev_init, dev, &test_dev); will_return(mock_dev_init, ZKOS_FAILURE); // 模拟初始化失败场景 // 调用被测函数 INT32 ret = shellInit(&test_shell); // 校验结果是否符合预期 assert_int_equal(ret, ZKOS_FAILURE); }
其他测试场景扩展
- 测试
init指针为空的分支:直接将test_ops.init赋值为NULL即可,无需绑定mock函数,校验shellInit返回ZKOS_SUCCESS - 测试初始化成功的场景:把
will_return的返回值改为ZKOS_SUCCESS,校验返回值为成功即可 - 多次调用同一个mock函数的场景:多次调用
will_return压入多个返回值,mock函数会按调用顺序依次取出返回
内容的提问来源于stack exchange,提问作者Wanghz
相关产品推荐
相关产品推荐

