嵌入式 TDD:在硬件上进行单元测试

Evek Golden Lv4

“我的代码只有刷到板子上才能跑。” —— 这句话阻碍了无数嵌入式项目的自动化测试进程。每改一行代码都要烧录、重启、按按钮,这种开发效率极其低下。

TDD (Test-Driven Development) 并不是纯软件的专利。

1. 为什么嵌入式难测?

核心痛点在于硬件依赖。你的代码里充斥着 #include "stm32f4xx.h",充斥着对外设寄存器的直接读写。这导致你的代码无法在 PC (x86) 上编译运行。

2. 解耦:Mock 掉硬件

要让代码可测,首先要分离业务逻辑硬件驱动

  • Bad Code:

    1
    2
    3
    4
    void LED_Blink(void) {
    GPIOB->ODR ^= (1 << 5); // 直接操作硬件,锁死了平台
    HAL_Delay(100);
    }
  • Testable Code:

    1
    2
    3
    4
    5
    // 注入硬件操作接口
    void LED_Blink(LedDriver_t *driver) {
    driver->toggle(LED_PIN_5);
    driver->delay_ms(100);
    }

在 PC 上跑测试时,我们可以注入一个“假”的 driver(Mock Object),在这个假 driver 里记录函数是否被调用。

3. 测试框架:Unity + CMock

ThrowTheSwitch 组织提供的 Unity 和 CMock 是嵌入式领域的神器。

  • Unity:极简的 C 语言单元测试框架。
    1
    2
    3
    4
    TEST(LedControl, BlinkShouldTogglePin) {
    LED_Blink();
    TEST_ASSERT_EQUAL_HEX(0x20, MockGPIO_GetLastState());
    }
  • CMock:自动扫描你的头文件 (led_driver.h),自动生成 Mock 实现 (Mockled_driver.c)。
    • 你可以在测试代码中设定期望:LedDriver_Toggle_ExpectAndReturn(LED_PIN_5, OK);
    • 如果代码运行时没有按期望调用该函数,测试直接失败。

4. 持续集成 (CI)

一旦代码能在 PC 上编译运行,就可以接入 GitLab CI 或 GitHub Actions。
每次提交代码,服务器自动运行所有用例:

  1. 编译(GCC for x86)。
  2. 运行单元测试。
  3. 生成覆盖率报告 (gcov/lcov)。
  4. (可选)交叉编译通过(GCC for ARM)。

总结

不要等到量产前一天才发现 Bug。TDD 虽然前期编写测试代码很“烦”,但它能给你重构代码的底气,和睡个安稳觉的权利。

  • Title: 嵌入式 TDD:在硬件上进行单元测试
  • Author: Evek Golden
  • Created at : 2025-01-05 23:33:00
  • Updated at : 2026-06-12 08:57:02
  • Link: https://blog.cocodemo.uno/posts/tdd8j2w/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments