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

C语言单元测试:Ceedling框架下指针参数匹配问题

Ceedling单元测试:匹配llist_remove_all参数的问题

问题描述

我在使用Ceedling框架做C语言单元测试时,遇到了参数匹配的问题:
测试代码中期望llist_remove_all接收的参数是&new_list,但被测试函数task_find_by调用该函数时,传入的是内部指针new的地址。虽然new和new_list指向同一个struct Person实例,但两个指针变量本身的内存地址不同,导致测试的参数匹配失败。现在需要在不修改task_find_by实现的前提下完成测试验证。

测试代码

struct Person *list;
/* TASK_FIND_BY */
void test_main_task_find_by_normal(void)
{
    char *string = (char *)malloc(sizeof(char));
    struct Person new_list_instance;
    struct Person *new_list = &new_list_instance;
    ask_input_ExpectAndReturn(string);
    llist_find_by_ExpectAndReturn(list, string, new_list);
    llist_print_Expect(new_list);
    llist_remove_all_Expect(&new_list);

    printf("\nOutside single: %p\n", new_list);
    printf("Outside double: %p\n", &new_list);

    task_find_by(list);
}

被测试函数

void task_find_by(struct Person *list)
{
    char *input = NULL;
    struct Person *new = NULL;

    printf("Input exact name/surname/email/phone: ");
    input = ask_input();
    if (input == NULL) {
        printf("Error!");
        return;
    }
    new = llist_find_by(list, input);
    if (new != NULL)
        llist_print(new);
    else 
        printf("Address not found!\n");
    
    printf("\nInside single: %p\n", new);
    printf("\nInside double: %p\n", &new);
    
    free(input);
    llist_remove_all(&new);
}

运行时地址输出

  • "Outside single: 0x7ffc2e3c03d0"
  • "Outside double: 0x7ffc2e3c03c0"
  • "Inside single: 0x7ffc2e3c03d0"
  • "Inside double: 0x7ffc2e3c0398"

解决方案

Ceedling依赖的CMock框架支持参数回调验证,可以绕过指针变量地址的严格匹配,转而验证指针指向的内容是否符合预期。具体步骤如下:

1. 修改测试代码,使用回调验证参数

把原来的llist_remove_all_Expect(&new_list)替换为「忽略参数匹配+回调验证」的逻辑,核心是检查llist_remove_all接收的指针(&new)指向的内容(即new的值)是否等于测试中的new_list。

修改后的测试代码:

struct Person *list;
/* TASK_FIND_BY */
void test_main_task_find_by_normal(void)
{
    char *string = (char *)malloc(sizeof(char));
    static struct Person new_list_instance;
    static struct Person *new_list = &new_list_instance;

    // 定义参数验证回调:检查传入的二级指针指向的内容是否为预期的指针
    void verify_llist_remove_all_arg(struct Person** arg) {
        TEST_ASSERT_EQUAL_PTR(new_list, *arg);
    }

    ask_input_ExpectAndReturn(string);
    llist_find_by_ExpectAndReturn(list, string, new_list);
    llist_print_Expect(new_list);

    // 替换原有的Expect,改为忽略参数并添加验证回调
    llist_remove_all_ExpectAnyArg();
    llist_remove_all_StubWithCallback((void*)verify_llist_remove_all_arg);

    printf("\nOutside single: %p\n", new_list);
    printf("Outside double: %p\n", &new_list);

    task_find_by(list);

    free(string); // 释放内存,避免测试内存泄漏
}

2. 原理说明

  • llist_remove_all_ExpectAnyArg():告诉CMock不严格匹配参数的具体地址,允许任意参数传入。
  • llist_remove_all_StubWithCallback():注册一个回调函数,当llist_remove_all被调用时,CMock会将实际传入的参数(即task_find_by中的&new)传给这个回调。
  • 在回调verify_llist_remove_all_arg中,通过TEST_ASSERT_EQUAL_PTR验证*arg(也就是new的值)是否等于new_list,这样就实现了我们需要的逻辑:只要new指向的是预期的struct Person实例,即使&new和&new_list地址不同,测试也能通过。

内容的提问来源于stack exchange,提问作者Mykolas D.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 10:48:08