我怎样才能unit testingArduino代码?

我想能够unit testing我的Arduino代码。 理想情况下,我将能够运行任何testing,而不必将代码上传到Arduino。 什么工具或图书馆可以帮助我呢?

在开发中有一个Arduino仿真器可能是有用的,但它似乎还没有准备好使用。

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

不要在Arduino设备或仿真器上运行unit testing

针对单片机设备/仿真器/基于Sim的testing的情况

unit testing的目的是testing你自己的代码的质量。 unit testing不应该testing你的控制之外的因素的function。

这样想:即使你要testingArduino库,微控制器硬件或者仿真器的function,这样的testing结果也绝对不可能告诉你任何有关你自己工作的质量。 因此,编写在设备(或仿真器)上运行的unit testing绝对没有价值

无论您是在考虑在设备上运行testing还是在仿真器上运行testing,您仍然在重复一个残酷的过程:

  1. 调整你的代码
  2. 编译并上传到Arduino设备
  3. 观察行为并猜测它是否正常工作。
  4. 重复

如果您希望通过串口获取诊断消息,但是您的项目本身需要使用Arduino唯一的硬件串行端口,则步骤3特别讨厌。 如果您认为SoftwareSerial库可能有所帮助,那么您应该知道这样做可能会中断任何需要精确计时的function,例如同时生成其他信号。 这个问题发生在我身上。

再一次,如果你要使用模拟器来testing你的草图,并且你的时间关键的例程完美运行,直到你上传到实际的Arduino,那么你将学习的唯一的一课是模拟器是有缺陷的 – 而且知道这仍然没有透露你自己的工作质量!

如果在设备或模拟器上testing是愚蠢的,我该怎么办?

您可能正在使用计算机来处理您的Arduino项目。 那台电脑的速度比单片机快数千倍 。 编写testing以在您的计算机上构build和运行

请记住,Arduino库和微控制器的行为应该被认为是正确的或者至less一致的不正确

当您的testing产生与您的期望相反的输出时,那么您的代码中可能存在一个已经过testing的缺陷。 如果你的testing结果与你的期望相符,但是当你把testing结果上传到Arduino上时,程序并不正确,那么你知道你的testing是基于不正确的假设,你可能有一个有缺陷的testing。 无论哪种情况,您都将获得关于您的下一个代码更改内容的真实见解。

如何在PC上构build和运行testing

你需要做的第一件事是确定你的testing目标 。 考虑你想要testing的代码的哪些部分,然后确保以这种方式构build你的程序,以便可以隔离分立的部分进行testing。

如果您要testing的部分调用任何Arduinofunction,则需要在testing程序中提供模拟replace。 这比看起来less得多的工作。 您的模型实际上不需要做任何事情,只是为您的testing提供可预测的input和输出。

您打算testing的任何自己的代码都需要存在于.pde草图以外的源文件中。 不要担心,即使在草图之外有一些源代码,草图仍然会被编译。 当您真正了解它时,应该在草图文件中定义比程序的正常入口点更多的地方。

剩下的就是编写实际的testing,然后用你最喜欢的C ++编译器编译它! 这可能是一个真实世界的例子最好的说明。

一个实际的工作例子

我在这里find的一个宠物项目有一些在PC上运行的简单testing。 对于这个答案的提交,我将回顾一下我如何嘲弄Arduino的一些库函数和我编写的testing这些模型的testing。 这与我之前所说的不testing其他人的代码并不矛盾,因为我是编写模型的人。 我想确定我的模型是正确的。

mock_arduino.cpp的来源,其中包含的代码复制了Arduino库提供的一些支持function:

#include <sys/timeb.h> #include "mock_arduino.h" timeb t_start; unsigned long millis() { timeb t_now; ftime(&t_now); return (t_now.time - t_start.time) * 1000 + (t_now.millitm - t_start.millitm); } void delay( unsigned long ms ) { unsigned long start = millis(); while(millis() - start < ms){} } void initialize_mock_arduino() { ftime(&t_start); } 

当我的代码将二进制数据写入硬件串行设备时,我使用以下模型生成可读输出。

fake_serial.h

 #include <iostream> class FakeSerial { public: void begin(unsigned long); void end(); size_t write(const unsigned char*, size_t); }; extern FakeSerial Serial; 

fake_serial.cpp

 #include <cstring> #include <iostream> #include <iomanip> #include "fake_serial.h" void FakeSerial::begin(unsigned long speed) { return; } void FakeSerial::end() { return; } size_t FakeSerial::write( const unsigned char buf[], size_t size ) { using namespace std; ios_base::fmtflags oldFlags = cout.flags(); streamsize oldPrec = cout.precision(); char oldFill = cout.fill(); cout << "Serial::write: "; cout << internal << setfill('0'); for( unsigned int i = 0; i < size; i++ ){ cout << setw(2) << hex << (unsigned int)buf[i] << " "; } cout << endl; cout.flags(oldFlags); cout.precision(oldPrec); cout.fill(oldFill); return size; } FakeSerial Serial; 

最后,实际的testing程序:

 #include "mock_arduino.h" using namespace std; void millis_test() { unsigned long start = millis(); cout << "millis() test start: " << start << endl; while( millis() - start < 10000 ) { cout << millis() << endl; sleep(1); } unsigned long end = millis(); cout << "End of test - duration: " << end - start << "ms" << endl; } void delay_test() { unsigned long start = millis(); cout << "delay() test start: " << start << endl; while( millis() - start < 10000 ) { cout << millis() << endl; delay(250); } unsigned long end = millis(); cout << "End of test - duration: " << end - start << "ms" << endl; } void run_tests() { millis_test(); delay_test(); } int main(int argc, char **argv){ initialize_mock_arduino(); run_tests(); } 

这篇文章已经够长了,所以请参考我在GitHub上的项目来看看更多的testing用例。 除了主人以外,我还在工作中进行工作,所以请检查那些分支以进行额外的testing。

我select编写自己的轻量级testing例程,但也可以使用更强大的unit testing框架,如CppUnit。

在Arduino没有任何预先存在的unit testing框架的情况下,我创build了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(); } 

我有相当多的成功unit testing我的PIC代码抽象硬件访问和嘲笑我的testing。

例如,我抽象PORTA

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

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

一旦硬件抽象经过testing,我很快就会发现,代码从testing平台到PIC首次运行。

更新:

我使用#include seam作为单元代码,#包括testing装置的C ++文件中的单元代码和目标代码的C文件。

作为一个例子,我想复用四个7段显示器,一个端口驱动段和第二个select显示。 显示代码通过SetSegmentData(char)SetDisplay(char)与显示器进行SetSegmentData(char) 。 我可以在我的C ++testing平台上嘲笑这些,并检查我是否能得到我期望的数据。 对于目标我使用#define这样我就可以直接分配而不需要函数调用的开销

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

Emulino似乎完美地完成了这项工作。

Emulino是Greg Hewgill的Arduino平台的模拟器。 ( 来源 )

GitHub仓库

simavr是一个使用avr-gcc的AVR 模拟器

它已经支持一些ATTiny和ATMega微控制器,而根据作者的说法,很容易添加更多。

在这个例子中,有一个Arduino仿真器simduino。 它支持运行Arduino引导程序,并可以通过Socat (一个修改后的Netcat )通过avrdude进行编程。

您可以使用我的项目PySimAVR以Python进行unit testing。 Arscons用于build模和simavr模拟。

例:

 from pysimavr.sim import ArduinoSim def test_atmega88(): mcu = 'atmega88' snippet = 'Serial.print("hello");' output = ArduinoSim(snippet=snippet, mcu=mcu, timespan=0.01).get_serial() assert output == 'hello' 

开始testing:

 $ nosetests pysimavr/examples/test_example.py pysimavr.examples.test_example.test_atmega88 ... ok 

这个程序允许自动运行几个Arduinounit testing。 testing过程在PC上启动,但是testing在实际的Arduino硬件上运行。 一组unit testing通常用于testing一个Arduino库。 (这个

Arduino论坛: http : //arduino.cc/forum/index.php? topic= 140027.0

GitHub项目页面: http : //jeroendoggen.github.com/Arduino-TestSuite

Python程序包索引中的页面: http : //pypi.python.org/pypi/arduino_testsuite

unit testing是用“Arduinounit testing库”编写的: http : //code.google.com/p/arduinounit

为每组unit testing执行以下步骤:

  • 阅读configuration文件以找出要运行的testing
  • 该脚本编译并上传包含unit testing代码的Arduino草图。
  • unit testing在Arduino板上运行。
  • testing结果通过串口打印并通过Python脚本进行分析。
  • 该脚本开始下一个testing,对configuration文件中请求的所有testing重复上述步骤。
  • 该脚本打印一个摘要,显示完整testing套件中所有失败/通过testing的概览。

我不知道任何可以testingArduino代码的平台。

但是,有Fritzing平台,您可以使用它来模拟硬件,然后导出PCB图表和内容。

值得检查。

我们使用Arduino板进行大型科学实验中的数据采集。 随后,我们必须支持不同实现的几个Arduino板卡。 我编写了Python实用程序,在unit testing期间dynamic加载Arduinohex图像。 以下链接中的代码通过configuration文件支持Windows和Mac OS X. 要找出Arduino IDE放置的hex图像的位置,请在按下构build(播放)button之前按Shift键。 点击shift键,find你的avrdude(命令行上传工具)在系统/版本的Arduino上的位置。 或者,您可以查看包含的configuration文件并使用您的安装位置(目前在Arduino 0020上)。

http://github.com/toddstavish/Python-Arduino-Unit-Testing

保持硬件特定的代码与其余部分分离或抽象,以便在任何有良好工具且最熟悉的平台上testing和debugging更大的“rest”。

基本上,尽可能多地从尽可能多的已知工作构build块中构build尽可能多的最终代码。 剩下的硬件特定的工作将变得更加容易和快速。 您可以通过使用现有的仿真器和/或自己模拟设备来完成。 然后,当然,你需要以某种方式testing真实的东西。 根据具体情况,这可能是也可能不是很好的自动化(即谁或什么将button和提供其他的input?谁或什么将观察和解释各种指标和产出?)。

编写Arduino代码时使用了Searduino 。 Searduino是一个Arduino模拟器和一个开发环境(Makefiles,C代码…),可以很容易地使用你最喜欢的编辑器在C / C ++中进行攻击。 您可以导入Arduino草图并在模拟器中运行它们。

Searduino 0.8的屏幕截图: http ://searduino.files.wordpress.com/2014/01/jearduino-0-8.png

Searduino 0.9将会被释放,一旦最后的testing完成,video将被logging下来….在一两天内。

在模拟器上的testing并不被认为是真正的testing,但它确实帮助我find愚蠢/逻辑错误(忘记做pinMode(xx, OUTPUT)等等)。

顺便说一句:我是开发Searduino的人之一。

James W. Grenning写了很棒的书,这个是关于embedded式C的embedded式C代码testing驱动开发的unit testing。

有一个名为ncore的项目,它为Arduino提供本地核心。 并允许您编写testingArduino代码。

从项目描述

本地核心允许您在PC上编译和运行Arduino草图,一般不做修改。 它提供了标准的Arduinofunction的本地版本,以及一个命令行intestiter给你的草图input,通常来自硬件本身。

另外在“我需要使用它”部分

如果你想build立testing,你需要从http://cxxtest.tigris.org获得; cxxtest。 NCORE已经用cxxtest 3.10.1进行了testing。

你可以使用emulare – 你可以在图上拖放一个微控制器,并在Eclipse中运行你的代码。 网站上的文档告诉你如何设置它。

使用带有Arduino库的Proteus VSM来debugging或testing代码。

在获取代码之前,这是一个最佳实践,但要确保时间安排,因为模拟在板上运行时不会实时运行。

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

如果你想在单片机外testing代码(在桌面上),检查libcheck: https ://libcheck.github.io/check/

我用它来testing我自己的embedded式代码几次。 这是非常强大的框架。