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

如何为大量typedef结构体创建C语言通用测试框架?

通用C语言结构体测试框架实现方案

这个场景太适合用C的宏系统来实现通用测试框架了——毕竟C没有原生泛型,宏就是我们实现“泛型”逻辑的最佳工具。我给你一套可扩展的方案,能轻松应对上百个typedef结构体的测试需求:

核心思路

利用C的宏定义生成针对不同结构体类型的测试代码,同时通过自动注册机制让driver.c无需修改就能执行所有测试。核心分为三个部分:

  • 通用断言宏:支持自定义结构体相等判断
  • 测试注册机制:自动把测试函数加入执行列表
  • 测试生成宏:一键生成指定结构体的测试函数

完整代码实现

1. 测试框架头文件 test_framework.h

#ifndef TEST_FRAMEWORK_H
#define TEST_FRAMEWORK_H

#include <stdio.h>

// 通用断言宏:接受类型、两个值、自定义相等判断函数
#define ASSERT_EQ(type, a, b, equal_func) \
    do { \
        if (!equal_func((a), (b))) { \
            fprintf(stderr, "Assertion failed: %s == %s\nLocation: %s:%d\n", #a, #b, __FILE__, __LINE__); \
            return 1; \
        } \
    } while(0)

// 测试函数的统一类型定义
typedef int (*TestFunc)(void);

// 测试链表节点:用于管理所有测试函数
typedef struct TestNode {
    TestFunc func;
    const char* test_name;
    struct TestNode* next;
} TestNode;

extern TestNode* test_head;

// 自动注册测试函数的宏(GCC扩展,其他编译器可替换为手动注册)
#define REGISTER_TEST(test_func) \
    static TestNode test_node_##test_func = { \
        .func = test_func, \
        .test_name = #test_func, \
        .next = NULL \
    }; \
    __attribute__((constructor)) static void register_##test_func(void) { \
        test_node_##test_func.next = test_head; \
        test_head = &test_node_##test_func; \
    }

// 一键生成结构体测试的宏
#define GENERATE_STRUCT_TEST(test_name, struct_type, target_func, expected_val, equal_func) \
    int test_name(void) { \
        printf("Running test: %s\n", #test_name); \
        struct_type result = target_func(); \
        ASSERT_EQ(struct_type, result, expected_val, equal_func); \
        printf("✅ Test %s passed!\n", #test_name); \
        return 0; \
    } \
    REGISTER_TEST(test_name)

#endif // TEST_FRAMEWORK_H

2. 测试驱动文件 driver.c

#include "test_framework.h"

TestNode* test_head = NULL;

int main() {
    TestNode* current = test_head;
    int total_tests = 0;
    int failed_tests = 0;

    printf("=== Starting All Tests ===\n\n");

    while (current != NULL) {
        total_tests++;
        if (current->func() != 0) {
            failed_tests++;
        }
        printf("\n");
        current = current->next;
    }

    printf("=== Test Summary ===\n");
    printf("Total: %d | Passed: %d | Failed: %d\n", 
           total_tests, total_tests - failed_tests, failed_tests);

    return failed_tests != 0;
}

3. 示例测试文件 struct_tests.c

#include "test_framework.h"
#include <string.h>

// 第一个测试结构体类型
typedef struct {
    int user_id;
    char username[32];
} user_t;

user_t create_default_user() {
    user_t u = {.user_id = 1001, .username = "john_doe"};
    return u;
}

// 自定义user_t的相等判断函数(处理字符串等非简单类型)
int user_equal(user_t a, user_t b) {
    return a.user_id == b.user_id && strcmp(a.username, b.username) == 0;
}

// 一键生成测试,自动注册
GENERATE_STRUCT_TEST(test_default_user, user_t, create_default_user, 
                     (user_t){.user_id=1001, .username="john_doe"}, user_equal)

// 第二个测试结构体类型
typedef struct {
    float temperature;
    int is_active;
} sensor_t;

sensor_t create_initial_sensor() {
    sensor_t s = {.temperature = 25.5f, .is_active = 1};
    return s;
}

// 浮点类型的相等判断要注意精度
int sensor_equal(sensor_t a, sensor_t b) {
    const float EPS = 0.0001f;
    return (a.temperature - b.temperature < EPS && a.temperature - b.temperature > -EPS) 
           && a.is_active == b.is_active;
}

GENERATE_STRUCT_TEST(test_initial_sensor, sensor_t, create_initial_sensor, 
                     (sensor_t){.temperature=25.5f, .is_active=1}, sensor_equal)

使用说明

  1. 对每个需要测试的结构体:
    • 定义结构体类型和对应的待测试函数
    • 实现该结构体的相等判断函数(处理指针、浮点数等特殊情况)
    • 调用GENERATE_STRUCT_TEST宏生成测试,无需手动修改driver.c
  2. 编译时把所有测试文件和driver.c一起编译即可

关键注意事项

  • 如果结构体包含指针成员,绝对不能用memcmp,必须在相等判断函数里手动比较指针指向的内容
  • 浮点类型的比较要设置合理的精度阈值,避免因浮点误差导致断言失败
  • 若需兼容非GCC编译器,可以把__attribute__((constructor))替换为手动注册:比如在每个测试文件里写一个init_test函数,然后在driver.c里手动调用所有init_test

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:01:49