Arduino環境使うとき、前々から気になっていたことに unit test があります。いつもテキトーに書いて動かしているけれども、unit testやった方が良いなあ。ちと面倒ですが、やっておくと後でツマラナイ問題で悩むことが少なくなることは痛感しています。いくつかArduino環境で使える「テスト・フレームワーク」みたいなものもあるみたいだし、この辺で学んでおくか、と。
※「鳥なき里のマイコン屋」投稿順Indexはこちら
皆さま方も unit test されていることと存じますです。私の狭い経験では、以下のテスト・フレームワークにお世話になっております。
-
- C#書くときの NUnit
- Python書くときときの unittest
- C書くときのgoogletest
お世話になっているといっても、使い方はいつも「通りいっぺん」、フレームワークで使える機能のごくごく一部を使わせていただいて十分間に合ってます。大したコードも書かないし。。。それに、あまり人生複雑にしたくないので、お世話になるテスト・フレームワークは積極的には増やしたくありません。でもね「ユニットテストをしないのは人生複雑にしてしまう」気がしています。
そんなわけでArduino環境で使えるユニットテストのフレームワーク、ちと調べ始めました。とはいえ人気のArduino環境なので先達がおられます。とても参考になる記事をみつけました。
Using Unit Test Frameworks With Arduino
この記事の中で挙げられていたものを列挙すると以下のようです。
1番目は全部自分で書く、これは「何時でもできる(やってる)」ので今回はパス。それに対して4番目は、前々からこれも気になっており VS Code + PlatformIOの中で確かめてみたいと思っていたもの。そして Arduino環境にも適用可能ですが、他の実行環境でも実行可能。こちらは「後で」別に取り上げさせていただくつもりであります。すると2番目か、3番目という選択になります。3番目の方は2番目の後から、2番目との互換性にも配慮しつつ作られたものようです。AUnitの説明文書から1文引用させていただきます。
AUnit consumes as much as 65% less flash memory than ArduinoUnit 2.2 on the AVR platform.
メモリ容量が限られたAVRマイコンのことを考えるとAUnitかなあ。ということでAUnitを最初に試用してみることにいたしました。
しかし、マイコンでunit test をやるにあたっては下のことも気になっていたのです。
毎回、マイコンのFlashにテスト用のオブジェクトを書きこむの辛い
テストなど一発で通る筈もなく、また、追加などもこれあり。フェイルの度、追加の度にビルドしなおし、オブジェクトをアップロードする手間は「うんざり」だ、と。また、最近のマイコンのFlash書き換え可能回数は多いので気にならなくなりましたが、昔の回数制限が気になるチップなどの記憶もふとよぎる、と。
パソコンの上でも実行できるような関数はパソコンの上でテストできるといいんじゃね
何時もの事ながら、AUnitの作者の方もまた「そんなことオミトオシ」でした。
AUnitの友、EpoxyDuino
EpoxyDuinoは、Arduino環境用のコード(.ino拡張子)やライブラリをPC上でビルドして模擬的に実行するためのフレームワークです。当然、マイコンのハードウエアにベッタリ依存しているような部分は実行しえません(具体的に言えば、ArduinoのLチカプログラムをビルドして実行できますが、LEDが光るわけじゃありません)が、ハードと切り離せるようなレイヤの関数ならそれなりに実行できる、というもの。そのうえ、AUnitを作られた方が作っているのでAUnitと「併用」できるようにもともと考えられていたようです。考えようによってはAUnitをPC上で実行するための代替環境のよう。作者のBrian Park様万歳!ということでまずはEpoxyDuinoのインストールからいたしてみました。
普段Windows上のArduinoIDEを使っているので、インストール先は、IDEのプロジェクトフォルダ内のlibrariesフォルダにしたいです。ここに置けばインストール済のライブラリモジュール群とともに参照しやすいです。しかし残念なことに
EpoxyDuinoはLinux系(FreeBSD含む)のみ対応
であります。Raspbianにも対応していたのでRaspbianも考えましたが、普段のArduino用のビルド環境と分けてしまうと、面倒なので直ぐに使わなくなること必定。
そこで長いこと眠っていた(マイコンのクロス環境はMSYS系利用が多いので)WSL(Windows Subsystem for Linux)を復活させてみました。WSL2なら仮想マシンでホンマのUbuntuが走るので互換性上は多分問題ない筈。しかし、軽く済ませたいので2のつかない昔のWSLのままでやってみました。WSLに載せていたUbutuが16.04と古かった(EposyDuinoは18.04か20.04推奨)ので20.04を再ダウンロードし、g++やmakeを使えるようにいたしました(build-essentialをインストール。)これで bash を走らせ、Windows上のArduinoのプロジェクトフォルダに入りました。EpoxyDuino自体はArduino用といいつつ「PCのソフト」なので、ArduinoIDEのライブラリマネージャではインストールすることはできません。githubからcloneして導入。早速 EpoxyDuino/examples内のサンプルプロジェクト
BlinkSOS
をビルドしてみました。ビルドはmake一発。成功。起動もできました。
暴走はしていませんが挙動が変
調べてみると stdin (EpoxyDuino環境では、ArduinoのSerialオブジェクトの出力先が stdout と stdinに向けられている)を読みに行って「止まって」しまっているようでした。本来のLinux系の挙動であれば止まらずに先に進む筈です。それがWindows上のWSL(1)環境のBashから実行すると標準入出力の挙動が微妙に違うのでしょうか?ブロックされてしまうみたい。そこで以下のような「便法」で切り抜けました。
つまり stdin に無尽蔵の入力を接続すれば、途中でブロックされず、意図通りに走るわけです。勿論、Serialから意味のあるreadするようなプログラムには適用できない逃げ方です。また、EpoxyDuinoの本来の仕様ではCTRL-Cで割り込める筈が、CTRL-Cで止めることができなくなりました。しかし、CTRL-Zでプロセスをサスペンドすることは可能でした。よって、ちと面倒ですが、CTRL-Zのあと、psしてPIDを調べ、killして始末をつけました。かっこ悪いけれど一応Windows上でも動かせそうね。
次に本題の AUnitを EpoxyDuino使って、PC上で動作させてみます。AUnitは「純粋」Arduinoのライブラリなので、ArduinoIDEのライブラリマネージャから探してインストール可能です。
さて、インストールしました。これでLibrariesフォルダ内には、EpoxyDuinoとAUnitのフォルダ(および他のArduinoライブラリ沢山)が並びました。AUnitのフォルダ内にもexamplesがあります。その中の basic.ino という「unittest」のサンプルをEpoxyDuino使ってPC上で動かしてみます。AUnitのサンプルにはEpoxyDuino使ってビルドするためのMakefileも含まれています。これまたmake 一発。ビルドはOK。動かし方は上の便法であります。こんな感じ。
テストがpassしたり failしたりしているのは、それを見せるためのデモ用のソースだから。Arduino用のunittestをPC(Windows)上で期待通りに実行できました。
今回は、Arduinoといいつつ、パソコンのキーボード叩いているだけだったです。実機は何時?