Arduinoコードを単体テストできるようにしたいです。理想的には、Arduinoにコードをアップロードすることなく、テストを実行できます。これに役立つツールまたはライブラリは何ですか?
開発中のArduinoエミュレータ がありますが、これは便利かもしれませんが、まだ使用できるようには見えません。
AVR Studio Atmelには便利なチップシミュレータが含まれていますが、Arduino IDEと組み合わせて使用する方法がわかりません。
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();
}
unit test の意味については多くの議論がありますが、私はここでそれについて議論しようとはしていません。この投稿は、 not 究極のターゲットハードウェアでの all 実用的なテストを回避するよう指示しています。最も日常的で頻繁なテストからターゲットハードウェアを削除することにより、開発フィードバックサイクルを最適化することを強調しようとしています。テスト対象のユニットは、プロジェクト全体よりもはるかに小さいと想定されています。
単体テストの目的は、独自のコードの品質をテストすることです。通常、単体テストでは、制御できない要因の機能をテストしないでください。
このように考えてください:Arduinoライブラリ、マイクロコントローラーハードウェア、またはエミュレーターの機能をテストする場合でも、そのようなテスト結果について何かを伝えることは絶対に不可能です自分の仕事の質。したがって、ターゲットデバイス(またはエミュレーター)で実行されない単体テストを記述する方がはるかに価値があり、効率的です。
ターゲットハードウェアでの頻繁なテストには、非常に遅いサイクルがあります。
ステップ3は、シリアルポート経由で診断メッセージを受け取ることを期待しているが、プロジェクト自体がArduinoの唯一のハードウェアシリアルポートを使用する必要がある場合、特に厄介です。 SoftwareSerialライブラリーが役立つ可能性があると考えている場合は、そうすることで、同時に他の信号を生成するなどの正確なタイミングを必要とする機能が混乱する可能性があることを知っておく必要があります。この問題は私に起こりました。
繰り返しになりますが、エミュレータを使用してスケッチをテストし、実際のArduinoにアップロードするまでタイムクリティカルなルーチンが完全に実行された場合、学習する唯一のレッスンはエミュレータに欠陥があるということです。 nothing が自分の品質作品について明らかにします。
おそらくコンピューターを使用してArduinoプロジェクトで作業しているのでしょう。そのコンピューターは、マイクロコントローラーよりも桁違いに高速です。ビルドするテストを作成し、コンピューター上で実行します。
Arduinoライブラリとマイクロコントローラーの動作は、が正しいか、少なくとも consistently wrongであると仮定する必要があります。
テストが期待に反した出力を生成する場合、テストされたコードに欠陥がある可能性があります。テスト出力が期待どおりであるが、Arduinoにアップロードしたときにプログラムが正しく動作しない場合、テストが誤った仮定に基づいており、テストに欠陥がある可能性が高いことがわかります。どちらの場合でも、次のコード変更がどうあるべきかについての本当の洞察が与えられます。フィードバックの品質が「 something is broken」から「this specific code is壊れた"。
最初に行う必要があるのは、テストの目標を特定するです。 独自のコードのどの部分をテストしたいかを考えてから、個別の部分を分離できるようにプログラムを構築してください。 検査用の。
テストするパーツがArduinoの関数を呼び出す場合、テストプログラムでモックアップの置き換えを提供する必要があります。これは見かけよりもはるかに少ない作業です。モックアップは、テストのために予測可能な入力と出力を提供する以外、実際に何もする必要はありません。
テストする予定の独自のコードは、.pdeスケッチ以外のソースファイルに存在する必要があります。心配しないでください。スケッチは、スケッチの外部にあるソースコードを使用してもコンパイルされます。実際に作業を終えたら、プログラムの通常のエントリポイントをスケッチファイルで定義する必要があります。
あとは、実際のテストを作成してから、お気に入りのC++コンパイラを使用してコンパイルするだけです!これはおそらく、実世界の例を使用して最もよく説明されています。
私のペットプロジェクトの1つ here には、PCで実行される簡単なテストがいくつかあります。この回答を提出するために、Arduinoライブラリ関数の一部のモックアップ方法と、それらのモックアップをテストするために作成したテストについて説明します。これは、私がモックアップを書いたので、他の人のコードをテストしないことについて前に言ったことに反していません。私は自分のモックアップが正しいことを非常に確実にしたかったのです。
Arduinoライブラリによって提供されるいくつかのサポート機能を複製するコードを含むmock_arduino.cppのソース:
#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();
}
この投稿は十分に長いので、 GitHubでの私のプロジェクト を参照して、実際のテストケースを確認してください。私は進行中の作品をマスター以外のブランチで保管しているので、追加のテストについてもそれらのブランチをチェックしてください。
独自の軽量テストルーチンを作成することを選択しましたが、CppUnitのようなより堅牢な単体テストフレームワークも利用できます。
ハードウェアアクセスを抽象化し、テストでモックすることで、PICコードの単体テストをかなり成功させています。
たとえば、次のようにPORTAを抽象化します
_#define SetPortA(v) {PORTA = v;}
_
PICバージョンにオーバーヘッドコードを追加することなく、SetPortAを簡単にモックできます。
ハードウェアの抽象化がしばらくテストされると、コードがテスト装置からPICに移動し、最初に機能することがすぐにわかります。
更新:
ユニットコードには#includeシームを使用し、テストリグにはC++ファイルにユニットコードを、ターゲットコードにはCファイルを使用します。
例として、4つの7セグメントディスプレイを多重化し、1つのポートでセグメントを駆動し、もう1つのポートでディスプレイを選択します。ディスプレイコードは、SetSegmentData(char)
およびSetDisplay(char)
を介してディスプレイとインターフェイスします。これらをC++テストリグでモックし、期待するデータが得られることを確認できます。ターゲットには_#define
_を使用して、関数呼び出しのオーバーヘッドなしで直接割り当てを取得します
_#define SetSegmentData(x) {PORTA = x;}
_
Python私のプロジェクトでは、 PySimAVR 。Arsconsを使用して単体テストを行うことができますシミュレーション用の建物および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'
テストを開始:
$ nosetests pysimavr/examples/test_example.py
pysimavr.examples.test_example.test_atmega88 ... ok
このプログラムは、いくつかのArduino単体テストの自動実行を可能にします。テストプロセスはPCで開始されますが、テストは実際のArduinoハードウェアで実行されます。通常、1つのユニットテストセットを使用して、1つのArduinoライブラリをテストします。 (この
Arduinoフォーラム: http://arduino.cc/forum/index.php?topic=140027.
GitHubプロジェクトページ: http://jeroendoggen.github.com/Arduino-TestSuite
Pythonパッケージインデックス: http://pypi.python.org/pypi/arduino_testsuite のページ
ユニットテストは、「Arduinoユニットテストライブラリ」で記述されています。 http://code.google.com/p/arduinounit
次の手順は、ユニットテストの各セットに対して実行されます。
Arduinoコードをテストできるプラットフォームは知りません。
ただし、 Fritzing プラットフォームがあり、これを使用してハードウェアをモデル化し、後でエクスポートすることができますPCB図とか。
価値があるチェック。
大規模な科学実験でのデータ収集にArduinoボードを使用しています。その後、実装が異なる複数のArduinoボードをサポートする必要があります。 Python単体テスト中にArduinoの16進画像を動的にロードするユーティリティ。以下のリンクにあるコードは、構成ファイルを介してWindowsおよびMac OS Xをサポートします。 Arduino IDEで、Shiftキーを押してからビルド(再生)ボタンを押すアップロードを押しながらShiftキーを押すと、システム/バージョンのArduinoでavrdude(コマンドラインアップロードユーティリティ)の場所がわかります。含まれている構成ファイルを見て、インストール場所を使用できます(現在はArduino 0020上)。
James W. Grenningは素晴らしい本を書いています。これは埋め込みCコードのユニットテストに関するものです埋め込みCのテスト駆動開発。
ハードウェア固有のコードを他のコードから分離または抽象化しておくと、優れたツールを使用し、最も馴染みのあるプラットフォームで、より大きな「残り」をテストおよびデバッグできます。
基本的に、できるだけ多くの既知の動作する構築ブロックから最終的なコードをできるだけ多く構築するようにしてください。残りのハードウェア固有の作業は、はるかに簡単で高速になります。既存のエミュレータを使用したり、自分でデバイスをエミュレートしたりして、それを終了できます。そして、もちろん、どうにかして本物をテストする必要があります。状況に応じて、それは非常によく自動化される場合とされない場合があります(つまり、ボタンを押して他の入力を提供するのは誰または何ですか?さまざまなインジケーターと出力を観察および解釈するのは誰ですか?)。
Arduinoコードを書くときに Searduino を使用しています。 SearduinoはArduinoシミュレーターであり、お気に入りのエディターを使用してC/C++を簡単にハックできる開発環境(Makefiles、Cコード...)です。 Arduinoスケッチをインポートして、シミュレーターで実行できます。
Searduino 0.8のスクリーンショット: http://searduino.files.wordpress.com/2014/01/jearduino-0-8.png
Searduino 0.9がリリースされ、最後のテストが完了するとすぐにビデオが録画されます。
シミュレーターでのテストは実際のテストとは見なされませんが、愚かな/論理的な間違い(pinMode(xx, OUTPUT)
などを忘れるなど)を見つけるのに大いに役立ちました。
ところで:私はSearduinoを開発している人の一人です。
arduino_ci
この目的のため。 Arduinoライブラリ(スタンドアロンスケッチではない)のテストに限定されていますが、ユニットテストをローカルまたはCIシステム(Travis CIやAppveyorなど)で実行できます。
Arduino Libraryディレクトリにある、DoSomething
と呼ばれる、do-something.cpp
:
#include <Arduino.h>
#include "do-something.h"
int doSomething(void) {
return 4;
};
次のように単体テストを行います(test/is_four.cpp
またはそのようなもの):
#include <ArduinoUnitTests.h>
#include "../do-something.h"
unittest(library_does_something)
{
assertEqual(4, doSomething());
}
unittest_main() // this is a macro for main(). just go with it.
それで全部です。 assertEqual
構文とテスト構造がおなじみの場合は、 Matthew MurdochのArduinoUnitライブラリ の一部を採用しているためです。彼は his answer で言及しています。
I/Oピン、クロック、シリアルポートなどのユニットテストの詳細については、 Reference.md を参照してください。
これらのユニットテストはコンパイルされ、Ruby gemに含まれるスクリプトを使用して実行されます。その設定方法の例については、 README.md を参照するか、これらの例の1つ:
ncore というプロジェクトがあり、Arduinoのネイティブコアを提供します。また、Arduinoコードのテストを作成できます。
プロジェクトの説明から
ネイティブコアを使用すると、ArduinoスケッチをPC上でコンパイルして実行できます。通常は変更する必要はありません。これは、標準のArduino関数のネイティブバージョンと、通常はハードウェア自体から来るスケッチに入力を提供するコマンドラインインタープリターを提供します。
テストをビルドする場合は、 http://cxxtest.tigris.org のcxxtestが必要です。 NCOREはcxxtest 3.10.1でテストされています。
MCUの外部(デスクトップ)でコードの単体テストを行う場合は、libcheckをチェックアウトします。 https://libcheck.github.io/check/
私はそれを使って自分の埋め込みコードを数回テストしました。かなり堅牢なフレームワークです。
Autodesk Circuit Simulatorを試してください。 Arduinoのコードと回路を他の多くのハードウェアコンポーネントでテストできます。
Proteus VSMとArduinoライブラリを使用して、コードをデバッグまたはテストします。
コードをオンボードにする前にベストプラクティスですが、ボード上で実行されるとシミュレーションがリアルタイムで実行されないため、タイミングを確認してください。
emulare を使用できます—ダイアグラム上でマイクロコントローラーをドラッグアンドドロップし、Eclipseでコードを実行できます。 Webサイトのドキュメントに、設定方法が記載されています。
基本的なArduinoはCおよびC++で記述されており、arduinoのライブラリもCおよびC++で記述されています。そのため、簡単に言えば、コードをCおよびC++として処理し、単体テストを実行してみてください。ここで、「ハンドル」という言葉は、serial.printlnからsysout、pinmodeからvaraibles、voidループからwhile()ループなど、すべての基本的な構文をキーストックで、または反復後に中断することを意味します。
私はこれが少し長いプロセスであり、それほど簡単ではないことを知っています。私の個人的な経験では、一度それを理解したら、これはより信頼できるものになります。
-Nandha_Frost