2019-09-15
組込みC言語の単体テスト自動化を考える
テスト自動化を考える。組込みでテスト自動化したいのだ。
重要な用語とその課題¥
テストとは、バグのある実装を避ける技術ではなく、意図しない破壊的変更を検出するための技術。
- テストフレームワーク
- 複数のテストを実行する。組込み開発環境には組み込み特有の課題がある。
- 命令がRAMではなく不揮発性のROMに書き込まれ、プログラムの差し替えが難しい
- RAMが小さく、大規模なことがしにくい
- ブートローダやリンカを使いこなす必要があり、難しい
- ファイルシステムやコンソールがないのでprintfによるテスト実行結果が確認しづらい
- スタブ
- 偽の通信相手を作成し、事前に設定した任意の期待値を得る。
- C言語はコンパイルが必要な言語なので、スクリプト言語のような関数の差し替えが難しい
- 全ての関数コールを関数ポインタ経由にするのも現実的ではない
- リターン値を自在にコントロールすることで正常系・異常系のテストができるはず。
- ハードウェアが揃わないと開発できない、揃っても危険。
- 割り込み待ち、という処理を抽象化できるか。本物は割り込みも再現してくれる。戦略
- 関数名は同じだが、実装を変える。コンパイラオプションで
- モック
- ビヘイビアを確認するために作成するオブジェクト
- 実は使いどころが難しいと個人的には思っている。
- 引数が必要な関数に偽オブジェクトを渡す。
- スタブはステートをいじるもの、モックはステートをいじってもらうもの。
- オブジェクトが意図した使われ方をするか、をテストできる
- google test
- FFF
- google mock
- elf spy
- fakeit
- unity
- catch
- cunit
組込み開発でもPCで実行すればいいじゃないか。
こういったテストフレームワークはPC向けを想定されていて、組み込み環境では使いにくい。それならば最初からPCの上で実行すればいいじゃないか。実際、そういう記事(英語)が多いので、その方法のほうが一般的なんだろう。
そのためには、組込み特有の「ペリフェラルのレジスタ(メモリマップドI/O)」「割り込み」「RTOS」の振る舞いを汎用PCの上で再現する必要がある。
- レジスタ
- 特定のアドレスから仮の値をリードする
- 特定のアドレスに値を書き込んだふりをして、何か機能が実行されたことにする
- 一定時間後にデータが用意される (HWがなくても必ず成功する)
- 特定の割り込みハンドラが実行される (HWがなくても必ず成功する)
- データが読み取れる(HWがなくても必ず成功する)
- 割り込み
- _
- RTOS
- 待ち状態に入る (waitFlag)
- 周期的な処理を行う(cyclic handler)
- 起きてほしいタイミングで起きて、処理を続行する。
- セマフォ・ミューテックス
- メッセージバッファ
- ミドルウェア
- テスタビリティは考慮されていないので、ミドルウェア全体をエミュレーションする
- 代表的な構造を想定する
- 裏でタスクが動く
- タスクがメインタスクに"何らかの手段"で通知/同期通信を行う
- メインタスクがデータを受け取り、処理を継続する。
この記事をちゃんと読んだらおもしろそう。http://www.electronvector.com/blog/for-embedded-tdd-dont-worry-so-much-about-testing-on-the-target
RTOS
freeRTOS kernelはWindows上で動くらしいので試してみた。delayTaskしか試してないけど、なんか動いてちょっと感動。求めていたのはこういうことなんだよ、という気分。ただ、どこまでできるのかは不明。
CIは普通Linux環境で実行されるので、Linuxで動作する環境を構築する必要がある。セットアップ面倒だな。
割り込み、レジスタアクセスは抽象化しないといけない。