gpt4 book ai didi

unit-testing - 如何对Arduino代码进行单元测试?

转载 作者:太空宇宙 更新时间:2023-11-04 14:25:10 25 4
gpt4 key购买 nike

我希望能够对我的Arduino代码进行单元测试。理想情况下,我可以运行任何测试,而不必将代码上传到Arduino。哪些工具或库可以帮助我解决此问题?

有一个Arduino emulator in development可能有用,但似乎尚未准备好使用。

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

最佳答案

不要在Arduino设备或仿真器上运行单元测试

针对微控制器设备/仿真器/基于Sim的测试的案例


  关于单元测试的含义有很多讨论,但我不是
  真的想在这里对此争论。这个帖子不是
  告诉您避免对最终目标进行所有实际测试
  硬件。我想提出一个关于优化您的观点
  通过消除目标硬件的开发反馈周期
  您最平凡和频繁的测试。假定被测单位
  比整个项目要小得多。


单元测试的目的是测试您自己的代码的质量。单元测试通常不应测试无法控制的因素的功能。

这样考虑:即使您要测试Arduino库,微控制器硬件或仿真器的功能,此类测试结果也绝对不可能告诉您有关您自己工作质量的任何信息。因此,编写不在目标设备(或仿真器)上运行的单元测试具有更大的价值和效率。

在目标硬件上进行频繁测试的周期非常缓慢:


调整您的代码
编译并上传到Arduino设备
观察行为并猜测您的代码是否正在按预期进行
重复


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

同样,如果您要使用仿真器测试草图,并且时间紧迫的例程可以完美运行,直到将其上传到实际的Arduino,那么您将要学习的唯一一课就是仿真器存在缺陷-并且仍然需要了解这一点没有透露您自己的工作质量。

如果在设备或仿真器上进行测试很愚蠢,我该怎么办?

您可能正在使用计算机来处理Arduino项目。那台计算机比微控制器快几个数量级。编写测试以在计算机上构建并运行。

请记住,应该假定Arduino库和微控制器的行为是正确的,或者至少始终是错误的。

当您的测试产生的输出与您的预期相反时,则可能表明您的测试代码存在缺陷。如果您的测试输出符合您的期望,但是将该程序上载到Arduino时该程序无法正常运行,那么您就知道您的测试基于错误的假设,并且您的测试可能有缺陷。无论哪种情况,您都将获得真正的见解,了解下一次代码更改应该是什么。您的反馈质量从“东西坏了”提高到“此特定代码已坏”。

如何在PC上构建和运行测试

您需要做的第一件事就是确定您的测试目标。考虑一下要测试自己代码中的哪些部分,然后确保以可以隔离离散部分进行测试的方式构造程序。

如果要测试的部件调用了任何Arduino功能,则需要在测试程序中提供模型替代品。这比看起来要少得多的工作。除了为测试提供可预测的输入和输出外,您的模型不需要执行任何操作。

您打算测试的任何您自己的代码都必须存在于.pde草图以外的源文件中。不用担心,即使草图外有一些源代码,您的草图仍然可以编译。当您真正了解它时,应该在草图文件中定义仅比程序的正常入口点多的东西。

剩下的就是编写实际的测试,然后使用您最喜欢的C ++编译器进行编译!最好用一个真实的例子来说明。

一个实际的工作例子

我发现的一个宠物项目here具有一些在PC上运行的简单测试。对于此答案提交,我将介绍如何模拟Arduino库功能以及为测试这些模型而编写的测试。这与我之前所说的不测试其他人的代码并不矛盾,因为我是编写模型的人。我想非常确定我的模型是正确的。

mock_arduino.cpp的源代码,其中包含与Arduino库提供的某些支持功能重复的代码:



#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;


最后是实际的测试程序:

#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();
}


这篇文章足够长,所以请参考 my project on GitHub来了解更多的测试案例。我将正在进行的作品保存在master以外的分支中,因此也请检查这些分支以进行额外的测试。

我选择编写自己的轻量级测试例程,但也可以使用更强大的单元测试框架,例如CppUnit。

关于unit-testing - 如何对Arduino代码进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4541077/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com