第十章:TDD部署 —— Ceedling 环境的深度集成

1. 核心工具链安装(Windows 环境)

嵌入式开发者大多在 Windows 下工作,建议采用以下路径:

  1. Ruby : 下载安装 RubyInstaller with Devkit

    • 关键点 :安装后运行 ridk install,选择 1, 2, 3 来配置 MSYS2 开发环境。
  2. Ceedling: 打开终端(CMD 或 PowerShell):gem install ceedling

  3. GCC : 确保 gcc 在你的系统路径中。你可以用 MinGW,或者直接使用 STM32CubeIDE 自带的 arm-none-eabi-gcc(注:但在 PC 上跑单元测试,我们通常直接用 MinGW 的 gcc 编译成原生 exe)。

2. 将 Ceedling 植入 STM32 工程

假设你的工程名叫 MyProject,在根目录下运行:

ceedling new .

注意: 这里的 . 会在当前目录生成文件,而不是新建文件夹。它会生成:

  • project.yml:核心配置。

  • vendor/:里面包含了 Unity、CMock 和 Ceedling 的源码。这意味着你的项目是自包含的,别人拉下代码不需要再装 Ruby 也能跑(只要有 GCC 和 Ruby 环境)。

3. 深度定制 project.yml

这是部署最关键的一步。为了让 Ceedling 找到 STM32 的代码,你需要修改几个关键点:

A. 路径映射

STM32CubeIDE 的代码通常在 Core/Src,你得告诉 Ceedling:

:paths:

:test:

  • +:test/**

:source:

  • Core/Src/**

:include:

  • Core/Inc/**

  • Drivers/CMSIS/Device/ST/STM32G0xx/Include # 必须加上,否则找不到寄存器定义

B. CMock 自动化配置

这是让 Mock 变得好用的秘诀:

:cmock:

:mock_prefix: mock_

:when_no_prototypes: :warn

:enforce_strict_ordering: TRUE # 强制检查函数调用顺序,对协议栈测试非常有用

:plugins:

  • :ignore

  • :expect_any_args

  • :return_thru_ptr # 关键:用于 Mock 那些通过指针返回数据的函数(如 HAL_UART_Receive)

4. "硬件库"处理:Dummy Header 技巧

这是部署中最硬核的一点: STM32 的一些底层头文件包含了很多只有 ARM 编译器才认识的指令(如 __PACKED__IO)。原生 GCC 编译测试时会报错。

解决方案:test/support 文件夹下创建一个 stm32_fix.h,定义这些宏:

#ifndef STM32_FIX_H

#define STM32_FIX_H

#define __IO volatile

#define __PACKED

// 其他报错的宏统统在这里定义为空

#endif

然后在 project.yml:test_preprocess 里包含它。

5. 验证部署是否成功

在命令行输入:

ceedling summary

如果你能看到:

Project: MyProject

Test Files: 0

Total Tests: 0

说明你的环境已经原地起飞

附录:STM32 项目专属 project.yml 完整模板

这份配置文件针对 STM32 的目录结构和 C 语言特性进行了深度优化。建议将此内容保存在项目根目录。

--- Ceedling Project Configuration ---

:project:

:use_exceptions: FALSE

:use_test_preprocessor: TRUE # 开启预处理,解决复杂宏定义问题

:use_auxiliary_list: FALSE

:build_root: build # 所有的测试编译产物都在这里

:test_file_prefix: test_

:release_build:

:output: build/release/MyProject.out

:environment: \[\]

:extension:

:executable: .exe

:paths:

:test:

  • +:test/**

:source:

  • Core/Src/**

:include:

  • Core/Inc/**

  • Drivers/CMSIS/Device/ST/STM32G0xx/Include

  • Drivers/CMSIS/Include

  • test/support # 存放修复硬件宏定义的头文件

:defines:

模拟在 PC 环境下运行,定义一些 STM32 必要的宏

:common: &common_defines

  • STM32G031xx

  • UNIT_TEST

:test:

  • *common_defines

:test_preprocess:

  • *common_defines

:cmock:

:mock_prefix: mock_

:when_no_prototypes: :warn

:enforce_strict_ordering: TRUE

:plugins:

  • :ignore

  • :expect_any_args

  • :return_thru_ptr # 处理 HAL 库指针传参的关键插件

  • :callback # 处理中断回调测试的关键插件

:treat_as:

uint8: HEX8

uint16: HEX16

uint32: UINT32

int8: INT8

bool: UINT8

编译标志:针对 GCC 环境优化

:flags:

:test:

:compile:

:executable: gcc

:args:

  • -Wall

  • -Wno-address

  • -std=c99

  • -g

:plugins:

:load_paths:

  • "#{Ceedling.linker.tools_path}"

:enabled:

  • stdout_pretty_tests_report

  • module_generator

  • gcov # 开启覆盖率分析

总结:TDD 的核心

  • 隔离是第一生产力:无法测试是因为耦合太深。解耦不仅是为了测试,更是为了模块化。

  • 不要过度 Mock:只 Mock 你的被测对象(SUT)之外的东西。如果一个函数纯粹是逻辑运算,直接测,别 Mock。

  • 测试是最好的文档 :半年后你忘记了某个协议怎么解析,看一眼 test_protocol.c 里的 Expect 序列,你就全明白了。

相关推荐
QiLinkOS1 小时前
合肥气链科技有限公司创办与未来技术应用
c语言·数据结构·c++·人工智能·单片机·嵌入式硬件·算法
一只肥瘫瘫2 小时前
STM32 程序升级学习笔记:Bootloader、IAP 与串口升级流程
笔记·stm32·学习
国科安芯2 小时前
ASM232S电气特性与TIA/EIA-232-F及ITU V.28标准符合性深度分析
单片机·嵌入式硬件·算法·安全·架构
ACP广源盛139246256732 小时前
GSV2231@ACP#三屏扩展旗舰芯片,TRAE SOLO 多任务并行开发核心引擎
运维·网络·人工智能·嵌入式硬件·gpt·电脑·音视频
记帖2 小时前
STM32C542开发(2)----BOOT_SEL设置
stm32·stm32cubemx·stm32cubeide·stm32cubemx2·stm32c542cct6·boot_set·串口烧录
Rsingstarzengjx2 小时前
【stm32】尚硅谷基础篇笔记
笔记·stm32·嵌入式硬件
济6172 小时前
ROS开发专栏---基于 NAV2 实现仿真环境自主导航实验--适配Ubuntu 22.04
嵌入式硬件·嵌入式·ros2·机器人方向
JNX_SEMI11 小时前
EG2226 全桥驱动芯片技术解析:600V/1A 耐压、SSOP16 封装,助力逆变器与无刷电机驱动设计
单片机·嵌入式硬件·物联网
大卡片11 小时前
PWM控制原理
嵌入式硬件