You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试无返回值的Arduino代码?Platformio+VSCode环境求助

测试Arduino flashXTimes 函数的两种有效方案

针对你需要验证numberOfFlashes=3时函数执行3次闪烁的需求,以下是基于PlatformIO + Unity测试框架的两种可行方案,解决C++中无法直接替换函数指针的问题:


方案一:预处理宏替换(无需修改业务代码)

通过编译阶段的宏替换,将digitalWrite和delay替换为我们的Mock函数,无需改动原有业务逻辑。

1. 编写测试文件(test/test_flash.cpp)

#include <unity.h>
#include "flash.h"

// 记录Mock函数的调用信息
static uint32_t digitalWriteCallCount = 0;
static uint8_t lastUsedPin = 0;
static uint8_t lastOutputVal = 0;

// Mock digitalWrite:记录调用次数、引脚和电平
void digitalWriteMock(uint8_t pin, uint8_t val) {
    digitalWriteCallCount++;
    lastUsedPin = pin;
    lastOutputVal = val;
}

// Mock delay:测试时跳过实际等待
void delayMock(uint16_t ms) {}

// 宏替换:编译阶段将原函数指向Mock实现
#define digitalWrite digitalWriteMock
#define delay delayMock

// 测试前置操作:每次测试重置计数器
void setUp(void) {
    digitalWriteCallCount = 0;
    lastUsedPin = 0;
    lastOutputVal = 0;
}

// 测试后置清理
void tearDown(void) {}

// 核心测试用例:验证3次闪烁的调用逻辑
void test_flash_3_times(void) {
    const uint8_t TEST_LED_PIN = 13;
    flashXTimes(TEST_LED_PIN, 3, 100, 100);

    // 验证调用次数:3次闪烁 → 每次HIGH+LOW,共6次调用
    TEST_ASSERT_EQUAL(6, digitalWriteCallCount);
    // 验证最后一次调用是关闭LED(LOW电平)
    TEST_ASSERT_EQUAL(TEST_LED_PIN, lastUsedPin);
    TEST_ASSERT_EQUAL(LOW, lastOutputVal);
}

// 测试入口
int main(int argc, char **argv) {
    UNITY_BEGIN();
    RUN_TEST(test_flash_3_times);
    UNITY_END();
    return 0;
}

2. 配置PlatformIO(platformio.ini)

添加测试环境配置,确保Unity框架生效:

[env:your_board]
platform = atmelavr
board = uno  # 替换为你的目标开发板
framework = arduino
test_framework = unity
test_build_project_src = true  # 编译项目源代码用于测试

执行测试

在VSCode终端运行命令:

pio test -e your_board

方案二:依赖注入(可测试性优化方案)

修改业务函数,通过可选函数指针参数注入引脚控制和延迟逻辑,既保留原有功能,又提升测试灵活性。

1. 修改业务代码

flash.h:

#ifndef FLASH_H
#define FLASH_H

#include <Arduino.h>

// 定义函数指针类型
typedef void (*PinWriteFunc)(uint8_t, uint8_t);
typedef void (*DelayFunc)(uint16_t);

// 添加可选参数:默认使用Arduino原生函数
void flashXTimes(
    uint8_t LEDPin,
    uint16_t numberOfFlashes,
    uint16_t onDuration,
    uint16_t offDuration,
    PinWriteFunc pinWrite = digitalWrite,
    DelayFunc delayFunc = delay);

#endif

flash.cpp:

#include "flash.h"

void flashXTimes(
    uint8_t LEDPin,
    uint16_t numberOfFlashes,
    uint16_t onDuration,
    uint16_t offDuration,
    PinWriteFunc pinWrite,
    DelayFunc delayFunc)
{
  for (uint16_t i = 0; i < numberOfFlashes; i++)
  {
    pinWrite(LEDPin, HIGH);
    delayFunc(onDuration);
    pinWrite(LEDPin, LOW);
    delayFunc(offDuration);
  }
}

2. 编写测试文件(test/test_flash.cpp)

#include <unity.h>
#include "flash.h"

static uint32_t pinWriteCallCount = 0;
static uint8_t recordedPin = 0;
static uint8_t recordedVal = 0;

// Mock引脚写入函数
void mockPinWrite(uint8_t pin, uint8_t val) {
    pinWriteCallCount++;
    recordedPin = pin;
    recordedVal = val;
}

// Mock延迟函数
void mockDelay(uint16_t ms) {}

void setUp(void) {
    pinWriteCallCount = 0;
    recordedPin = 0;
    recordedVal = 0;
}

void tearDown(void) {}

void test_flash_3_times(void) {
    const uint8_t TEST_PIN = 13;
    // 测试时传入Mock函数
    flashXTimes(TEST_PIN, 3, 100, 100, mockPinWrite, mockDelay);

    TEST_ASSERT_EQUAL(6, pinWriteCallCount);
    TEST_ASSERT_EQUAL(TEST_PIN, recordedPin);
    TEST_ASSERT_EQUAL(LOW, recordedVal);
}

int main(int argc, char **argv) {
    UNITY_BEGIN();
    RUN_TEST(test_flash_3_times);
    UNITY_END();
    return 0;
}

额外测试扩展建议

如果需要验证电平变化的顺序,可以扩展Mock函数,用数组记录每次调用的电平值,再断言数组内容是否符合[HIGH, LOW, HIGH, LOW, HIGH, LOW]的预期。

内容的提问来源于stack exchange,提问作者Thomas J

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 19:43:18