这一章我们要从代码逻辑回归到工程落地。
很多开发者在尝试 TDD 时,最先放弃的地方不是写不出测试,而是面对 STM32CubeIDE 那堆复杂的文件夹结构、散乱的 .h 文件,以及 Ceedling 默认路径不匹配时感到崩溃。这一章,我们要把“杂乱的工程”理顺,让 Ceedling 像手术刀一样精准地接入你的项目。
8.1 典型的 STM32 工程痛点
STM32CubeIDE 生成的项目通常长这样:
-
Core/Src 和 Core/Inc(业务和初始化混在一起)
-
Drivers/STM32G0xx_HAL_Driver(庞大的官方库)
-
Middlewares/Third_Party/FreeRTOS(第三方中间件)
核心冲突: Ceedling 默认希望 src 和 test 在根目录。如果强行改变结构,CubeIDE 可能就不识别了。
8.2 解决方案:调教 project.yml
不要移动代码去适应工具,要让工具来适应代码。打开项目根目录下的 project.yml,这是 Ceedling 的大脑。
A. 多路径搜索配置
:paths:
:test:
– +:test/**
– -:test/support # 排除不需要的文件夹
:source:
– Core/Src/**
– Drivers/STM32G0xx_HAL_Driver/Src # 只有需要 mock 官方库时才加
:include:
– Core/Inc/**
– Drivers/STM32G0xx_HAL_Driver/Inc
– Drivers/CMSIS/Device/ST/STM32G0xx/Include
B. 编译器标志(定义宏)
STM32 代码里经常有 #ifdef STM32G031xx。如果不告诉 Ceedling,编译必报错。
:flags:
:test:
:compile:
:+:
– -DSTM32G031xx # 定义全局宏
– -DUNIT_TEST # 定义一个测试专用宏,用于屏蔽某些硬件代码
8.3 实战技巧:如何处理“大文件”?
STM32 的 main.c 往往集成了硬件初始化代码和你的业务逻辑。 TDD 准则:不要直接测试 main.c。
-
重构策略: 将业务逻辑抽离到 App_Main.c。
-
隔离手段: 在 main.c 的 while(1) 里只调用 App_Main_Loop()。这样你就可以只对 App_Main.c 进行单元测试,而完全跳过那些包含寄存器底层初始化的 main.c。
8.4 混合 C/C++ 的处理
如果你在 STM32 中使用了 C++(比如你之前提到的 CMake 项目),Ceedling 默认是用 gcc。
-
技巧: 在 project.yml 中将编译器改为 g++。
-
注意: 被测的 C 函数接口必须加上 extern "C",否则 Unity 会因为符号修饰(Name Mangling)找不到函数。
8.5 本章核心心法:持续集成(CI)的基石
重点强调:配置文件不是一劳永逸的,它是项目的“地图”。
测试覆盖率:在 project.yml 中开启 gcov 插件,看看你的测试是否覆盖了所有的 if/else。
自动化运行:因为有了这个配置文件,你可以轻松地在 GitHub Actions 或 GitLab CI 里跑测试。每当有人提交代码,服务器自动运行 ceedling test:all。如果进度条不是绿色的,禁止合并代码。
本章小结
这一章我们解决了“环境兼容性”的问题。已经能把 Ceedling 丝滑地集成进现有的 STM32 工程中,而不需要大幅改动原本的代码结构。


