見出し画像

状態遷移テストと1スイッチカバレッジ

最近、自分のMacにAstah*を入れたので、状態遷移テストについて書いてみます。本文に挿入した図は全てAstah*で書いたものです。コロナ感染症の拡大防止対策のために急遽WFHしなきゃいけない人がAstah*を使えないといけないということで、2020年5月31日まで無償で使えることになったとのことです。こんな時だから、家にいてモデリングの勉強なんかにも使えるのでとってもいいですよね!経緯は下のツイートで。

はじめに

状態遷移モデルを書いてそのモデルを網羅するようにテストケースを洗い出す、状態遷移テストをご存知でしょうか?「当然知っている」って人もいるでしょうし、「なんとなくはわかってるんですが...」って人もいるでしょうし、「よく知らない」って人もいるでしょう。

同値分割法、境界値分析、デシジョンテーブルといったテスト技法は、ある入力とその入力をもとに行われる処理による出力を確認してテストをするときに有用な技法です。

・同値分割法、境界値分析→テストケースのパラメーター
・デシジョンテーブル→パラメーターと処理の組み合わせ
・オールペア→パラメーターの組み合わせ

テスト技法は、テストケース構造でいうパラメーター のバリエーションに着目しています。その中でも上記の技法は事前入力のバリエーションに着目しています。

一方、状態遷移テストは、上記した技法とは異なり、テストケース構造の事前状態(事前条件)に着目しています。テスト技法によって導かれるのは入力の組み合わせではなく、ある操作手順とその前後の状態になります。

状態遷移テストの定義

翔泳社から出ているJSTQBのFL試験参考書の状態遷移テストの解説部分の最初に書いてあるところを引用します、

テストの入力条件が同じならば同じ出力結果になります。通常のソフトウェアテストでは、この前提に立ってテストケースを設計します。しかし、そのようなテストケースばかりではありません。現在の状態や過去の履歴によって異なる振る舞いをすることがあります。同じ入力データを用いても、異なる出力結果になることがあります。(ソフトウェアテスト教科書JSTQBFandation

入力が同じであっても必ず同じ出力にならない場合というのは、その入力の前に何かしら異なることをしています。そのため複数の手順の組み合わせを考慮してテストを行い、その結果を確認する必要があります。この複数の手順を組み合わせたテストを設計する際に使うのが状態遷移テストです。手順は利用者による操作を複数組み合わせる場合もあるし、時間とともに処理が動くタイマーのようなものも含まれます。

状態遷移テストの例

状態遷移テストは、複数の機能を手順を踏んでつなぎ合わせた時に、それらをその順序で動かしていってもうまく動いてくれるか?ってことをテストするときにはとても強力なテスト技法です。例えば、架空の中古車販売のWebサイトを例にしてみます。

仕様は以下の通りにしてみます。

・販売できる中古車をWebサイトに登録すると、その中古車はお客さんからの予約を受け付けることができるようになる。これが予約受付中状態。
Webサイトにてお客さんがその中古車を予約した後、予約したお客さんが購入に必要な詳細情報を登録できる。販売する側は、その内容を審査して予約を成立の可否を判断する。ただし、詳細情報が予約受付済みになってから48時間たっても登録されない場合は予約受付は自動的にリセットされ、なかったことになる。これが予約受付済み状態。
・審査結果OKを登録すると予約が成立し、正式に販売手続きに入ることができる。販売手続きが完了し、納車が済むまでは、お客さんは購入をキャンセルする権利がある。キャンセル後は他のお客さんが該当の中古車を予約可能になる。これが予約成立状態
・納車が済むとWebサイトからは該当の中古車は検索できなくなる。

この仕様で書いた「予約を受け付ける」とか「購入に必要な詳細情報を登録する」といったそれぞれの処理のテストをする際は、同値分割法や境界値分析、デシジョンテーブルなどを使います。

それだけでなく、一連の処理の流れに伴う状態の変化で、実行できる処理が適切かも確認したいとします。例えば、以下のようなことが該当します。

・予約受付済み状態の時には、他のお客さんがその中古車を予約出来てはいけない。ダブルブッキングになっちゃいます。
・審査結果の入力は予約受付済みの状態のときにしか出来てはいけない。OKしたあとにNGの登録をしたらおかしなことになります。
・予約受付済みの後、必要な情報を入力せずに48時間経過すると予約がリセットされる仕様なので、そのあとは他の人がその中古車を予約できるようにならないといけません。

上記のような確認をする際、単に処理を並べて複数回実行するのではなく、状態に影響を与えるだろう処理を組み合わせることで、処理順序に潜む欠陥のリスクを効率的にテストすることができます。処理順序の組み合わせを見つけ出すには、仕様を状態遷移モデルで表して網羅します。

上記した中古車販売Webサイトの仕様は以下のような状態遷移モデルで表現できます。

中古車販売サイトの予約状態

注)状態遷移モデルでは、ガード条件、アクション、履歴も記述することで更にリッチに仕様を表現できますが、状態遷移テストの説明をするための本筋ではないのでこのnoteでは割愛して簡略させたモデルだけで説明を続けていきます。

「これらの欠陥を見つけることを確認するために状態遷移モデルをどう網羅すると良いのか」に対して、先人が編み出したプラクティスがスイッチカバレッジというカバレッジ基準です。

状態遷移テストのカバレッジ基準

スイッチカバレッジとは、状態遷移モデルの中から、「事前状態と事後状態、事後状態に遷移させるトリガーになる手順(このことをイベントとも呼びます)」を抜き出してみたときに全部を少なくとも1回は動かしているかどうかで測るカバレッジ基準です。

注)スイッチカバレッジはnスイッチとか言いますが、これは事前状態と事後状態の間にある状態をスイッチにたとえてるところから来ています。0個でであれば0スイッチですし、1つであれば1スイッチです。このような数を変数としてn個分のスイッチがあるというところからnスイッチと呼ばれます。遷移の数でいうとnと遷移の数が合わないのはそのためです。

0スイッチカバレッジ

状態遷移モデルの中から、「事前状態と事後状態、事後状態に遷移させるトリガーになる手順」を抜き出して網羅する場合をゼロスイッチカバレッジと呼びます。

スクリーンショット 2020-03-28 13.50.48

上記したモデルであれば、「予約受付中(事前状態)」「予約(処理手順)」「予約受付済み(事後状態)」を抜き出す単位にします。事前と事後の間にはトリガーになる手順しかない(スイッチがゼロ)のため、0スイッチと呼びます。

状態遷移表

0スイッチカバレッジに必要な組み合わせを抜き出すには、状態遷移モデルを図ではなく、表にするのがよいです。以下が中古車販売Webサイトの例を状態遷移表にしてみたものになります。

スクリーンショット 2020-04-11 11.46.03

上記表の行が事前状態、列がトリガー(イベント)、セルの交点になる部分が事後状態になります。

状態遷移図を状態遷移表に表すことで、交点が空欄になっている部分が多数あることに気づくでしょうか。実は、図で表したモデルには、状態とイベントの組み合わせの結果どこの事後状態にいくかが明確に示されていない組み合わせがあるのです。これらをどうするかがソフトウェア設計で重要になるのですが、テスト設計としても重要になります。空白になるところは、CH:Cannot Happen(発生し得ない)とIE:Ignore Event(そのイベントを無視する)に分けることができます。CHは発生し得ないため、テストすることができません。一方IEはそのトリガーを発生させることはできますが無視をするはずなので、本当に無視するかをテストしたほうがよいですね。なので以下のように空欄の部分がどう動くはずなのかを追記します。

スクリーンショット 2020-04-11 11.51.57

そしてこの交点になったところを必ず一度はテストするように手順の組み合わせを作れば0スイッチカバレッジ100%のテストになります。以下のように18パターンの組み合わせになります。

スクリーンショット 2020-04-11 12.00.37

0スイッチカバレッジは、仕様通りにできてるか確認するにはよいですが、込み入った手順で想定外の欠陥を見つけるようなテストまでカバーできません。例えば、予約成立したのだけれど、成立した予約を取り消した後、一定の時間を過ぎれば他の人が予約可能になるか?といったことを確実にテストするには0スイッチカバレッジだと不十分です。その場合は1スイッチカバレッジ基準を適用します。

1スイッチカバレッジ

1スイッチカバレッジでは、状態遷移モデルの中から、「事前状態と事後状態、事後状態に遷移させるトリガーになる手順」を抜き出す際に、トリガーになる手順の間に状態が1つ入った組み合わせを網羅することになります。

スクリーンショット 2020-03-28 13.50.18

上記したモデルであれば、「予約受付中(事前状態)」「予約(処理手順)」「予約受付済み(スイッチ)」「審査OK(処理手順)「予約成立(事後状態)」を抜き出す単位にします。事前と事後の間にはトリガーになる手順が2つあり、手順の間にスイッチが1つあるため、1スイッチと呼びます。

行列の掛け算

1スイッチカバレッジを見つけ出すには、行列の掛け算を使います。以下に行列の掛け算の説明がわかりやすいサイトのリンクを貼っておきます。

これを実際にやってみましょう。計算しやすいように、開始状態と終了状態を一旦見えなくして、中古車販売Webサイトの状態遷移モデルのトリガーを記号にしてみました。

中古車販売サイトの予約状態

これを、状態X状態のマトリクスで表現します。

スクリーンショット 2020-04-11 13.52.53

これを以下のように行列計算します。

画像9

結果はトリガーの組み合わせで表現します。例えば、acであれば[予約受付中 a 予約受付済 c 予約受付中]という順序の組み合わせを示します。
ac+adのように、事前状態と事後状態が一緒になるトリガーの組み合わせが複数ある場合は+で表現します。

ただし、IEまで含めて、全部を行列計算するのは、手動計算だとかなり大変ですよね?少なくとも私はちょっと辛いと思ってしまいます。

Astah*だと、1スイッチカバレッジに相当する組み合わせを状態遷移表を書いておけば自動で出してくれます。(すごくべんり!)

スクリーンショット 2020-04-11 14.48.52

上記のように、「状態遷移パス」を選択し、遷移回数を「2」にすればOKです。画像では35パターンまでしか表示してませんが、この場合だと、実際113パターンになります。

現実的には

0スイッチだと18パターンだったのが、1スイッチだと113パターンになるので、結構たくさんパターンが増えてしまいます。なので、単純に1スイッチカバレッジをやるのでなく工夫をしてパターンが増えないようにします。この工夫を「テスト設計」と呼びます。

工夫の例
・特に欠陥が入ってしまいそうだと思われる事前状態を決めて、その事前状態を起点にした場合だけ1スイッチカバレッジを行う。
・テストする観点では、複数の状態を1つとみなして構わないと判断したら状態遷移モデルを簡略化する。(以下の図参照)

スクリーンショット 2020-04-11 11.29.41

では演習してみましょう!

以下のチェンジビジョンのサイトで解説している、状態遷移モデルから
・1スイッチカバレッジのパターンを全部洗い出してください
・テスト設計をしてパターンの数を適正にしてみてください

解答は今はありません(私もこれから設計してみます)。

サポートありがとうございます。これをカテにこれからも頑張ります。