読者です 読者をやめる 読者になる 読者になる

組み込み開発へのテスト駆動開発の導入 その2

組み込み開発へのテスト駆動開発の導入 - 千里霧中の続きです。

実機を伴うテストの問題点

 では次に実機を伴うテスト環境についてですが、こちらはターゲットに似た実機環境を用意する方法と、テスト専用の機器上で動かす方法があると思います。

 まず後者については、有力な候補ではないと思います。テスト用デバイスというのはパッケージソフトウェア以上に高額な価格設定がされているのが一般的な上、ターゲットと大分違う条件でテストをせざるを得ないためです。おそらくこのような環境を活用できるのは、よほど恵まれた環境か、特定製品に専業化した環境ぐらいに限られると思います。

 一方前者に関しては、組み込み開発では最も一般的に行われている手段ではないかと思われます。例えば試作段階のターゲットの基盤を最低限のプロセッサが動作できるように一時的に改造して、Tera Termといった端末でファームウェアと通信したり、メモリダンプを活用したり、ICEを導入したりしてテストを行うする方法は、マイコンが絡む開発をしている方にとってはありふれたものでしょう。
 ただ問題なのは、こうした実機を使ったテストというのは、焼きこみに時間がかかったり、ハードウェアの初期化処理を必要としたりして、実際に始めるまでにタイムラグや手作業が発生することが多いという点です。すなわち、テスト結果を見て修正、などといった開発作業を、軽快に進められません。

 以上、組み込み開発でのターゲットを伴わないテスト環境というのは、いろいろ課題があります。

 

実機依存のTDD

 ではどうするかについてですが、まったくありふれた考え方ですが、上流設計段階から厳しくテスタビリティを織り込んで、同一IDE上でコードもテストケースも一緒に編集してしまう形が、今の自分の対処となっています。具体的には次の2ステップのようになります。

ホスト上のテスト

 テストはCUnitなどの軽快なテストツールを利用します。
 テストツールがコードをビルドして結果を返すまでの処理を、バッチファイルなどで自動化します。またマクロの定義などもIDEの機能で自動化し、IDEから手軽にテストを実行できるようにします。出力は標準IOを用います。

 一方で、ソフトウェア実装時は徹底的にクロス開発環境でのテスタビリティをコードに織り込みます。具体的には、実機非依存部を実機依存コードから切り離し、なるべく細かなファイルで構成するように慎重に設計します。どうしても除去できない実機依存コードや関数のstatic宣言、テスト時にドライバ/スタブなどに切り替える必要なるコードなどは、マクロで無用/有効を切り替えられるようにし、前述の自動化処理に組み込みます。
 またこうしたテスタビリティの織り込みは、制約の多い組込みCでは実装段階だけで済ませるのがとても大変なので、上位の構造化・モジュール設計の段階から取り組みます。

 ここでテストコードはテスト対象のコードと同じIDE上で編集します。テストも自動化されたタスクとしてIDEから実行します。

 なおこの方法に関しては、制約が色々存在する以上使い勝手の良いIDEが必要になるでしょう。その点、最近組み込み向けでもEclipseベースのIDEが増えてきたのはいい傾向だと感じます。

ターゲット上のテスト

 IDEでの同一のワークスペース上に、テスト対象のプロジェクトと、実機テスト用のプロジェクトの2つを用意します。
 両者はコードを共有していますが、テストコードの追加などで生じた差分はテスト用のプロジェクトのみに適用します。一方で、Tera Termのような端末にテスト結果を出力するように、assert関数を独自実装します。テストはTera Termのような端末に、シリアル通信などで結果を送信しながら進めます。

流れ

 上記ステップの流れとしては、基本的にホスト上のTDDで軽快にくみ上げつつ、外部依存部が必要になったらターゲット上のテストを使ってTDDを行うような形になります。


 とりあえずプライベートで突き詰めてみようと思います。TDDが組み込みであってもとても重要であるということは、前のWEwLC読書会でよくわかりましたから。