第五章:如何对 HAL 库本身进行单元测试?

这一章我们将深入嵌入式开发最"底层"的阵地。很多开发者会问:"逻辑层可以隔离,但我直接配置 STM32 寄存器或调用 HAL 库的代码,怎么测?"

这一章,我们要处理那些无法回避的底层调用,并引入 TDD 的进阶手段:Fake(伪函数)

5.1 为什么 Mock 有时不够用?

对于 HAL_GPIO_WritePin 这种简单的一对一调用,Expect 很好用。但如果你在写一个 I2C 扫描逻辑,代码里涉及大量的循环和连续调用,写几十个 Expect 会让测试脚本极其冗长且难以维护。

此时,我们需要 Fake(伪造实现):我们写一个功能简单的函数,替换掉真正的 HAL 函数,并让它记录下所有的动作。

5.2 实战:测试一个 I2C 设备探测器

需求: 扫描 I2C 总线上地址从 1127 的设备,并返回第一个响应的地址。

底层接口 (stm32g0xx_hal.h)HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout);

5.3 编写测试:使用 Stub(存根/钩子)

Ceedling 的 CMock 支持 StubWithCallback。我们可以定义一个自定义函数,让 CMock 在被调用时运行我们的代码。

#include "unity.h"

#include "mock_stm32g0xx_hal_i2c.h" // 模拟 HAL 库

#include "I2C_Scanner.h"

// 这是一个伪造的 I2C 响应函数

// 我们模拟只有地址 0x50 的设备有响应

HAL_StatusTypeDef my_I2C_Stub(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout, int num_calls) {

if (DevAddress == (0x50 << 1)) {

return HAL_OK;

}

return HAL_ERROR;

}

void test_Scanner_Should_Return0x50_WhenDeviceFound(void) {

// 告诉 CMock:当 HAL_I2C_IsDeviceReady 被调用时,别管 Expect 了,去运行 my_I2C_Stub

HAL_I2C_IsDeviceReady_StubWithCallback(my_I2C_Stub);

uint8_t found_addr = I2C_Scanner_ScanFirst();

TEST_ASSERT_EQUAL_HEX8(0x50, found_addr);

}

5.4 进阶技巧:针对 STM32 寄存器的"影子内存"

如果你在写非常底层的代码(如手写寄存器驱动),可以利用一种叫 Shadow Register 的技术:

  1. 在测试环境中,定义一组全局变量(如 uint32_t V_GPIOA_ODR)。

  2. 在头文件中通过宏定义将 GPIOA->ODR 指向这个变量。

  3. 测试方法 :调用你的驱动函数,然后断言 TEST_ASSERT_EQUAL_HEX32(0x01, V_GPIOA_ODR)

这让你可以验证驱动程序是否真的改写了对应的寄存器位。

5.5 本章核心心法:什么时候该停止测试?

请注意:

  • 不要去测试 ST 官方的 HAL 库 :我们默认 HAL_GPIO_WritePin 是工作的。

  • 测试的是"调用行为":我们要测的是"当传感器数据溢出时,驱动是否正确调用了复位寄存器"。

  • 避免过度 Mock:如果你的测试代码比业务代码长 5 倍,说明你的函数拆分得还不够细。

本章小结

我们掌握了 StubCallback,这让我们能够处理复杂的循环调用和底层库交互。至此,你已经完成了从业务逻辑到硬件驱动的全路径 TDD 覆盖。

相关推荐
宵时待雨9 分钟前
优选算法专题9:哈希表
数据结构·算法·散列表
三84416 分钟前
BGP/GRE练习
网络
gwf21619 分钟前
磨损均衡算法(Wear Leveling)——SSD如何让每块闪存“公平退休“?
运维·数据库·人工智能·python·嵌入式硬件·算法·智能硬件
noipp37 分钟前
推荐题目:洛谷 P6231 [JSOI2013] 公交系统
c语言·数据结构·c++·算法·游戏·洛谷·luogu
念恒123061 小时前
网络基础
linux·网络·c++
白山云北诗1 小时前
漏洞扫描+渗透测试:从资产摸底到风险验证,完成二次安全收口
网络·安全·web安全·渗透测试·漏洞扫描·ddos防护·cc防护
zlinear数据采集卡2 小时前
从“脏信号”到“纳伏级纯净”:硬核拆解DABL7606的多级抗混叠滤波与24位过采样算法
arm开发·科技·嵌入式硬件·fpga开发·开源
爱研究的小梁2 小时前
乾元通聚合路由及管理平台支持全面适配信创
网络·人工智能·信息与通信
放学校门口见2 小时前
vscode部署stm32开发调试环境
ide·vscode·stm32