組み込みアプリ層のテストはなぜフレーキーになるのか
組み込み開発では、テストが不安定になる、いわゆる「フレーキーテスト」が発生することがある。CI 環境だけで失敗したり、デバッグ時には再現しなかったり、同じ入力でも結果が揺れたり、sleep を入れると安定するように見えたりといった現象が典型的だ。こうした問題はしばしばテスト設計や実装ミスとして扱われるが、原因はそれだけではない。
フレーキーテストには単純なテスト実装の問題もあれば、実行構造そのものが不安定さを生むケースもある。本記事で扱うのは後者、つまり「実行のされ方」が揺らぐ構造的な問題である。ここでいう実行構造とは、OS スケジューラ、割り込み、タイマー、キュー処理といった、“いつ・どの順で・どの状態から実行されるか” を決める仕組み全体を指す。
アプリ層は本来フレーキーになりにくい
理想的なアプリケーション層はシンプルな構造を持つ。なぜなら入力が決まれば出力が決まるし、状態は局所に閉じており、副作用は外部に分離されているからだ。
この前提が守られている限り、テストは本来安定する。
入力 → 処理 → 出力
それでもフレーキーが発生するのは、別の要素がこの構造の中に入り込むためである。
実行構造をテストが制御できていない
フレーキーテストを観察すると、単純に「テストが悪い」とは言い切れないケースが多い。
実際には、ある時だけ実行順が変わったり、実行タイミングによって結果が変わったり、前回の状態に引きずられたりといった、実行のされ方に起因する現象が頻繁に現れる。つまり問題になっているのはロジックそのものではなく、テスト側が実行構造を十分に制御できていないことだと考えられる。
ここでいう実行構造とは、「いつ実行されるか」という時間の問題、「どの順番で実行されるか」という順序の問題、そして「どの状態から開始されるか」という状態の問題といった、実行に関わる要素全体を指す。
時間として見えるケース
- sleep依存で安定したり不安定になったりする
- タイマーやtimeoutの境界で揺れる
これは単なる時間依存というよりは、テストが「いつ実行されるか」を制御できていないことの表れである。
順序として見えるケース
- 割り込みタイミングで結果が変わる
- RTOSスケジューリングで挙動が揺れる
- キュー処理順に依存する
これらも単なる処理順序の問題というより、テストが「どの順で実行されるか」を制御できていないことの表れである。
状態として見えるケース
- グローバル状態に依存する
- ハードウェア状態に引きずられる
- 他モジュールの影響を受ける
これは状態設計の問題として現れることも多い。しかし同時に、テストが初期条件を十分固定できていない状態としてみることもできる。
“設計の良し悪し”とは少し違う
フレーキーは単純な意味での設計不良とは限らない。モジュール分割は適切に実施され
内部ロジックも整理されている。インターフェースも最適な形に設計されている。
そのような非常に練られた設計であっても、それでも不安定になることは普通にある。
理由はシンプルで、
フレーキーテストとは?
フレーキーテストとは、実行タイミングや順序、状態の決定権がテストの外側にあるときに発生する現象である。ここで重要なのは、「外にあること」自体が問題なのではなく、「テストがそれを制御できないこと」が原因になっている点である。
組み込みアプリ層で起きるフレーキーテストは、テストコード単体の問題ではなく、実行の制御権がテスト側にないことによって生じる観測結果として整理できる。時間や順序、状態の揺らぎとして現れることが多く、単なる偶発的な失敗ではない。むしろ、実行構造がテストから見て制御不能になっていることを示すシグナルと言える。
解決への接続
ここまで見てきたように、フレーキーテストにはテスト実装の問題だけでなく、テストコードが実行構造を十分に制御できていないことによって起きるケースがある。実行構造が原因のフレーキーに対して個別の現象へ対症療法的に対応しても、別の場所で同じ問題が再発することが多い。
この問題は、いわゆる「テストしやすいコード」を書くだけでは解決しない。必要なのは、「実行の決定権をどこに置くか」を設計として整理することである。時間の進行を誰が決めるのか、非同期処理の実行順を誰が決めるのか、状態遷移の開始条件を誰が固定するのかといった点が曖昧なままでは、テストの安定はどうしても難しくなる。
フレーキーを直すのではなく、フレーキーが生まれない構造を設計することが重要になる。本シリーズが、その考え方を整理する際の手がかりになればうれしい。
本テーマをさらに深く掘り下げたい方は、以下の記事も参考になる。
本テーマと関連の強い記事
RTOS依存を捨てる設計:最小OS抽象という考え方 #2
テスト困難性を局所化する #Sleep Abort
なぜ組み込みソフトはテスト不能になるのか:消えたシステム境界を取り戻す
Discussion