「その6」は、3年以上前のこちらです。 www.kzsuzuki.com
Twitterで交わされていた「ユースケーステストのテストカバレッジ」という言葉が気になったので、考えてみました。
ユースケースやユーザーストーリーのテストカバレッジを考えるとき、カバレッジの段階にはC0, C1, C2みたいな呼び方はあるのかな。具体的には、 (1) のみを満たしたカバレッジに何か名前はついてる?
— tsuemura (@tsueeemura) 2023年11月5日
1. 基本的な振る舞い
2. 代替の振る舞い
3. エラー時の振る舞い
もしかすると、同じようなこと(というかもっと優れたこと)を言っている文献があるかもしれませんが、調べていません! 議論のきっかけになり、ついでに良い資料なども知ることができればなと他力本願です。
またこの記事では、ユースケース、パス、シナリオ、フローといった言葉を、きっちり定義・区別していない点にも注意してください(開き直っている)。
用語定義の考え方については、以下のスライドが1つの提案として面白いです。
ユースケーステストの定義
おなじみ、JSTQBのテストアナリストシラバスから引用してみます。
3.2.7 ユースケーステスト
ユースケーステストは、ユースケースで具体的にした、コンポーネントまたはシステムの意図される使われ方をエミュレートするトランザクションベースおよびシナリオベースのテストを可能にする。何らかのゴールを達成するために、アクターと、コンポーネントまたはシステムとの間の相互作用の観点でユースケースを定義する。アクターとしては、ユーザー、外部ハードウェア、またはその他のコンポーネントやシステムを挙げることができる。
正直、文章で理解するのは困難ですね・・・。
まず、ユースケースから押さえていきましょう。
ユースケース
『UMLモデリング入門』では、「ユースケース」を以下のように定義しています*1。
アクター(行為者)が仕事を遂行するために使用する手段であり、アクターと「システム」との対話として表わしたもの。
ポイントとなるのは、「システムの機能」ではなく、「アクターとシステムの対話」に注目していることです。
次に、『はじめて学ぶソフトウェアのテスト技法』の第9章、「ユースケーステスト」で提示されるユースケース記述の例を見てみます。
ただし説明の都合上、一部を簡略化・改変*2しています。
ユースケースの構成要素 | 説明 |
---|---|
ユースケース名 | 科目への登録 |
主アクター | 学生 |
事前条件 | なし |
成功時の事後条件 | 学生が当該科目に登録される |
失敗時の自己条件 | 学生が当該科目に登録されない |
トリガー | 学生が科目を選択し、「登録」する。 |
主成功シナリオ A: アクター S: システム |
(1)A: 「科目の登録」を選択する (2)S: 科目の一覧を表示する (3)A: 科目を選択する (4)S: 受講可能なクラスを表示する (5)A: クラスを選択する (6)S: 選択したクラスの曜日と時間を表示する (7)A: 受け入れる (8)S: 科目・クラスを学生の科目リストに追加する |
拡張シナリオ | (3a) 科目が存在しない S: メッセージを表示し(2)に戻る (5a) クラスが存在しない S: メッセージを表示し(4)に戻る (5b) クラスが定員いっぱい S: メッセージを表示し(4)に戻る (7a) 学生が受け入れない S: メッセージを表示し(2)に戻る |
この例からもわかるように、アクターとシステムの相互作用が表現されています。
また、一番メインと考えられる「主成功シナリオ」に加えて、それ以外の「拡張シナリオ」が記載されています。後者は、サブ的な成功シナリオである「代替シナリオ」や、失敗にぶつかる「例外シナリオ」に分けて記述されることもあります。
これらのシナリオをテストしていくのが、ユースケーステストということになります。
たとえば、主成功シナリオを(1)から(8)まで通すのが、ユースケーステストにおける1つのテストケースと言えます。
ユースケーステストのカバレッジ
では、ユースケーステストのカバレッジを、どのように考えていけばいいでしょうか。
ここでは、2つに分けて考えてみます。1つは、データレベルのカバレッジ。もう1つが、シナリオレベルのカバレッジです。
なお、この辺はわたしの独自定義です。厳密なものではないので、雰囲気で読んでください。
データレベルのカバレッジ
「ある1つのシナリオに対して、必要となるデータセットのうちどれだけが実行できたか」が、データレベルのカバレッジです。
『はじめて学ぶソフトウェアのテスト技法』を再度引いてみます。「カバレッジ」という言葉は直接は出てきませんが、以下のように説明されています。
この実装をテストする基本的なルールは次の通りです。すなわち、主成功シナリオに対して少なくとも1つのテストケースを作成し、拡張のシナリオのそれぞれに少なくとも1つのテストケースを作成することです。
ここで「少なくとも」という言葉が出てくることに注意しましょう。
ユースケースは入力データを規定していないので、テスト担当者がそれを選択する必要があります。通常は、ここまでの章で紹介した同値分割と境界値分析の技法を利用します。
シナリオを、ハイレベルテストケースと考えるとわかりやすいでしょう。主成功シナリオは1本ですが、そのシナリオを通すためのデータのバリエーションは1つではなく、そのバリエーションごとにローレベルテストケースを作成できる、ということになります。
シナリオレベルのカバレッジ
「ある1つのユースケース記述に対して、必要となるテストシナリオのうちどれだけが実行できたか」が、シナリオレベルのカバレッジです。
では、「必要となるテストシナリオ」はどのように定義すればいいでしょうか。
いくつかのレベルに分けて考えていきます。
(3)以降は、コードカバレッジからの連想でユースケーステストのカバレッジ基準を考えた、思考実験に近いものです。コードカバレッジについては以下の記事を参考にしてください。
www.kzsuzuki.com
(1)主成功シナリオ
カバレッジの分母は、主成功シナリオの数です。原則として1個。
もっとも弱いカバレッジ基準と言っていいでしょう。
(2)主成功シナリオ+拡張シナリオ
カバレッジの分母は、主成功シナリオおよび拡張シナリオの数です。今回の例では、主成功1+拡張4で、5個のシナリオが対象になります。
ユースケーステストにおいて、最低限のカバレッジ基準です。
拡張シナリオを代替シナリオと例外シナリオに分けて、基準を区分してもいいかもしれません。
(3)条件判定網羅的なシナリオ
カバレッジの分母は、主成功と拡張の分岐における判定の組み合わせの数です。
わかりづらいですね。具体例で考えましょう。
今回の例をフローチャートにすると以下のようになります。
4つの分岐があるので、判定の組み合わせは24=16のパターンがあります。そのうち5つは、(2)ですでにカバーされています。
カバーされていないのはたとえば、「選んだ科目が存在しなかったので戻って科目を選び直し、新しく選んだ科目から選んだクラスが存在しなかったので戻ってクラスを選び直し、そのクラスが満員だったのでさらに別のクラスを選び直し、最後の確認画面で受け入れなかったので最初に戻る」というシナリオです*3。
このように、このカバレッジ基準では、「複数の代替パスを通る」ようなシナリオをカバーすることができます。
(4)経路網羅的なシナリオ
カバレッジの分母は、基準とするループ回数の数です。
今回の例ではFOR・WHILE的なループはないのですが、前方に戻るIF文があるので、これをループを見なしましょう。
ループ回数の基準を「2回」と決めたとすると、4つのある分岐でそれぞれ「戻らない」「1回戻る」「2回戻る」シナリオがありうるので、4×3=12のパターンがあります。そのうち8つ*4は、(2)でカバーされています。
カバーされていないのはたとえば、「選んだクラスが満員だったので別のクラスを選んだら、そのクラスも満員だった」というシナリオです。 このように、このカバレッジ基準では、「同じ代替パスを複数回通る」ようなシナリオをカバーすることができます。
(5)さらに複雑なシナリオ
(3)と(4)を組み合わせることで、複雑なシナリオは無数に生成することができるでしょう。
ただ、そのカバレッジを高めても、費用対効果は低そうです。
ユースケーステストは「きれいなシナリオ」?
さて、ここまで見てきたシナリオはどれも、「整理された無駄のないユースケース記述から機械的に導出可能な、きれいなシナリオ」のように思えます。これでシナリオは十分と言えるのでしょうか?
JSTQBシラバスでは、以下のように言っています。
ユースケースは、ガイドラインとしてとらえるべきであるが、要件のセット全体を明確に定義するものではない可能性があるため、テストすべき内容を完全に定義するものとはならない
また秋山浩一さんは、シナリオテストの説明において、このようにおっしゃっています。
当然のことながら単純な物語ではすんなり通りバグ発見にはつながりません。
— あきやま🍠 (@akiyama924) 2016年6月14日
ですから、シナリオテストでは、ゴールを達成するまでの物語にいくつもの乗り越えるべき障害物を盛り込んでおきます。
上述のユースケース記述の例でも「シナリオ」という言葉が出てきますし、「ユースケースシナリオ」という用語もあったりするのでややこしいのですが、ユースケーステストとシナリオテストは別モノであるとされることが多いように思います。たとえば、以下のTogetter。 togetter.com
以上をまとめると、「ユースケーステストからシナリオを導くことはできるが、シナリオテストで行うべきシナリオとしては不十分」という、面倒な話になります。
Michael Bolton氏の『Scenarios Ain’t Just Use cases』というブログ記事では、Cem Kaner氏の言葉を引いています。翻訳はわたしによるものです。 developsense.com
a scenario test has several characteristics: it is motivating, in that stakeholders would push to fix problems that the test revealed; credible, in that it not only could happen, but that things like it could probably happen; that it involves complexity in terms of use, environments, or data.
シナリオテストにはいくつかの特徴がある。
・そのテストで明らかになった問題は、ステークホルダーも修正を推すだろうと意味で、モチベーションを与える。
・単に「起こる可能性がある」というだけでなく、「おそらく起こるだろう」と言えるという意味で、信頼性がある。
・利用方法、環境、データの観点から、複雑さを有している。
この2点目、3点目に注目してください。氏は、ユースケースから直接得られる「手順1→手順2→手順3→手順4→手順5」のようなものを「シナリオ」と呼ぶのは、シナリオの可能性を狭めているとしています。
では、彼のいう現実世界のシナリオとはいかなるものか。その例が、以下です。
- do 1
- start 2
- respond to one email, and delete a bunch of get-rich-quick offers
- resume 2
- take a phone call from the dog grooming studio; Fluffy will be ready at 4:30
- realize they’ve lost track of what they were doing in 2
- go back to 1
- restart 2
- look up some figures in Excel
- place a pizza order for the lunchtime meeting
- finish 2
- go to 3
(以下略、全56行)
本質的にはたった5つしかない手順なのに、それを達成するためのステップが50以上もあるのです。しかも、「作業中に電話がきて」とか「ピザを注文して」とか、一見システムとは何の関係もありません。が、「おそらく起こるだろう」「複雑な」シナリオと言えるでしょう。
ピザを注文している間に、手順2の画面がタイムアウトしているかもしれません。そこまでの入力は、どうなっているのでしょうか? 何か問題が見つかるかもしれません。でもこのようなシナリオは、単純にユースケース記述をカバーするだけでは出てこないのです。
秋山さんのツイに通じるところのあるこのようなシナリオは、ユースケース記述から論理的に導けるものではないですし、カバレッジを考えることも難しいでしょう。
やはりわたしたちには、シナリオテストを設計するための方法論が必要ということになります(結論)。