一、课程导论:什么是测试桩?为什么需要测试桩?

各位同学,咱们今天聊一个嵌入式开发里绕不开的话题——测试桩。

先问大家一个问题:你写了一个底层驱动函数,比如读取温度传感器的 temp_read(),但硬件还没焊好,或者传感器还没到货。你怎么验证这个函数对不对?

嗯,这时候就需要测试桩了。

1.1 什么是测试桩?

测试桩(Test Stub),说白了就是一个“假函数”。它长得跟真函数一模一样——函数名、参数、返回值类型都相同,但内部实现是模拟的,不干真正的硬件操作。

举个例子:

// 真实的驱动函数(硬件还没好)
int temp_read(uint8_t channel) {
    // 操作I2C寄存器,读取传感器数据
    return i2c_read_register(channel, TEMP_REG);
}

// 测试桩函数(先顶上)
int temp_read(uint8_t channel) {
    // 直接返回一个固定温度值
    return 25;  // 假装25度
}

你看,测试桩就是这样一个“替身演员”。它让上层代码能先跑起来,不用等底层硬件就绪。

核心要点:测试桩 ≠ 真实驱动。它只保证接口签名一致,内部逻辑是模拟的。

1.2 为什么需要测试桩?

我在项目中遇到过好几次这样的情况:硬件组说“板子下周回来”,但软件交付节点就在这周五。没有测试桩,整个集成测试就得干等。

具体来说,测试桩解决了这几个痛点:

  • 解耦依赖——模块A调模块B,B还没写好?用桩把B顶上,A先测。
  • 模拟异常——真实硬件很难触发某些错误场景,比如传感器断线、通信超时。桩函数可以轻松返回各种异常值。
  • 加速调试——每次烧录、复位、等待硬件响应,少说几十秒。用桩函数,毫秒级返回。
  • 回归测试——自动化测试环境里,不可能每次都接真实硬件。桩函数让测试可重复、可自动化。

个人经验:我习惯在项目启动时就定义好所有模块的接口头文件,然后给每个接口写一个“空桩”。这样团队并行开发时,每个人都能独立编译、独立测试。

1.3 集成测试与单元测试的区别

很多初学者会把这两个概念搞混。我刚开始做嵌入式时也犯过这个错——以为单元测试跑通了,集成测试就稳了。结果一联调,全是接口不匹配的问题。

咱们用一张表说清楚:

对比维度 单元测试 集成测试
测试对象 单个函数 / 单个模块 多个模块之间的交互
关注点 函数逻辑是否正确 接口协议、数据流、时序是否一致
依赖处理 大量使用测试桩隔离外部依赖 部分使用测试桩,部分用真实模块
执行环境 通常在本机或模拟器 目标硬件或硬件仿真环境
发现问题 算法错误、边界条件、逻辑分支 接口参数不匹配、数据格式错误、时序冲突
测试桩角色 替代所有外部依赖 替代尚未就绪或难以模拟的模块

说白了,单元测试是“单兵作战能力检验”,集成测试是“联合作战演习”。

举个例子你就明白了:

  • 单元测试:测 calc_crc() 这个函数,输入一串数据,看CRC算得对不对。这时候不需要硬件,纯算法验证。
  • 集成测试:测 uart_send_frame() 调用 calc_crc() 再调用 uart_write() 这个流程。要验证数据帧格式对不对、CRC是否附加在正确位置、UART发送时序是否满足协议要求。

避坑指南:我曾经在一个项目中,单元测试覆盖率做到了90%以上,但集成测试时发现通信协议里有一个字节序问题——模块A用大端,模块B用小端。单元测试各自为政,根本发现不了这种接口层面的问题。所以,集成测试不是单元测试的“升级版”,而是完全不同的测试维度。

1.4 测试桩在集成测试中的位置

咱们用一张图来看清楚测试桩在整个测试体系中的位置:

测试桩在集成测试中的位置 被测模块 (SUT) 模块接口层(函数调用 / 消息传递 / 共享内存) 真实模块 A 测试桩 B 测试桩 C 说明: • 被测模块通过接口层调用依赖模块 • 真实模块 A 已就绪,直接使用 • 模块 B、C 尚未就绪或难以模拟,用测试桩替代 • 测试桩保持接口一致,返回预设值或模拟行为

从这张图可以看到,集成测试时,被测模块(SUT)的真实依赖中,一部分用真实模块,一部分用测试桩。测试桩的作用就是“补齐缺失的拼图”,让整个集成测试链路能跑通。

1.5 什么时候该用测试桩?

我总结了几条经验法则:

  1. 硬件未就绪——传感器、执行器、通信外设还没到货或还没调试好。
  2. 环境不可控——比如要模拟GPS信号丢失、网络断连、电池电量低,真实环境很难复现。
  3. 测试速度要求——自动化测试每跑一次要等硬件响应几秒钟,用桩函数可以压到毫秒级。
  4. 安全考虑——有些操作(如擦除Flash、控制电机)在测试时不能真做,用桩函数“假装执行”。
  5. 并行开发——团队分工,你负责模块A,我负责模块B,互相用桩函数解耦。

一句话总结:测试桩是嵌入式集成测试的“万能替补”。它让测试不再依赖硬件就绪时间,让异常场景变得可控,让自动化测试成为可能。