我希望能够单元测试我的Arduino代码。理想情况下,我可以运行任何测试,而无需将代码上传到Arduino。哪些工具或库可以帮助我做到这一点?

目前正在开发的Arduino模拟器可能很有用,但似乎还没有准备好使用。

Atmel的AVR Studio包含一个芯片模拟器,可能很有用,但我不知道如何将它与Arduino IDE结合使用。


当前回答

如果您有兴趣运行INO草图并检查串行输出,我在我的Arduino NMEA校验和项目中有一个工作实现。

下面的脚本获取该文件,并使用Arduino CLI将其编译为HEX文件,然后加载到SimAVR中,SimAVR对其进行计算并打印串行输出。由于所有Arduino程序都永远运行,没有真正杀死自己的选项(exit(0)不起作用),我让草图运行几秒钟,然后将捕获的输出与预期的输出进行区分。

下载并提取Arduino CLI(在本例中,版本为0.5.0 -撰写本文时的最新版本):

curl -L https://github.com/arduino/arduino-cli/releases/download/0.5.0/arduino-cli_0.5.0_Linux_64bit.tar.gz -o arduino-cli.tar.gz
tar -xvzf arduino-cli.tar.gz

现在你可以更新索引并安装相应的核心:

./arduino-cli core update-index
./arduino-cli core install arduino:avr

假设你的草图名为nmea-checksum。ino,获取ELF和HEX,运行:

./arduino-cli compile -b arduino:avr:uno nmea-checksum.ino

接下来,SimAVR运行HEX(或ELF) -我从源代码构建,因为最新版本不适合我:

sudo apt-get update
sudo apt-get install -y build-essential libelf-dev avr-libc gcc-avr freeglut3-dev libncurses5-dev pkg-config
git clone https://github.com/buserror/simavr.git
cd simavr
make

成功的编译将为您提供simavr/run_avr,您可以使用它来运行草图。就像我说的,暂停它,否则它永远不会终止:

cd simavr
timeout 10 ./run_avr -m atmega168 -f 16000000 ../../nmea-checksum.ino.arduino.avr.uno.elf &> nmea-checksum.ino.clog || true

生成的文件将有ANSI颜色代码控制字符包装串行输出,以摆脱这些:

cat nmea-checksum.ino.clog | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" > nmea-checksum.ino.log
cat nmea-checksum.ino.log

现在你所需要做的就是将这个文件与一个已知的好文件进行比较:

diff nmea-checksum.ino.log ../../nmea-checksum.ino.test

如果没有差异,diff将以代码0退出,否则脚本将失败。

其他回答

在没有Arduino单元测试框架的情况下,我创建了ArduinoUnit。下面是一个简单的Arduino草图,展示了它的使用:

#include <ArduinoUnit.h>

// Create test suite
TestSuite suite;

void setup() {
    Serial.begin(9600);    
}

// Create a test called 'addition' in the test suite
test(addition) {
    assertEquals(3, 1 + 2);
}

void loop() {
    // Run test suite, printing results to the serial port
    suite.run();
}

试试Autodesk电路模拟器。它允许用许多其他硬件组件测试Arduino代码和电路。

使用带有Arduino库的Proteus VSM来调试代码或测试它。

这是在将代码安装到板上之前的最佳实践,但要确保计时,因为模拟不会在板上运行时实时运行。

你可以使用仿真——你可以在图表上拖放微控制器,然后在Eclipse中运行你的代码。网站上的文档会告诉你如何设置。

通过抽象出硬件访问并在测试中模拟它,我在单元测试PIC代码方面取得了相当大的成功。

例如,我用抽象PORTA

#define SetPortA(v) {PORTA = v;}

然后SetPortA可以很容易地模拟,而不需要在PIC版本中添加开销代码。

一旦硬件抽象被测试了一段时间,我很快发现代码通常会从测试平台到PIC,并且第一次就能工作。

更新:

对于单元代码,我使用#include seam,对于测试平台,在c++文件中使用#include单元代码,对于目标代码使用C文件。

作为一个例子,我想复用四个7段显示器,一个端口驱动段和第二个选择显示。显示代码通过SetSegmentData(char)和SetDisplay(char)与显示进行接口。我可以在我的c++测试平台中模拟这些,并检查我是否得到了我期望的数据。对于目标,我使用#define,这样就可以直接赋值,而不需要调用函数

#define SetSegmentData(x) {PORTA = x;}