C语言的3种打桩方法总结

        前段时间项目组相对很久以前的工程做单元测试,由于比较久远内部逻辑复杂,外部依赖都比较多,所以想通过打桩的方式(不但要对外部接口还得可以对内部函数)进行函数级别的单元测试。调查了几个方法记录一下,以备以后参照。

  • google的cmockery框架实现

       优点很多,请大家自行google。

        但cmockery不能对内部函数进行打桩,所以不满足我们要求。

  • 利用C编译器预编译的特点,通过宏定义实现

       利用C编译器的预编译特点,通过宏定义替换需要打桩的函数。直接上代码。

        main.c

#include "test.h"

// 把func1替换成func1_stub_行号
#define func1 func1_(__LINE__)
#define func1_(line) func1__(line)
#define func1__(line) func1_stub_ ## line

// 把func2替换成func2_stub_行号
#define func2 func2_(__LINE__)
#define func2_(line) func2__(line)
#define func2__(line) func2_stub_ ## line

//test函数中func1为第5行
void func1_stub_5(void)
{
    printf("func1_stub\n");
}

//test函数中func1为第6行
void func2_stub_6(void)
{
    printf("func2_
<think>好的,我现在需要帮助用户了解如何使用cppstub对C语言中的静态函数进行打桩。首先,我需要回顾用户提供的引用内容,看看有没有相关的信息。 用户提到了引用[3],指出Stub API的源码地址是GitHub上的cpp-stub项目。另外,引用[4]提到了Mockito处理构造函数和静态方法时需要在try块或使用@BeforeEach/@AfterEach方法,这可能与资源管理有关,但用户的问题是关于C语言的,而引用[4]是Java的Mockito,可能不直接相关。不过,这提醒我要注意资源释放的问题。 用户的需求明确是针对C语言的静态函数打桩。首先,我需要确认cpp-stub是否支持C语言的静态函数打桩。通常,C的静态函数(static functions)的作用域限于当前文件,这可能导致直接打桩困难,因为它们对其他文件不可见。因此,可能需要通过头文件包含或预处理器宏来覆盖这些函数。 接下来,根据cpp-stub的文档或示例,查找是否有相关示例。假设cpp-stub使用类似宏定义或函数指针替换的方法打桩。例如,在测试时,可以通过宏替换静态函数的定义,或者在链接时替换目标文件。 可能的步骤包括: 1. 包含被测源文件,以便访问静态函数。 2. 使用宏或函数指针替换静态函数。 3. 在测试用例中设置桩函数的行为。 4. 执行测试并验证结果。 需要确保在打桩时,测试框架能够正确替换静态函数,同时处理好作用域和链接问题。例如,如果被测文件中的静态函数在编译单元内,可能需要通过包含源文件的方式(如#include "source.c")来访问,但这可能带来其他问题,如重复定义。另一种方法是使用链接器包装(如--wrap选项),但cpp-stub是否支持这种方式需要确认。 另外,引用[1]中的单例模式实现可能展示了静态局部变量的使用,但这里可能不直接相关。引用[2]中的C++代码示例涉及静态成员变量,但用户的问题是C语言,所以需要区分C和C++的不同处理方式。 总结步骤: - 包含被测源文件以访问静态函数。 - 使用cpp-stub提供的API设置桩函数。 - 在测试中调用被测函数,验证桩函数是否被正确调用。 可能的代码示例可能涉及使用Stub类的set方法,将目标静态函数替换为桩函数。需要注意静态函数的可见性,可能需要修改源代码或在测试环境中进行条件编译,例如在测试时定义宏来覆盖静态函数的定义。 例如,被测文件中的静态函数: static int static_func(int a) { return a + 1; } 测试文件中,可能通过宏定义替换: #define static_func(a) (a + 2) 或者使用函数指针替换,但需要确保在测试构建过程中能够覆盖原函数。这可能需要在链接时替换相应的函数实现。 根据cpp-stub的文档,可能需要使用类似Stub::set(原函数, 桩函数)的方式,但由于静态函数的可见性问题,可能需要特殊处理。如果cpp-stub支持符号拦截或动态替换,这可能可行,否则可能需要调整代码结构,如在测试时包含源文件,并通过宏控制静态函数的定义。 最后,需要提醒用户注意静态函数打桩的局限性,建议在可能的情况下将静态函数改为非静态,或通过头文件暴露供测试使用,以便于打桩。</think>### 使用cpp-stub对C语言静态函数打桩方法 #### 核心思路 在C语言中,**静态函数**(static函数)的作用域仅限于当前文件,这导致直接打桩困难。cpp-stub通过**符号替换**和**动态拦截**实现打桩,需注意以下两点: 1. **静态函数可见性**:需在编译时将被测源文件包含到测试代码中(例如通过`#include "source.c"`),使静态函数在测试作用域内可见。 2. **打桩方法**:使用cpp-stub的`Stub`类替换目标函数地址。 #### 示例步骤 假设有以下被测代码 `calc.c`: ```c // calc.c static int add(int a, int b) { // 静态函数 return a + b; } int calculate() { return add(1, 2); // 调用静态函数 } ``` ##### 1. 测试代码中引入被测源文件 ```cpp // test_calc.cpp #include "cpp-stub/stub.h" #include "calc.c" // 关键!直接包含源文件以暴露静态函数 // 定义桩函数 int fake_add(int a, int b) { return 100; // 固定返回值 } TEST(TestCalc, StaticFuncStub) { Stub stub; // 替换静态函数add的地址 stub.set(add, fake_add); ASSERT_EQ(calculate(), 100); // 验证打桩后的结果 } ``` ##### 2. 编译时链接选项 需在编译时**忽略符号重复定义**警告(因为包含源文件可能导致重复符号): ```bash g++ test_calc.cpp -Icpp-stub/include -Wl,--allow-multiple-definition -o test ``` #### 注意事项 1. **副作用风险**:直接包含`.c`文件可能导致全局变量重复定义,建议将被测文件中的全局变量改为`static`限定。 2. **C++兼容性**:若被测代码是纯C,需在C++测试文件中用`extern "C"`包裹包含语句[^3]。 3. **线程安全**:cpp-stub的替换操作非线程安全,需避免多线程测试场景[^1]。 #### 替代方案(推荐) 若无法修改被测代码,可通过**预处理器宏**临时覆盖静态函数: ```cpp // test_calc.cpp #define add fake_add // 宏覆盖 int fake_add(int a, int b) { return 100; } #include "calc.c" // 在宏定义后包含源文件 TEST(TestCalc, MacroOverride) { ASSERT_EQ(calculate(), 100); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值