LoginSignup
1
1

概要

テスト担当者が状態遷移テストをする際、テスト対象の仕様を理解し、どんな状態遷移をモデル化するか、モデルからどのようなテストケースを生成するについての事例紹介です。
状態遷移図描画とテストケース生成には、GIHOZを使ってみました。
また、文中の「戻る操作」というのは、明示的に設置されたボタンやリンクによる操作を示しており、例えば、ブラウザの戻るボタンは含みません。
UnDoのような機能、あるいは、商品・サービスで中心的な機能や画面に戻る操作、戻りすぎて状態が大きく変わってしまうのを制限したい仕様など、評価する上での参考になればと思います。
汎化して抽象的過ぎる感もありますが、テスト設計のお役になればと思います。

2024/3/3 遷移しないケースが丸っと抜けていましたので、追記しています。事例2と事例3が対象です。

状態遷移の例

2つの状態では、直前を覚えたとしても、2つの状態を行き来するだけなので、ここでは、最低でも3つの状態がある場合を考えてみます。

簡単な状態遷移0スイッチ002.png

例えば上記のような場合の1回だけ遷移するテスト(0-スイッチ)は、

testID 開始状態 操作1 終了状態
1 状態A event_AB 状態B
2 状態B event_BA 状態A
3 状態B event_BC 状態C
4 状態C event_CB 状態B
5 状態A event_AC 状態C
6 状態C event_CA 状態A
7 状態A keep_AA 状態A
8 状態B keep_BB 状態B
9 状態C keep_CC 状態C

直前の状態に戻る(UnDo)かのテストでは、一回目の操作で遷移した状態が、次のUnDo操作で戻るのかのテストとなるため、2回状態遷移する(1-スイッチ)で、

testID 開始状態 操作1 後状態 操作2 終了状態
1 状態A event_AB 状態B event_BA
UnDo_BA
状態A
2 状態A event_AB 状態B event_BC 状態C
3 状態A event_AB 状態B keep_BB 状態B
4 状態B event_BA 状態A event_AB
UnDo_AB
状態B
5 状態B event_BA 状態A event_AC 状態C
6 状態B event_BA 状態A keep_AA 状態A
7 状態B event_BC 状態C event_CB
UnDo_CB
状態B
8 状態B event_BC 状態C event_CA 状態A
9 状態B event_BC 状態C keep_CC 状態C
10 状態C event_CB 状態B event_BA 状態A
11 状態C event_CB 状態B event_BC
UnDo_BC
状態C
12 状態C event_CB 状態B keep_BB 状態B
13 状態A event_AC 状態C event_CB 状態B
14 状態A event_AC 状態C event_CA
UnDo_CA
状態A
15 状態A event_AC 状態C keep_CC 状態C
16 状態C event_CA 状態A event_AB 状態B
17 状態C event_CA 状態A event_AC
UnDo_AC
状態C
18 状態C event_CA 状態A keep_AA 状態A
19 状態A keep_AA 状態A event_AB 状態B
20 状態A keep_AA 状態A event_AC 状態C
21 状態A keep_AA 状態A keep_AA 状態A
22 状態B keep_BB 状態B event_BA 状態A
23 状態B keep_BB 状態B event_BC 状態C
24 状態B keep_BB 状態B keep_BB 状態B
25 状態C keep_CC 状態C event_CB 状態B
26 状態C keep_CC 状態C event_CA 状態A
27 状態C keep_CC 状態C keep_CC 状態C

操作の表記は、状態Aから状態Bに遷移する場合、event_AB
状態Bから状態Cに遷移する場合、event_BCといったように記述しています。
また、状態遷移図と生成されたテストケース内で、UnDoに相当するテストについて、手修正しています。
testID 1 のevent_BAは、UnDoなので、UnDo_BA と修正するなど。

直前の状態を覚える仕様における状態遷移

3つの状態があるような場合に、状態Aから状態Bに遷移した後、戻る操作で状態Aには戻ることを確認する必要があります。
また、直前の状態が無い(開始状態)から、最初の状態遷移を考慮すると、

  1. 最初(直前の状態を覚えていない)の状態遷移操作(初めて直前の状態を覚える)
  2. 直前の状態を覚えている状態からの操作
  3. 戻る(UnDo)操作

の3操作を確認するには、最低でも2-スイッチの状態遷移で考えることになります。
これから紹介する状態遷移図の事例以外にも、実際に適用すべきモデルはあるかと思います。ここはぜひ、適用したモデル選定を開発・実装側ともレビューを通じて共有したいところですね。
以下に、考えてみた状態遷移図の3例と、生成したテストケースを紹介します。

直前を覚えた状態を個々に定義した例(事例1)

状態aBというのは、直前が状態Aだったことを覚えている状態Bのことをさします。
直前のみ2.png
開始状態は状態A / 状態B / 状態C です。さらに状態D、状態Eと増えた場合には、もっと複雑になります。3つでもゴチャゴチャなのに。
開始状態を明確に表現している点では、他の2例のモデルよりも適当だとは思います。
GIHOZで生成したテストケースから、操作3に戻る操作が含まれるものだけ取り出してみました。

testID 開始状態 操作1 後状態1 操作2 後状態2 操作3 終了状態
1 状態A event_AC 状態aC event_CB2 状態aB UnDo_BC2 状態aC
2 状態A event_AC 状態aC event_CA2 状態cA UnDo_AC2 状態aC
3 状態A event_AC 状態aC event_CA4 状態bA UnDo_AC4 状態aC
4 状態A event_AC 状態aC event_CB6 状態cB UnDo_BC6 状態aC
5 状態A event_AB 状態aB event_BA2 状態bA UnDo_AB2 状態aB
6 状態A event_AB 状態aB event_BC2 状態aC UnDo_CB2 状態aB
7 状態A event_AB 状態aB event_BC3 状態bC UnDo_CB3 状態aB
8 状態A event_AB 状態aB event_BA4 状態cA UnDo_AB4 状態aB
9 状態B event_BC 状態bC event_CA2 状態bA UnDo_AC2 状態bC
10 状態B event_BC 状態bC event_CB3 状態aB UnDo_BC3 状態bC
11 状態B event_BC 状態bC event_CA5 状態cA UnDo_AC5 状態bC
12 状態B event_BC 状態bC event_CB5 状態cB UnDo_BC5 状態bC
13 状態B event_BA 状態bA event_AB2 状態aB UnDo_BA2 状態bA
14 状態B event_BA 状態bA event_AB3 状態cB UnDo_BA3 状態bA
15 状態B event_BA 状態bA event_AC2 状態bC UnDo_CA2 状態bA
16 状態B event_BA 状態bA event_AC4 状態aC UnDo_CA4 状態bA
17 状態C event_CA 状態cA event_AC2 状態aC UnDo_CA2 状態cA
18 状態C event_CA 状態cA event_AB4 状態aB UnDo_BA4 状態cA
19 状態C event_CA 状態cA event_AC5 状態bC UnDo_CA5 状態cA
20 状態C event_CA 状態cA event_AB5 状態cB UnDo_BA5 状態cA
21 状態C event_CB 状態cB event_BA3 状態bA UnDo_AB3 状態cB
22 状態C event_CB 状態cB event_BC5 状態bC UnDo_CB5 状態cB
23 状態C event_CB 状態cB event_BA5 状態cA UnDo_AB5 状態cB
24 状態C event_CB 状態cB event_BC6 状態aC UnDo_CB6 状態cB

戻った状態を別の状態として定義した例(事例2)

事例1は、UnDo操作が期待通りに動くかのテストとしては十分かもしれませんが、UnDoの前後に別の操作まで含めたテストにしたい場合は、3-スイッチになってしまい、生成されたテストケースからUnDoを含むテストだけ取り出したり、修正したりするのが煩雑になります。
そこで、別の状態を「戻った状態」として分離しました。

2024/03/03 直前のみ覚える仕様以外に、さらにその前も覚える仕様の時は、戻った状態を増やしていくことで対応できるかと思います。

直前のみ24.png

3-スイッチで生成したテストケースの内、戻る操作を含むのは、戻った状態 とか さらに戻る とかを状態遷移図見ながら修正するのが、かなり面倒ですが、

testID 開始状態 操作1 後状態1 操作2 後状態2 操作3 後状態3 操作4 終了状態
1 状態A event_AB 状態B event_BA 状態A keep_AA 状態A keep_AA 状態A
2 状態A event_AB 状態B event_BA 状態A keep_AA 状態A keep_AA 状態A
3 状態A event_AB 状態B event_BC 状態C event_CB 状態B UnDo_BC 状態C
4 状態A event_AB 状態B event_BC 状態C event_CA 状態A keep_AA 状態A
5 状態A event_AB 状態B event_BC 状態C UnDo_CB 状態B さらに戻る 状態B
6 状態A event_AB 状態B UnDo_BA 状態A さらに戻る 状態A さらに戻る 状態A
7 状態A event_AB 状態B keep_BB 状態B event_BA 状態A UnDo_AB 状態B
8 状態A event_AB 状態B keep_BB 状態B event_BC 状態C UnDo_CB 状態B
9 状態A event_AB 状態B keep_BB 状態B UnDo_BA 状態A さらに戻る 状態A
10 状態A event_AB 状態B keep_BB 状態B keep_BB 状態B UnDo_BA 状態A
11 状態B event_BA 状態A event_AB 状態B UnDo_BA 状態A さらに戻る 状態A
12 状態B event_BA 状態A event_AB 状態B keep_BB 状態B UnDo_BA 状態A
13 状態B event_BA 状態A event_AC 状態C UnDo_CA 状態A さらに戻る 状態A
14 状態B event_BA 状態A event_AC 状態C keep_CC 状態C UnDo_CA 状態A
15 状態B event_BA 状態A UnDo_AB 状態B さらに戻る 状態B さらに戻る 状態B
16 状態B event_BA 状態A keep_AA 状態A event_AB 状態B UnDo_BA 状態A
17 状態B event_BA 状態A keep_AA 状態A event_AC 状態C UnDo_CA 状態A
18 状態B event_BA 状態A keep_AA 状態A UnDo_AB 状態B さらに戻る 状態B
19 状態B event_BA 状態A keep_AA 状態A keep_AA 状態A UnDo_AB 状態B
20 状態B event_BC 状態C event_CB 状態B UnDo_BC 状態C さらに戻る 状態C
21 状態B event_BC 状態C event_CB 状態B keep_BB 状態B UnDo_BC 状態C
22 状態B event_BC 状態C event_CA 状態A UnDo_AC 状態C さらに戻る 状態C
23 状態B event_BC 状態C event_CA 状態A keep_AA 状態A UnDo_AC 状態C
24 状態B event_BC 状態C UnDo_CB 状態B さらに戻る 状態B さらに戻る 状態B
25 状態B event_BC 状態C keep_CC 状態C event_CB 状態B UnDo_BC 状態C
26 状態B event_BC 状態C keep_CC 状態C event_CA 状態A UnDo_AC 状態C
27 状態B event_BC 状態C keep_CC 状態C UnDo_CB 状態B さらに戻る 状態B
28 状態B event_BC 状態C keep_CC 状態C keep_CC 状態C UnDo_CB 状態B
29 状態C event_CB 状態B event_BA 状態A UnDo_AB 状態B さらに戻る 状態B
30 状態C event_CB 状態B event_BA 状態A keep_AA 状態A UnDo_AB 状態B
31 状態C event_CB 状態B event_BC 状態C UnDo_CB 状態B さらに戻る 状態B
32 状態C event_CB 状態B event_BC 状態C keep_CC 状態C UnDo_CB 状態B
33 状態C event_CB 状態B UnDo_BC 状態C さらに戻る 状態C さらに戻る 状態C
34 状態C event_CB 状態B keep_BB 状態B event_BA 状態A UnDo_AB 状態B
35 状態C event_CB 状態B keep_BB 状態B event_BC 状態C UnDo_CB 状態B
36 状態C event_CB 状態B keep_BB 状態B UnDo_BC 状態C さらに戻る 状態C
37 状態C event_CB 状態B keep_BB 状態B keep_BB 状態B UnDo_BC 状態C
38 状態A event_AC 状態C event_CB 状態B UnDo_BC 状態C さらに戻る 状態C
39 状態A event_AC 状態C event_CB 状態B keep_BB 状態B UnDo_BC 状態C
40 状態A event_AC 状態C event_CA 状態A UnDo_AC 状態C さらに戻る 状態C
41 状態A event_AC 状態C event_CA 状態A keep_AA 状態A UnDo_AC 状態C
42 状態A event_AC 状態C UnDo_CA 状態A さらに戻る 状態A さらに戻る 状態A
43 状態A event_AC 状態C keep_CC 状態C event_CB 状態B UnDo_BC 状態C
44 状態A event_AC 状態C keep_CC 状態C event_CA 状態A UnDo_AC 状態C
45 状態A event_AC 状態C keep_CC 状態C UnDo_CA 状態A さらに戻る 状態A
46 状態A event_AC 状態C keep_CC 状態C keep_CC 状態C UnDo_CA 状態A
47 状態C event_CA 状態A event_AB 状態B UnDo_BA 状態A さらに戻る 状態A
48 状態C event_CA 状態A event_AB 状態B keep_BB 状態B UnDo_BA 状態A
49 状態C event_CA 状態A event_AC 状態C UnDo_CA 状態A さらに戻る 状態A
50 状態C event_CA 状態A event_AC 状態C keep_CC 状態C UnDo_CA 状態A
51 状態C event_CA 状態A keep_AA 状態A UnDo_AC 状態C さらに戻る 状態C
52 状態C event_CA 状態A keep_AA 状態A keep_AA 状態A UnDo_AC 状態C
53 状態A keep_AA 状態A event_AB 状態B UnDo_BA 状態A さらに戻る 状態A
54 状態A keep_AA 状態A event_AB 状態B keep_BB 状態B UnDo_BA 状態A
55 状態A keep_AA 状態A event_AC 状態C UnDo_CA 状態A さらに戻る 状態A
56 状態A keep_AA 状態A event_AC 状態C keep_CC 状態C UnDo_CA 状態A
57 状態A keep_AA 状態A keep_AA 状態A event_AB 状態B UnDo_BA 状態A
58 状態A keep_AA 状態A keep_AA 状態A event_AC 状態C UnDo_CA 状態A
59 状態B keep_BB 状態B event_BA 状態A UnDo_AB 状態B さらに戻る 状態B
60 状態B keep_BB 状態B event_BA 状態A keep_AA 状態A UnDo_AB 状態B
61 状態B keep_BB 状態B event_BC 状態C event_CB 状態B UnDo_BC 状態C
62 状態B keep_BB 状態B event_BC 状態C event_CA 状態A UnDo_AC 状態C
63 状態B keep_BB 状態B event_BC 状態C UnDo_CB 状態B さらに戻る 状態B
64 状態B keep_BB 状態B event_BC 状態C keep_CC 状態C UnDo_CB 状態B
65 状態B keep_BB 状態B keep_BB 状態B event_BA 状態A UnDo_AB 状態B
66 状態B keep_BB 状態B keep_BB 状態B event_BC 状態C UnDo_CB 状態B
67 状態B keep_BB 状態B keep_BB 状態B keep_BB 状態B Bから戻る 状態B
68 状態C keep_CC 状態C event_CB 状態B event_BA 状態A UnDo_AB 状態B
69 状態C keep_CC 状態C event_CB 状態B event_BC 状態C UnDo_CB 状態B
70 状態C keep_CC 状態C event_CB 状態B UnDo_BC 状態C さらに戻る 状態C
71 状態C keep_CC 状態C event_CB 状態B keep_BB 状態B UnDo_BC 状態C
72 状態C keep_CC 状態C event_CA 状態A event_AB 状態B UnDo_BA 状態A
73 状態C keep_CC 状態C event_CA 状態A event_AC 状態C UnDo_CA 状態A
74 状態C keep_CC 状態C event_CA 状態A UnDo_AC 状態C さらに戻る 状態C
75 状態C keep_CC 状態C event_CA 状態A keep_AA 状態A UnDo_AC 状態C
76 状態C keep_CC 状態C keep_CC 状態C event_CB 状態B UnDo_BC 状態C
77 状態C keep_CC 状態C keep_CC 状態C event_CA 状態A UnDo_AC 状態C
  • さらに戻る操作が無効であることのテスト
  • 戻る操作をした後の、次の状態遷移テスト
  • 遷移しない操作の後の、戻る操作で、戻るかどうかのテスト(2024/3/3 追加)

がテストできるようになりました。

ここで注意が必要なのは、開始状態でリセット処理が必要になる点です。最初のモデルも2つ目のモデルも、テスト件数分だけリセット処理(例えば、ブラウザの履歴削除や電源OffOnなど)を入れないと開始状態にならないので、仮にバグらしきものが見つかった場合、再現しないなどに陥る要因になる時があります。
自動テストにしておいて、毎回ブラウザをプロセス再起動するなど
で対応している場合は良いのですが、手動テストになると、大変な作業です。

図は、MagicPodのブラウザ起動オプションの例
magicpod001.png

3状態のモデルをそのまま流用(事例3)

3つ目に紹介する状態遷移図は、最初に3状態で記載したものをそのまま使い、生成したテストケースは、終了状態が、次の開始状態になるように、並べ替えて使うというものです。
テストケース生成も、0-スイッチで生成したので、3つの事例の中では、一番軽いものになりました。

testID 開始状態 操作1 終了状態
1 状態A event_AB 状態aB
2 状態aB UnDo_BA 状態bA
3 状態bA keep_AA 状態bA
4 状態bA event_AC 状態aC
5 状態aC UnDo_CA 状態cA
6 状態cA リセット 状態Bで起動
7 状態B event_BC 状態bC
8 状態bC UnDo_CB 状態cB
9 状態cB keep_BB 状態cB
10 状態cB event_BC 状態bC
11 状態bC keep_CC 状態bC

testID 1の終了状態がtestID 2の開始状態になるように並べ替えてテストします。
実行順序に依存したテストである点、例えば、途中のtestIDでバグが見つかった場合、以降のテストができなくなることはあり得ます。
どうしても一筆書きでテストを並べられなかった場合は、途中にリセット操作が挟まる場合もあります。(testID 6)
一番軽いテストである点、手動テストに向いていると思います。
開始状態(起動した後、利用開始直後 など)が、状態A / 状態B / 状態C であるかの確認もできますね。

まとめ

今回は直前のみ覚える仕様で考えましたが、2回前を覚えたり、操作によって、覚えたり・覚えなかったりする仕様もあり得ます。

状態が3つだけなんてことも、実際には無いですね。2回前まで覚えるなら操作の数と状態の数は増えます、結果的に生成されるテストケース数も増えます。

事例3のように、旨くは並べ替えられなくて、途中のリセット操作が増えるかもしれませんね。

状態が再現されているかどうかの確認は、単純に画面表示だけでは無いこともあります。(APIの戻り値を確認する等)

完成度によっては、0-スイッチで期待通りに動くかどうかを見てから、さらに状態遷移していくテストをした方が近道という場合もあります。

正しい状態遷移図を描くことが目的では無く、限られた時間などのリソース内で、いかに効果的なテストをしていくかで、テストやプロジェクト全体の進捗が左右されることが多いです。

いろんなプロジェクトでソフトウェアテストをする経験を重ねると、様々なバグに遭遇する機会が増えてきて、そんな経験を状態遷移テストに反映させるようなケースがあるかと思います。
モデルを共有して有効なテストをレビューから洗練するツールとしても、GIHOZが使えるかなと思います。

モデル化して、テストの規模感がなんとなく判ってきたら、全てをテストケース生成するのでは無く、
商品やサービスの中で、特に重要な状態やイベントに絞った状態遷移テストを開発者とイメージを合わせてテスト実施というのが現実的です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1