複数条件が関わる題材を用いてテスト設計から自動テストのケース作成まで考える(前編)

はじめに

本記事はソフトウェアテスト Advent Calendar 2021の22日目の記事です。

今回はとあるお題に対して、テスト設計からテスト実装、そして自動テストまで作成してみることで、私が普段どんなことを意識しているか記述したいと思います。

前編である本記事では、テスト実装までの話を書きます。

発表スライド&発表動画

speakerdeck.com

www.youtube.com

目次

今回のお題

お題:座席順番待ちシステム

因子水準を考える

まずはお題に出てくる要素を抜き出して、因子・水準を考えてみます。なお、本来、「因子・水準」という言葉は直交表由来ですが、後述するデシジョンテーブルにおいて、これにあたる言葉が見当たらなかったので、便宜上用いています。もっと適切な言葉がある場合は教えてくださいませ!

因子水準表

因子水準表を元に全組み合わせを書く

今回のお題の期待値も含めて考えます。

条件と期待値

これを元に、因子水準表に出てくる条件全ての組み合わせを考えてみます。なお本記事では、各水準が排他となる関係である前提で、"◯"と空欄で表記しています。

初期の全組み合わせ(画像は一部であり、右にまだまだ列が続きます)

全組み合わせの総数は、(名前)×(大人の人数)×(子供の人数)×(印刷)= 3×5×5×2 =150通りとなります。

予約番号の印刷を任意にする

150通りもテストしたくはありません。それでは、どのようにしてテストパターンを削減すれば良いでしょうか?

まず、今回の「順番待ちに登録する」が成功するかどうかに関係ない因子「予約番号の印刷」を組み合わせ対象から外すという方法があります。(無則)

因子「予約番号の印刷」の水準は任意のものを選ぶこととする(「-」で表記)

すると、テストパターンの総数は、(名前)×(大人の人数)×(子供の人数)×(印刷)= 3×5×5×1 =75通りとなります。とりあえず半分になりました。

名前に関する条件と人数に関する条件を別表に分ける

次に、名前と人数の組み合わせで予約できるかを網羅的に確認する必要が無さそうなので、それぞれで因子水準表を分けて記述することができます。

名前と人数の因子を別々に記述する

そして、それぞれの表でデシジョンテーブルを作成します。

デシジョンテーブルを分けて作成する

すると、テストパターンの総数は、(名前)+(大人の人数)×(子供の人数)= 3+5×5 =28通りとなります。

名前と人数の条件を掛け合わせる必要もあるのでは?

「別々に記述しましょう」というと、こんな風な疑問を持つ人もいるかもしれません。

反論

このような場合は、「名前も人数も適切でない場合にエラーメッセージが両方出るか確認するテスト」を別途作成しましょう。おそらく、名前も人数も適切でないパターンを1つだけやればよく、それぞれの適切でないパターンを全部やらなくても良いでしょう。なぜならば、全組み合わせをやったことで新たに見つかるバグはあまりないと考えるからです。

例えば、

  • 名前が11文字以上、大人の人数が3名、子供の人数が2名の場合…名前のエラーメッセージと人数のエラーメッセージの両方が出てくる(期待値通りの動作)
  • 名前が11文字以上、大人の人数が3名、子供の人数が3名の場合…人数のエラーメッセージのみが出てくる(期待値と異なる動作)

と、ある場合だけテスト失敗することがあり得るでしょうか?

そのようなケースがあまり無さそうであれば、わざわざ全組み合わせを用いる必要が無さそうです。

そこは、自分一人で判断するのではなく、チームで議論した上で「この組み合わせのテストをやる必要がないよね」と皆で納得した上で削りましょう。

人数の同値クラスを考える

さて、ここまでのデシジョンテーブルで、実は1つ工夫していることがあります。名前の文字数です。

先ほどまでのデシジョンテーブルでは、名前の文字数の水準を「0文字」「1〜10文字」「11文字以上」の3つにしています。

一方で愚直に水準を書くと、「0文字」「1文字」「2文字」「3文字」「4文字」「5文字」「6文字」「7文字」「8文字」「9文字」「10文字」「11文字以上」と12通りになります。*1

これは、同値分割法を利用して、「1文字〜10文字」を有効同値クラスとして判断していたので、3通りに減らすことができたのです。

名前の水準

これと同様に、人数の条件も同値分割法を利用してみましょう。

今回は、下記のようにしました。

人数の同値クラスを考える

こうすることで、「大人の人数」「子供の人数」の水準を、それぞれ5通りから3通りに減らすことができました。

これを元にデシジョンテーブルを書くと、下記のようになります。

人数の同値クラスを考えた上でのデシジョンテーブル

テストパターンの総数は、先ほど作成した、名前に関するデシジョンテーブルと合わせて、(名前)+(大人の人数)×(子供の人数)= 3+3×3 =12通りとなります。

しかし、今回作成したデシジョンテーブルのうち、パターン5で期待値が定まらなくなってしまいました。

これは、実際に選ぶ値によって期待値が変わってしまうためです。例えば、

  • 大人1名、子供1名…予約できる
  • 大人3名、子供2名…予約できない

となります。

このような場合はどうすれば良いでしょうか?

合計人数という因子を追加する

期待値が変わってしまう原因は何か考えると、大人の人数と子供の人数の合計が4名以下なのか5名以上なのかによるものだと分かりました。

そこで、合計人数という因子を新たに作成し、それらとの組み合わせを書いてみることにしました。

合計人数の因子を加えた時のデシジョンテーブル

すると、人数の条件の全組み合わせは(大人の人数)×(子供の人数)×(合計人数)= 3×3×3 =27通りとなってしまいます。

しかし、このデシジョンテーブルにはN/A(Not Applicable, 適用不可)なパターンが数多く存在することが分かります。(禁則)

例えば、パターン2は、「大人の人数が0名」「子供の人数が0名」「合計人数が1〜4名」という水準が選ばれています。しかし、合計人数は0名であり、1〜4名となることはないので、N/Aとしています。

同様に、N/Aの部分は省略して、デシジョンテーブルに記述し直すと、下記のようになります。

N/Aの部分を省略したデシジョンテーブル

ここまでのまとめ

  • 愚直に全て書き出すと150通り
  • 予約番号の印刷は予約登録の期待結果に影響しないため(無則)、因子から除外(150→75通り)
  • 名前の因子と人数の因子を別々に考える(3×5×5=75→3+5×5=28通り)
  • 人数の同値クラスを考える
    • 合計人数という因子も含めてみる(28→3+10=13通り)

次からは、デシジョンテーブルの技法以外との関係について考えてみましょう。(もうちっとだけ続くんじゃ*2

テスト観点との関係性について考える

テストを実行するまでに考えることを整理した概念として、テストプロセスがあります。

参考:ISTQBテスト技術者資格制度 Foundation Level シラバス 日本語版 Version 2018V3.1.J03

ここまでで紹介したデシジョンテーブルはテスト設計技法の1つです。しかし、このテストプロセスでいうとテスト設計の前にテスト分析という考えがあります。そのテスト分析を行う方法の1つに、テスト観点図の作成があります。

ここまででデシジョンテーブルの整理することでテストパターンの削減を行ってきましたが、実はテストプロセスに従ってテスト観点から考えていくことで、最初から簡単化したデシジョンテーブルを作成できるかもしれません。

そこで、テスト観点図の整理と、それぞれのタイミングで書き出していったデシジョンテーブルを照らし合わせてみましょう。

初期のテスト観点

問題にあるアプリの画像の要素をただ書き写しただけのテスト観点は、こんな形で出てくるかもしれません。

初期のテスト観点

このテスト観点をもとにデシジョンテーブルを書こうとすると、初期(150通り)のデシジョンテーブルが最初に書けるでしょう。

無則な観点を削った場合

予約番号の印刷がテスト結果に影響しないと気付いた場合、下記のように、「予約番号の印刷」というブランチを消したテスト観点になるかもしれません。

不要なテスト観点を削った図

このテスト観点をもとにデシジョンテーブルを書こうとすると、予約番号の印刷という因子が省略された(150通り→75通りの)デシジョンテーブルを最初に書くでしょう。

人数の条件でまとめた場合

名前の条件と人数の条件で、それぞれ予約可否の判断が行われると考えた場合、下記のようなテスト観点になるかもしれません。

人数の条件でまとめたテスト観点図

このテスト観点を元に、デシジョンテーブルを作成しようと考えると、最初から名前の条件と人数の条件でそれぞれ別のデシジョンテーブルを作成しよう(3×5×5=75→3+5×5=28通り)と思えたかもしれません。

合計人数の条件を含めた場合

合計人数という概念があると気付いた場合、下記のようなテスト観点になるかもしれません

合計人数の概念も含めたテスト観点図

この観点を元に、デシジョンテーブルを作成しようと考えると、合計人数を因子の1つとして含めたデシジョンテーブルを作成しようと思えたかもしれません。

ここまでに書いたように、テスト観点を整理しておくことで、最初に作成するデシジョンテーブルが整理されたものになっていたかもしれません。

別のテスト技法を用いて考える

今回の人数の条件を、ドメイン分析技法で表現すると下記のようになります。今回は、大人の人数をx、子供の人数をyと置いています。

ドメイン分析技法

なぜドメイン分析技法で表現したかというと、合計人数の変数は大人の人数と子供の人数という2つの変数によって導き出されるからです。

ここから、テストすべき内容を抜き出すと下記のようになります。

ドメイン分析技法で導き出したテストすべき箇所

今回の場合、予約できる範囲内(赤色部分)のうち、線上の値(ONポイント)は有効値なため、無効値となるOFFポイントは外側に置いています。

例えば、大人の人数が1名、子供の人数が3名の場合はONポイントにある有効値であり、大人の人数が2名、子供の人数が3名の場合はOFFポイントにある無効値となります。

これは、人数の条件に関する最終的なデシジョンテーブル(下記の表)のパターン5とパターン6にあたります。

人数の条件に関する最終的なデシジョンテーブル

このように、デシジョンテーブル以外の技法を用いて表現することも可能です。

ただし、ドメイン分析技法はJSTQB AL TAの学習範囲であり、少し応用的な技法なので、まずはデシジョンテーブルから考えた方が良いと思います。*3

ドメイン分析技法はJSTQB AL TAの学習範囲

テスト設計の成果物を元に、テスト実装を行う

ここまでで作成したデシジョンテーブルはテスト設計の成果物です。この成果物を元に、テスト実装としてテスト手順を作成してみます。

今回は、名前の条件に関するデシジョンテーブルを元に、テスト実装を考えてみます。

名前の条件に関するデシジョンテーブル

ここでは通し番号として、表IDの「DT_Name」を追加しています。

次に、このデシジョンテーブルを元に作成したテスト手順を作成します。

テスト実装結果

ここでのポイントがいくつかあります。

ポイント1:テスト設計番号と対応させている

先ほど書いたテスト設計の表IDを用いて、作成したテスト手順がテスト設計のどれにあたるのか表現しています。

例えば、テスト実装の#1は、名前の条件に関するデシジョンテーブルのパターン1「名前が0文字の場合、予約ができない」と対応します。

ポイント2:テスト設計とテスト実装は1:1の関係ではない

テスト実装の#2と#3に注目してください。両方とも、「DT_Name-2」が書かれています。つまり、デシジョンテーブルのパターン2「名前が1〜10文字の場合、予約ができる」のテストになります。

なぜ「DT_Name-2」が2箇所に現れているかというと、「1〜10文字」というまとめ方は同値分割をした際の有効同値クラスであり、これを境界値分析で改めて考えているからです。

このように、テスト設計が1に対して、テスト実装がnになる場合があります。

次に、テスト実装の#2に再度注目してください。ここには「DT_Name-2」の他に、「DT_People-4」も書かれています。これは、別表「人数の条件に関するデシジョンテーブル」のパターン4「大人の人数が1〜3名、子供の人数が0名、合計人数が1〜4名の場合、予約ができる」のテストを指そうとしています。

このように、テスト実装が1に対して、テスト設計がnになる場合もあります。

ポイント3:テスト設計では省略している内容(実装実施時要検討事項)がテスト実装では現れる

テスト実装の#1に注目してください。ポイント1でも書いた通り、このテストでは「名前が0文字の場合、予約ができない」という、DT_Name-1のテストを行うための手順です。

このテスト実装の中で、「2.大人の人数を1名にする」「3.子供の人数を0名にする」「4.「順番待ちに登録」のボタンを押す」というのは、DT_Name-1のテスト条件には含まれていません。ですが、テスト手順から省略することができません。省略してしまうと、期待値を確認できないテストになってしまうからです。

2018年に、にしさんが「実装実施時要検討事項」と命名しています。以降、この概念を「実装実施時要検討事項」と表記します。

テスト実装#1では、「2.大人の人数を1名にする」「3.子供の人数を0名にする」「4.「順番待ちに登録」のボタンを押す」が実装実施時要検討事項になると考えられます。

特に、「大人の人数」「子供の人数」は一見するとテスト条件に見えてしまいますが、あくまでも実装実施時要検討事項です。

これをテスト条件として捉えてしまうと、最初に書いたデシジョンテーブル(150通り)になってしまう可能性があります。

特に、テスト実装(テスト手順)だけが手元にあり、テスト設計をリバースして作成することになった場合、テスト条件なのか実装実施時要検討事項なのか見極めることが大切です。

同様に、複数のテスト設計と紐づいているテスト実装#2については、それぞれのテスト設計によって実装実施時要検討事項が変わっていると考えることができます。

テスト設計ごとのテスト条件と実装実施時要検討事項の使い分け

まとめ

まとめです。

  • デシジョンテーブルの簡単化によって、テストケース数を効率的に減らすことができる
  • テスト観点の整理をしておくことで、最初に作成するデシジョンテーブルがある程度簡単化できている状態を期待できる
  • デシジョンテーブルが唯一の技法ではなく、ドメイン分析技法といった別の技法でも表現ができることがある
  • テスト設計とテスト実装が1:1の関係になるとは限らない
  • 実装実施時要検討事項を意識することで、不要な組み合わせの発生を防ぐことが期待できる

おわりに

ここまで長々と書いてきましたが、最後にお伝えしたいことがあります

  • ここに書いた内容が唯一解ではありません
    • 皆さんが考える解をぜひ知りたいです!
  • ここに書いた内容が確固たるものではありません
    • JSTQBやJISの表記ルールに従ってない部分があります*4
    • 実装実施時要検討事項という概念は、まだきちんとした標準になっているわけではないです*5
  • 業務でもここに書いた全てをドキュメントに残すわけではありません
    • テスト設計の段階でデシジョンテーブルを書いたら、「これを満たすテストを実施」として、テスト手順を細かく記述しないかもしれません

まあ、要はケースバイケースということです。 なので、ここに書いていることを全て信じるのではなく、ここに書いてあることを参考にしつつ、自分なりのテスト設計を模索していただければと思います。

次回、後編では、今回の例を自動化した場合のポイントについて記載します。

参考文献

jstqb.jp

note.com

softest.jp

www.omg.org

speakerdeck.com

note.com

togetter.com

*1:さらに言うと、11文字以上の部分も、「11文字」「12文字」「13文字」…とどんどん水準を増やすことができます

*2:このドラゴンボールネタはどれくらいの人に伝わるんだろうか……?

*3:ちなみに私も、最初はデシジョンテーブルから考えて、「そういえばドメイン分析技法が使えるかも……」と思いつきました。

*4:たとえばJISの表記ルールでは、条件指定部で各パターンで適用したい条件に"Y"、適用しない条件は"N"の表記をしていますし、JSTQB(ISTQB)で参考にしているOMGでは拡張指定の記述として、各パターン内に水準を記入する方式も紹介しています。一方本記事では、各水準が排他となる関係である前提で"◯"と空欄で表記しています。この方法を採用している理由は、全体を見通した時に、それぞれの組み合わせをしているかが記号の埋まり具合ですぐに判断できるからです。("Y"と"N"だと、どのセルも何らかの文字で埋められていおり、書いてある文字を読む必要が出てくるため、全体感が分かりづらいと個人的には感じています。)

*5:個人的には業務でもかなり活用してはいます