状態遷移図があるのに、なぜテスト技術者は状態遷移表を書くのか
前回の最後に予告した通り、テスト技術者は状態遷移図がある場合にもなぜ状態遷移表を作成するのか、その理由の話から始めたいと思います。
以下に示した状態遷移図は、あるECサイト注文・決済の部分をモデル化したものです。かなり単純化されていますが、今回の説明のためには十分です。下に示されているのが、同じモデルを状態遷移表で表したものです。モデル図と表を見比べるとよくわかると思いますが、表には×印が多数あります。モデル図には、どのイベントが入ってきたらどの状態に遷移するのかの情報だけが描かれています。表には、状態とイベントの組み合わせがすべて出ているので、モデル図に示されていない組み合わせについて、×が入っていることになります。
状態遷移表の例
| State \ Event | 支払う | キャンセル | 出荷する | 配達完了 |
|---|---|---|---|---|
| 未払い | 支払済 | キャンセル済 | ✕ | ✕ |
| 支払済 | ✕ | キャンセル済 | 出荷済 | ✕ |
| キャンセル済 | ✕ | ✕ | ✕ | ✕ |
| 出荷済 | ✕ | ✕ | ✕ | 配達完了 |
| 配達完了 | ✕ | ✕ | ✕ | ✕ |
※状態遷移表と状態遷移図は、多くのツールが相互に変換してくれます。片方を定義すれば、もう片方は自動生成してくれます。筆者も1つツールを提供していますので、ご活用ください。
開発設計者は基本的に「起こってほしいこと」をモデル化して設計していくことが多いと思います。常にすべての組み合わせの場合を網羅的に考えていると、一向に整理が進まず、設計も進みません。最もシンプルな基本的振る舞いのルールを発見するべく、複雑さを縮減する方向に頭を働かせています。状態遷移表で×の入っているところは基本的に関心のない部分です。
さて、ハードウェアの場合は、その関心のない部分については、特になにか機構を設けないので、何も起こらないことのほうが普通です。一方、ソフトウェアの場合は、設計時に関心を払っていない、かつ想定しないイベントが入ってくると、条件分岐のelse文やotherwise、default文のパスに入り込み、とんでもない動作をする危険性が高いと言えます。
要求されている振る舞いを機能としてしっかり作り込むのと同時に、それ以外の振る舞いは、やはりしっかり防がないと、例えば現物先出し・二重出庫・出荷済からのキャンセル・二重返金・二重請求・キャンセルしたのに請求といった、金銭的な損害やブランドを毀損するようなビジネス上の事故につながってしまいます。
AI時代になり、AIにやってほしい振る舞いを指示するだけで所望のプログラムが出来上がるようになりました。ただ、それで喜んでいると、危険だということがここからもわかります。やってはいけない振る舞いを教えていないケースが多々あるならば、何をやらかすかわからない。もちろん、人間の経験則からそれを学習している領域も多いと思いますが、検証なしに使用するのはリスクが大きいと言わざるを得ないでしょう。
テストをしていると、例えば画面に仕様には書かれていない余計な遷移を引き起こすボタンなどが残っているケースを実際に見かけます。開発者はしっかり消したつもりなのでしょうが、表示データ量が多く、複数ページ表示の2ページ目や「もっと表示する」ボタンを押した後などに、消したはずのボタンが復活表示される例もありました。起こってはいけないことを防ぐことができているかを確認するためのテストは、これからもこれまでと変わらずに重要です。
さて、話を本題に戻します。状態遷移図に対して、状態遷移表は発生してはいけないイベント、起こってはいけない状態遷移、つまり「制約」を表現できていると言えます。
実は、デシジョンテーブルと原因結果グラフとの間にも、以下に示すようにちょうど同じような対応関係があります。興味深いのは、原因結果グラフ法はモデル図側に制約が表現されることになり、ちょうど状態遷移の場合と反対になっています。
デシジョンテーブルは完全にすべての組み合わせを出せば、その中で期待値とともに制約されるべきものを列挙できるではないかと言われればその通りですが、まさかそれを一つひとつ全部確認するなどというやり方は不合理ですし、動的テストの方法そのものがないということもあります。
※「NeoCEG」には学習モードが付いていて、256列までのデシジョンテーブルであればすべての列を表示し、そのうえで制約関係で潰されている列はそれがわかるように表示されるようになっています。実務で使うことはないと思いますので、学習モード扱いにしています。
要するに、制約されている実例を挙げ出したら大変な数になってしまうので、どのような制約関係のルールがあるべきで、それが確実に機能しているかをテストするという方法を取るべきでしょう。
