新人技術者のためのロジカル・シンキング入門(7) ―― 「ひたすら流すだけのテスト」にさよなら
【2】モジュール単体のテスト・ケースを考える(2/2)
● ステートありでは入力を網羅しても全数テストではない
次に,内部にステートを持つモジュールについて考えてみることにしましょう.ここでもハードウェア回路に倣って,このようなモジュールを「順序回路」と呼ぶことにします.順序回路とは,ハードウェアの観点からいうとフリップフロップを持つ回路です.このような回路はハードウェアであれソフトウェアであれ,内部にステートを持ちます.順序回路の特徴は,次の通りです.
- 入力とステートの組み合わせで出力が決まる
- ステートには初期値が必要
- リセットが必要
これらの特徴を図3に示すTフリップフロップを例に
とって考えてみます.
まず特徴(1)ですが,Tフリップフロップは,端子Tに'1'が入るたびにQのステート(状態)が'0'→'1'→'0'→'1'と反転する(トグルする)回路のことです.入力が同じ(例えばTが'1')でも,'0'と'1'が交互に出力されることから,出力は入力だけでは決まらないことが分かります.出力の期待値は,あくまで入力とステートの組み合わせから決まります.
ステートを持っているので,ステートの値には初期値が必要であることが分かります(特徴(2)).そうでなければ回路の中に不定値を持つ部分があることになってしまうからです.そこから,ステートを初期値に設定するリセット処理が必要なことが分かります(特徴(3)).これを実装の面から見ると,「ハードウェアではリセット信号が必要」ということになります.ソフトウェアであれば,モジュールにはリセット用の関数が必要ということになります(図4).
ステートを持つ場合,スタティック変数の値と入力の組み合わせで出力が決まる.スタティック変数を毎回設定してテストできれば全数テストも可能.そのようなスタティック変数にモジュールの外から初期値以外の値が設定できるようにするには設計に工夫が必要.
以上のことから,順序回路の場合は入力パターンをすべて網羅しても全数テストになるわけではないということが分かります.
● ソフトウェアは比較的容易に全数テストできることも
このことは,時としてテストを困難なものにしてしまいます.なぜなら,モジュールの外からステートを直接設定できるような作りになっているとは限らないからです.これはハードウェア,ソフトウェアの両方の場合で共通していえます.
ハードウェアの場合,テスト回路を組んで,テスト用にステートを設定できるようにする手段もあるでしょう.しかし,回路の中にあるすべてのフリップフロップを望みのステートにするようにテスト回路を組むのは非現実的であるように思えます.順序回路の場合,組み合わせ回路とは別の事情から,テスト・ケースの絞り込みが必要となってしまいます.
しかしソフトウェアの場合,ステートの設定がモジュールの外からできるようになっていれば,テストは容易になります(図5).本連載の第2回で示したように,ステート,すなわちスタティック・データを構造体からたどれるように実装した場合を考えてみます.この場合は,テスト対象となるモジュールの外から自由にスタティック・データの値を設定できるので,入力とステートのパターンをすべて網羅することもできます.要するに,入力信号と同じように手軽にステートを設定できる場合,組み合わせ回路と同じ考え方で全数テストを行えるのです.
モジュールの外からステートが設定できるようになっていれば,入力データやパラメータ,ステートを与えることで,出力とステートが期待値と一致するかを確認できる.設計やコーディングの際はテストのしやすさも考慮に入れること.
逆にステートの中身が関数の外から設定できない場合は,全数テストの実施が難しくなります.
連載第5回では,「設計,テスト,コーディングの各工程を調和させなければならない」と述べましたが,ここで示した例でも分かるように,設計やコーディングを行う段階でテストのしやすさまで考えることは重要です.
入力イベントとステートによって処理(アクション)と次のステートが定まる,いわゆる「ステート・マシン」は,このような全数テストが望ましい回路(モジュール)といえるでしょう.
要するに,入力とステートの組み合わせを状態遷移表にして,次の動きが一意に定まるような場合は,全数テストが有効,もしくは必要であるといえます.ステート・マシンの場合,状態遷移表の升目の数だけテスト・ケースを用意すれば全数テストとなります.ですから,テストのたびに升目にチェックを付けていき,表のすべてがチェック印で埋め尽くされたところでテストが完了します.