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

ESP8266 Arduino平台C++类单元测试方案咨询

ESP8266 Arduino平台C++类的单元测试方案

当然可以搞定!针对ESP8266 Arduino平台上的C类做单元测试,确实得绕开标准C测试库的一些限制(比如Arduino不支持异常),不过有几个非常贴合你需求的方案,我来给你拆解一下:

1. 轻量级断言与测试结构:用AUnit库

AUnit是专门为Arduino生态设计的单元测试库,完美适配ESP8266,完全不需要依赖异常,还支持你需要的测试套件、测试用例结构,以及丰富的断言功能。

上手步骤:

  • 在Arduino库管理器里搜索并安装AUnit
  • 编写测试代码的示例:
#include <AUnit.h>
// 引入你要测试的类
#include "TemperatureSensor.h"

// 定义测试套件和测试用例
test(TemperatureSensorTests, testReadTemperature) {
  TemperatureSensor sensor;
  // 断言读取的温度在合理范围内
  assertBetween(sensor.read(), 20.0, 30.0);
  // 断言传感器初始化状态正确
  assertEqual(sensor.isInitialized(), true);
}

test(TemperatureSensorTests, testCalibration) {
  TemperatureSensor sensor;
  sensor.calibrate(25.0);
  assertEqual(sensor.read(), 25.0);
}

void setup() {
  Serial.begin(115200);
  // 启动测试运行器
  aunit::TestRunner::run();
}

void loop() {
  // 测试运行器的循环逻辑,用于处理异步测试(如果需要)
  aunit::TestRunner::loop();
}
  • 上传代码到ESP8266后,打开串口监视器就能看到测试结果,包括每个用例的通过/失败状态。

AUnit支持setup()/teardown()方法,你可以在每个测试用例前后做初始化或清理操作,非常方便。

2. 方法调用验证的模拟功能

针对模拟需求,有两个实用方向:

手动Mock(适合简单场景)

如果你的类依赖其他组件(比如传感器、外设驱动),可以自己写一个Mock类来记录方法调用的次数、参数,然后在测试里验证。示例如下:

// 模拟一个串口输出类
class MockSerial {
public:
  int writeCount = 0;
  String lastMessage;

  size_t write(const char* msg) {
    writeCount++;
    lastMessage = String(msg);
    return strlen(msg);
  }
};

// 测试依赖串口的Logger类
test(LoggerTests, testLogMessage) {
  MockSerial mockSerial;
  Logger logger(&mockSerial);
  
  logger.log("Hello Test");
  
  // 验证write方法被调用了1次
  assertEqual(mockSerial.writeCount, 1);
  // 验证输出的消息正确
  assertEqual(mockSerial.lastMessage, "Hello Test");
}

这种方式简单直接,不需要额外依赖库,适合小项目或简单的依赖模拟。

使用FakeIt库(适合复杂模拟)

FakeIt是一个轻量级的C++ Mocking库,可以配置成不依赖异常,完美适配ESP8266。你需要把FakeIt的源码加入到项目中,然后在ESP8266的编译选项里添加-fno-exceptions(关闭异常支持)。

示例代码:

#include "FakeIt.h"
// 定义你要模拟的接口
#include "IButton.h"
// 引入依赖该接口的类
#include "ButtonHandler.h"

using namespace fakeit;

test(ButtonHandlerTests, testButtonPress) {
  // 创建接口的Mock对象
  Mock<IButton> mockButton;
  
  // 设置Mock的行为:当调用isPressed()时返回true
  When(Method(mockButton, isPressed)).Return(true);
  
  // 把Mock对象注入到ButtonHandler中
  ButtonHandler handler(mockButton.get());
  
  // 执行测试逻辑
  bool result = handler.checkButtonState();
  
  // 验证isPressed()方法被调用了一次
  Verify(Method(mockButton, isPressed)).Once();
  // 断言结果正确
  assertEqual(result, true);
}

FakeIt支持更复杂的Mock场景,比如指定参数匹配、多次调用的不同返回值等,适合有复杂依赖的类测试。

3. 离线测试(推荐方案)

如果你的类核心逻辑和Arduino硬件API(比如digitalRead、Serial)耦合度不高,强烈建议把核心逻辑抽离成不依赖Arduino环境的纯C++类,然后在标准C++环境(比如VSCode+GCC、CLion)里用成熟的测试库测试,比如:

  • Catch2:可以通过配置关闭异常支持,语法简洁,支持测试套件和丰富断言
  • Google Test:同样可以关闭异常,功能强大,适合大型项目

比如,你可以把硬件操作抽象成接口,核心类依赖接口而不是具体的Arduino实现:

// 抽象硬件接口(纯C++,无Arduino依赖)
class ILedDriver {
public:
  virtual void turnOn() = 0;
  virtual void turnOff() = 0;
};

// 核心逻辑类(依赖接口)
class LedController {
private:
  ILedDriver* _driver;
public:
  LedController(ILedDriver* driver) : _driver(driver) {}
  void toggle() {
    // 核心逻辑...
  }
};

// Arduino环境下的具体实现
class ArduinoLedDriver : public ILedDriver {
private:
  int _pin;
public:
  ArduinoLedDriver(int pin) : _pin(pin) {
    pinMode(pin, OUTPUT);
  }
  void turnOn() override {
    digitalWrite(_pin, HIGH);
  }
  void turnOff() override {
    digitalWrite(_pin, LOW);
  }
};

这样你可以在标准C++环境里用Mock框架测试LedController的核心逻辑,测试效率更高,还能利用IDE的调试功能,之后再把测试好的代码放回Arduino项目中对接硬件实现。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:42:53