ソフトウェアの品質を学びまくる

ソフトウェアの品質、ソフトウェアテストなどについて学んだことを記録するブログです。

モデルベースドテストについて学んでみよう - その3

Mannequins

 前回は、MBTツール「MISTA」でブロックゲームのシンプルなモデルを描いてみて、シミュレーションで一手進めたところまでを見ました。

www.kzsuzuki.com

f:id:kz_suzuki:20200426185300p:plain

トークンとイベントの関係とは

 上の状態から、もう一度pickup(x)を選んで遷移させてみましょう。

f:id:kz_suzuki:20200428045811p:plain

 2つのトークンが、プレースholdingにあります。つまり、「2つのブロックがともに、アームにつかまれているという状態です。
 これは、「一度につかめるブロックは一つだけ」というルールに反していますね。つまりモデルに不備があるということです。

 実はこのファンクションネットが表しているのは、

プレースontableにあるトークンに対し、イベントpickupを行うと、プレースholdingに遷移する

というよりは、

プレースontableにトークンがあるという条件を満たせば、イベントpickupが実行可能になり、プレースholdingに遷移させることができる

だと理解した方が正しいと思います。

 一般的な表現にすると、

  • あるイベントを起こすためには、そのイベントに流入するすべてのプレースにトークンが存在していないといけない
  • そのすべてのトークンは、イベント発生後に、次のプレースに移動する

ということになります。

条件を追加していく

 pickup(x)を実行可能にするために必要な条件を、プレースと矢印で表現する必要があります。その条件は、以下の3つです。

  • ブロックxがテーブルにあること。 →トークンxが、プレースontableにあること。
  • ブロックxの上に他のブロックがないこと。 →トークンxが、プレースclearにあること。
  • アームがブロックをつかんでいないこと。 →任意のトークンanyが、プレースholdingにないこと。

 元のモデルはこれです。先ほどまでといきなり形が変わりましたが、内容は同じです。完成形から逆に図を作っているため、いびつな形になっています。。

f:id:kz_suzuki:20200428051702p:plain

 1つ目の条件は表現されています。2つ目の条件のために、プレースclearを追加しましょう。
 イベントpickup(x)を起こすには、トークンxがプレースontableだけでなくプレースclearにもなくてはならないので、その矢印を引きます。
 また、プレースholdingにあるトークンは、イベントputdown(x)を通じてプレースontableだけでなくclearにも遷移するので、その矢印を引きます。

f:id:kz_suzuki:20200428051740p:plain

 3つ目の条件に行きます。
 「プレースholdingにトークンがあると、イベントpickup(x)が行えない」ということを表現するために、Inhibitor Arc(禁止矢印)を引きます。

f:id:kz_suzuki:20200428051751p:plain

 最後に、ブロックB1とB2の初期状態は、他のブロックの下にないので、アノテーションにも以下を追加します。

INIT ontable(B1), ontable(B2), clear(B1), clear(B2)

 これで、「テーブルからブロックを上げ下げするモデル」はできました。

残りのプレースとイベントも追加する

 あと足りないのは、イベントstack(x, y)unstack(x, y)、プレースonです。

 まずイベントstack(x, y)(ブロックyの上にブロックxを置く)から。
 これを実行するための条件は以下の通りです。

  1. ブロックxがアームにつかまれていること。 →トークンxが、プレースholdingにあること。
  2. ブロックyの上に他のブロックがないこと。 →トークンyが、プレースclearにあること。

 また、乗せたブロックはclearになることも表現する必要があります。
 これらに対応する3つの矢印を引きます。

f:id:kz_suzuki:20200428052716p:plain

 実はもう1つ条件があります。ブロックxとブロックyが別のブロックであるということです。holdingclearは両立するプレースなので、この制約を入れないと、ブロック1の上にブロック2を乗せるというアリエナイ遷移を許してしまいます。変数の関係は、プレースstack(x, y)ガード条件としてx<>yと記載してあります。

 もう1つ、「xがyの上にある」という状態を表現するために、プレースonを追加して、stack(x, y)から遷移する矢印を引きます。

f:id:kz_suzuki:20200428053230p:plain

 乗せた後は、トークンが以下のプレースに移動します。

  • トークンxは、プレースclearon(第1変数)に移る
  • トークンyは、プレースon(第2変数)に移る (すでに矢印を追加済み)

 同じように、イベントunstack(x ,y)(ブロックyの上からブロックxを持ち上げる)も追加しましょう。
 unstack(x, y)に入るための条件は、以下の4つです。

  1. xがyの上に乗っている。 →トークンxyが、プレースon(x, y)にあること。
  2. xの上に何も乗っていない。 →トークンxが、プレースclear(x)にあること。
  3. xとyは別ものであること。 →x<>y *1
  4. アームが何もつかんでいない。 →任意のトークンanyが、プレースholdingにないこと。

 また、unstackが完了すると、トークンxはプレースholdingに、yclearに遷移することも表現します。

f:id:kz_suzuki:20200428053714p:plain

 これでモデルはいったん完成です。
 次回はこのモデルでのシミュレーションと、いよいよテストケース導出をやってみましょう。

www.kzsuzuki.com

*1:1.が満たされればこの条件も自動的に満たされそう。

モデルベースドテストについて学んでみよう - その2

Melissa Adret, Model

 モデルベースドテスト(Model-based Testing、MBT)について学ぶシリーズの第2回です。2018年アドベントカレンダーの2日目でもあります。

www.kzsuzuki.com

 第1回を振り返ってMBTとさくっと説明すると、「要求・仕様に基づいてモデルを描き、そこからテストケースを生成する」というものでした。ISTQBのシラバスを読みながらMBTを理解していくことを考えていましたが、やっぱりツールを使ってみます。

 今回使うのは、「MISTA」というツール。
 クイックガイドに掲載されているモデルを作成してみましょう。

MISTAとは

 Model-based Integration and System Testing Automation の略で、モデルベースのテスト生成ツールです。
 アーカイブはBoise州立大学で配布していたのですが、そのサイトが消えている・・・。もしかするともう公開されていないのかもしれません。

 MISTAの特徴は以下の通りです。

  • 描いたモデルに対し、シミュレーションを行うことができる。
  • モデルから、複数のカバレッジ基準に合わせて、テストケースを自動生成できる。
  • モデルなどの情報から、目的の言語に合わせて実行可能なテストコードを生成し、テスト対象システムで実行することができる。
  • モデルとして、function net、UML protocol state machine、contractsという3つがサポートされている。

 モデルなど、と書きましたが、具体的には以下の3つです。

  1. MISTAで描いたモデルそのもの
  2. モデルと実装を関連付けるMIM(model-inplementation mapping)
  3. プログラミング言語ごとに必要な補助コード

 モデル作成とテストケース生成は1.だけでもできますので、この記事ではそれをやってみましょう。

MISTAでファンクションネットを描いてみる

 上述の通り、MISTAは3つのモデルをサポートしています。5つのものから選ぶのはいい! 3つのものから選ぶのもいい! だが「4つ」のものから選ぶとよくない事が起こるんだ。

 今回は、function net(以降、「ファンクションネット」を使ってみましょう。
 なぜなら、MISTAのデフォルトがファンクションネットですし、もっというとcontractsって何かわからないからです。契約プログラミングの文脈なのでしょうか・・・?

 そうはいっても、ファンクションネットが何かを知らない方もいるでしょう(わたしです)。
 ですので、MISTAでモデルを実装しながら、雰囲気をつかんでいくことにしましょう。わたしも同じ流れで理解しているだけなので、嘘・不正確があったらごめんなさい。

実装する仕様

 ガイドでは、ブロックゲームを例にしています。
 ブロックゲームの概要はこんな感じ。

  • テーブルの上に、複数のブロックが乗っている。
    • テーブルの上に直接乗っているものもあれば、他のブロックの上に乗っているものもある。
  • アームを使ってブロックをつかむことができる。
    • 一度につかめるブロックは一つだけ。
    • 他のブロックの下にあるブロックはつかめない。
  • アームでつかんだブロックは、テーブルの上か、他のブロックに乗せることができる。
  • 初期の配置(INIT)から、指定された配置(GOAL)にもっていくことが目的。

 この仕様から導出される操作は、以下の4つです。

  • pickup(x): ブロックxをテーブルから上げる
  • putdown(x): ブロックxをテーブルに下ろす
  • stack(x, y): ブロックxをブロックyに上に下ろす
  • unstack(x, y): ブロックxをブロックyの上から上げる

 また、ブロックの状態は、以下の4つです。

  • ontable: テーブルの上にある
  • holding: アームがブロックをつかんでいる
  • on: 他のブロックの上にある
  • clear: 他のブロックの下にない

 ものすごくめんどくさかったのですが、がんばって絵を描いてみました。

f:id:kz_suzuki:20200426185237p:plain

 状態遷移図に慣れた人は違和感をもったかもしれません。ブロックの状態同士がMECEではないのでは?と。たとえば、onclearは両立しますよね。
 実はファンクションネットにおいては、これらを「状態」と呼ぶのは適切ではないのですが、説明は後ほどとして、暫定的に「状態」と呼んでおきます。

とりあえず描き始めてみる

 まず、ontableholdingという2つのブロック状態のノードを置いてみましょう。
 ファンクションネットではこのノードのことを、Placeと呼んでいます。この記事では「プレース」と呼ぶことにしましょう。

f:id:kz_suzuki:20200426185241p:plain

 状態遷移図だと、状態と状態の間の矢印が遷移を表しています。
 一方、ファンクションネットにおいては、あるプレースから別のプレースへの遷移の間にイベントのノードを置き、プレースからイベントへ、イベントからプレースへ矢印が引かれます。MISTAではこのノードのことを Transision と呼んでいるのでちょっとややこしいのですが、この記事では以下のように呼びます。

  • トランジション: プレースからプレースへの移動
  • イベント: トランジションを起こす契機となる事象

 テーブルの上にあるブロックをアームで持ち上げて、その後にまたテーブルに下ろすモデルを描いてみましょう。この2つの四角が、イベントです。

f:id:kz_suzuki:20200426185245p:plain

 とりあえず、遷移の輪が閉じました。

変数と初期状態を追加する

 ここでモデル検証のため遷移のシミュレーションをしたいのですが、追加しなくてはならない情報がまだいくつかあります。

 pickup(x)では、テーブルの上にある1個以上のブロックの中から、特定のブロックxを選んで持ち上げることになります。
 ですので、プレースontableからの矢印に「x」というラベルを付けます。プレースholdingに遷移するのも同じブロックですから、そちらの矢印にも「x」を付けます。変数xを受け渡すことで、「持ち上げたブロックと、アームがもっているブロックが同一である」ことを意味しているわけです。

 同じように、putdown(x)に入る矢印、出る矢印にも「x」というラベルを付けます。
 なお、変数のスコープは分かれており、上の遷移のxと下のxは別モノとして扱われます。   f:id:kz_suzuki:20200426185248p:plain

 次に初期状態を指定します。
 モデルの中に Annotation(アノテーション)というものを置き、その中に記述することになります。
 ここでは、2つのブロック「B1」「B2」が、ともにテーブルの上にある(積まれていない)としましょう。
 以下のような記述になります。

INIT ontable(B1), ontable(B2)

f:id:kz_suzuki:20200426185252p:plain

 これでシミュレーションの準備ができました。

モデルのシミュレーション

 シミュレーションを実行してみましょう。実行画面はこんな感じ。
 Simulation Contorol Panel というウィンドウが表示され、モデルも色づいています。

f:id:kz_suzuki:20200426185256p:plain

 モデルの方から見てみましょう。
 プレースの中に、何やら青い点が出現していますね。これを「トークン」と呼びます。ブロックを2つ定義していますので、トークンも(最低)2つあります。初期状態はともにontableとしましたが、それを表現しているのがこのトークンなのです。

 個々のブロックに対応するトークンがその瞬間、どのプレースに配置されているか。実はこれこそが、システムの「状態」と呼ぶべきものです。各ブロックの状態もトークンの配置の組み合わせで表現されるため、プレースは排他である必要がありません。

 赤く塗られたイベントは、この状態で実行可能なイベントです。2つのブロックがともにテーブルの上にある状態なので、アームはどちらかを持ち上げることができます。

 次に、パネルを見てみます。
 左ペインの真ん中に、現在の状態(トークンの配置)が書かれています。
 右ペインのEventフィールドでは、実行可能なイベントが選べます。ここではpickup(x)のみです。Parametersフィールドでは、xに対する値を指定します。ここではB1B2を選ぶことになります。

 ではこの初期状態から、イベントにpickup(x)、パラメタxB1を選んで、Playをクリックしてみましょう。

f:id:kz_suzuki:20200426185300p:plain

 モデル上でトークンが1つ、プレースholdingに遷移していることがわかります。アームにブロックB1がつかまれている状態です。
 この状態では、イベントpickup(x)だけでなくputdown(x)も赤くなっており、実行可能であることがわかります。アームでつかんだブロックB1を下ろせるということです。

 パネルの左を見ると、状態は「B2はテーブル上にあり、B1はアームにつかまれている」ことがわかります。
 また右を見ると、イベントとしてpickup(x)putdown(x)が選択できます。指定できるパラメタはそれぞれ、B2B1です。

 このように、描いたモデルに対しシミュレーションを実行して、想定外の動きにならないか、指定した状態に到達可能か、といった検証を行うことができます。

 次回はこのモデルの問題点を直し、完成させていきましょう。

www.kzsuzuki.com

『ソフトウェアテスト技法 練習帳』のデシジョンテーブルもクリアしたよ。

SAKURAKO - Piano Lesson. [Explored]

 『ソフトウェアテスト技法練習帳』のPart2「デシジョンテーブル」を一通り解き終えました。

 パラメタの単純な組み合わせから得られるフルのデシジョンテーブルから始まって、判定の順番がわかっている場合のテーブルの圧縮(簡単化)を学べるのはもちろんのこと、

  • 2.8: デシジョンテーブルの分割
  • 2.9: テスト設計における仕様不良の特定
  • 2.10: デシジョンテーブルテストにおけるfailからの欠陥箇所推定

という一歩進んだ題材も扱っていて、楽しんで解くことができました。

 なお2.1については一つ疑問が残ったので、メモしておきます。
 まあ、以下のツイートに書いたことがほぼすべてで、秋山さんからもリプライいただいているのでですが。

 2.1は、居酒屋のビールの価格がいくらになるかという問題です。
 仕様は以下の通り。

  • 通常、1杯490円で提供されます。
  • 16:00から17:59まではハッピーアワーのため、1杯290円で提供されます。
  • クーポンを使うと、利用時間にかかわらずはじめの1杯のみ100円で提供されます。
  • ハッピーアワーでもクーポンは利用できます。
  • その時点で最も安い価格で提供されます。 1杯目のビールの価格を表すデシジョンテーブルを作成してください。

 この問題を書き写しているだけで、とっても居酒屋に行きたくなってきました。恋しいぜ外食・・・。

 気を取り直して、解説ではまず、「クーポンありなし」「ハッピーアワー内外」の2値×2の4パターンで、フルのテーブルを導出しています。
 ここまではよいのですが、2.1.3の解説で、以下のように説明しています。

ロジックが明らかで、処理される順番が「クーポン利用」「ハッピーアワー」の場合、デシジョンテーブルは簡単化することができます。簡単化とは、結果が同じ動作になる組合わせがある場合、その組合わせを1つだけ残して、結果に影響を与えない条件を任意の値を表すマークである「-(ハイフン)」に置き換えることです。

 切り取ったこの部分だけ見ると妥当だと思うのですが、仕様をよく考えると、これは適切でない簡略化といえそうです。

 確かに今の仕様においては、ハッピーの290円よりクーポンの100円が安いので、クーポンありならハッピーは「結果に影響を与えない条件」になります。この値段設定が変わらないなら、処理される順番を確かめてテーブルを簡略化してもいいでしょう。

 ですが仕様はあくまでも、「最も安い価格」なのです。クーポンが常に優先される仕様ではありません。
 クーポンありでの価格がたとえば100円から300円になると、今度はハッピーの方が安くなります。この時に、プログラムの処理順を変えるでしょうか?
 そうではなく、ハッピーとクーポンのどちらが安いかを比較して、価格を決定するという実装の方が自然です。つまりこの問題においては、「処理される順番」を仮定すること自体が不自然であるように思えます。よってわたしなら、テーブルの簡略化はしません。

 ということで、「価格は変更されうるパラメタだよな」などと仕様の深読みをしていくのも、本書での「練習」の醍醐味と言えます。テスト設計には必ず唯一解があるわけではないので、著者の方々の提示する解答と異なっていたら、自分の解答の方が妥当だとする根拠を主張して議論する方が面白いですよね!

 なお仕様変更からテーブルアップデートについては、2.9でも扱っています。

JSTQBでいう「テストの目的」を、健康診断のアナロジーで考えてみる。

Global health

 前回の記事では、ISTQBのシラバスに列挙された「テストの目的」の変化について書きました。

www.kzsuzuki.com

 が、そもそもこの項をきちんと熟読していませんでした。
 この記事では「テストの目的」を、健康診断のアナロジーで考えてみたいと思います*1

用語の対比

 まずは、テストと健康診断の用語の対比を考えてみましょう。
 テスト周りにはややこしい用語が多いのですが、まずはドラフトってことで。

テストの言葉 JSTQBの定義 健康診断の言葉
テスト対象(test object) テストすべき作業成果物。 人間の体
テストアイテム(test item) テストプロセスで使用するテスト対象の一部分。 体の各部位
テスト条件 テストのための根拠となる、コンポーネントやシステムのテストが可能な一部分。 検査対象となる体の機能・状態
テスト技法(test technique) テスト条件の定義、テストケースの設計、およびテストデータの明確化をするための手続き。 検査の手法。胃カメラとか。
テストケース(test case) 実行事前条件、入力値、アクション(適用可能な場合)、期待結果、および実行事後条件のセットであり、テスト条件に基づいて開発されたもの。 検査項目
欠陥(defect) 作業成果物に存在する、要件または仕様を満たさない不備または欠点。 症状をもたらす身体上の問題
故障(failure) コンポーネントやシステムが定義された範囲内で要求する機能を実行しないこと。 冷たいものを食べると歯が染みる、といった症状
測定値(measure) 測定することによって、ある実体の特性に付加した数字や種別。 検査で測定できる数値。血圧や歯周ポケットの深さなど

テストアイテムとテスト条件

 テストアイテムもテスト条件については少し前に、湯本さんからこう教えていただきました。

 人間の体も多くの部位・器官に分かれていますが、その部位たちは当然ながら、検査の都合を考えて作られているわけではありません。たとえば鼻と耳は別の部位と見なされますが、「耳鼻科」のようにまとめて扱う方が検査しやすかったりもします。
 同じように、テストアイテムは必ずしもテストの都合に合わせて整理されているわけではなく、テスト条件を導くためには一度、テストのために整理し直す必要があります。

 なお、「耳だけが先にリリースされる」というケースはマレで、人体は一式でdeliver*2されることが多いので、人体のテストはビッグバンテストということができますね。
 また人体の設計は、人間より上位の存在であるプライムベンター(神)から指定されており、ある程度品質は担保されているのですが、誰も使用しない機能があったり、指定したパラメタが何かの拍子で狂ったりすることもあるので、完全とは言い切れないようです。

テストケース

 健康診断の検査項目、たとえば「血圧」を考えてみると、腕のどのあたりに何秒間圧力をかけるか、ということが決まっていますね。入力値、アクションはこれらが該当するでしょう。
 また、各項目には基準値が設定されています。血圧でいうと、「収縮期」の基準は130mmHgとなっています。   

テストの目的と健康診断の目的

 さて、本題に入りますしょう。
 Version3.0の和訳をベースに、3.1を和訳したものが以下です。

  1. 要件、ユーザーストーリー、設計、およびコードなどの作業成果物を評価することで、欠陥の作りこみを防ぐ。
  2. 明確にしたすべての要件を満たしていることを検証する。
  3. テスト対象が完成したことをチェックし、ユーザーやその他ステークホルダーの期待通りの動作内容であることの妥当性確認をする。
  4. テスト対象の品質に対する信頼を積み重ねて、所定のレベルにあることを確証する。
  5. 故障や欠陥を発見することで、不適切なソフトウェア品質のリスクレベルを低減する。
  6. ステークホルダーが意志決定できる、特にテスト対象の品質レベルについての十分な情報を提供する。
  7. 契約上、法律上、または規制上の要件や標準を遵守する、そして/またはテスト対象がそのような要件や標準に準拠していることを検証する。

 それぞれ、意味を考えていきます。

5. 故障や欠陥を発見することで、不適切なソフトウェア品質のリスクレベルを低減する。

 わかりやすいところから行きましょう。
 たとえば歯科検診で虫歯が見つかったとすれば、その歯を治療することになるでしょう。これは、テストケース実行によるバグ*3発見とその改修のイメージですね。

 ちなみに、前回の記事で書いた通り、Version3.1のこの項は、3.0の2つの項目を合わせたものです。3.0では、このようなカッコ補足がありました。

(以前に検出されなかった故障が運用環境で発生するなどの)不適切なソフトウェア品質のリスクレベルを低減する。

 ソフトウェア側が変わっていなくても、環境の違いや時間の経過によって、隠れていた不良が顕在化することがあります。
 たとえばネットワーク通信速度の向上によって、想定していた処理順にならなくなったとか。開発当初は知られていなかった脆弱性が公知となったとか。よって一度リリースしたソフトウェアに対し、継続してテストを行うことは有効です。

 人間の体も加齢に連れてガタが来ますし、検査の技術も向上していきますので、定期的に検査を受けることが大切ですね。

1. 要件、ユーザーストーリー、設計、およびコードなどの作業成果物を評価することで、欠陥の作りこみを防ぐ。

 これも比較的わかりやすいです。
 たとえば、体重が年々増えていき、BMIも悪化している。これが肥満によるものなのであれば、たとえば基準値内だったとしても、悪い傾向を正していく必要がありそうです。

 これは、「技術的負債の蓄積による保守性の悪化」と例えることもできますし、「長時間稼働によるメモリリーク」と例えてもいいかもしれません。また、「開発プロセスの悪化」とも。
 ともあれ、時間の経過によりバグを生んでしまったり障害を発生させてしまったりする前に、対処の必要性を明らかにすることができます。

6. ステークホルダーが意志決定できる、特にテスト対象の品質レベルについての十分な情報を提供する。

 ソフトウェア開発におけるステークホルダーは様々で、開発しているソフトウェアの詳細まで知っている人もいれば、コンセプトくらいまで把握していれば十分という人もいます。ステークホルダーが必要とするレベルに合わせて情報を提供することが大切です。

 わたしの手元にある人間ドックの結果表を見ると、まず「総合判定」が出てきます。これは体全体の評価です。ここで「A」なら、もうその先には特に読まないという人もいるでしょう。
 一方、もっと詳細を気にする(すべき)人もいます。総合判定がたとえば「C」なら、なおさらですね。わたしですが。

 総合判定の次に、各検査の結果が並んでいます。身体計測、視力、眼圧、眼底、聴力、・・・のそれぞれに対し、A~Fが振られています。ソフトウェアでいえば、機能ごとの品質判定になぞらえられるでしょう。
 この後に、「医師の指示事項」が載っています。わたしは「胃部検査で経過観察が必要」とあります*4。これは各機能に対するテスト結果のサマリと言えますね。
 さらにこの後に、各検査項目の詳細が出てきます。先ほど「血液一般」というカテゴリになっていたものは、「白血球数」「赤血球数」「血色素」・・・と詳細になっています。これはテストケースに相当しそうですね。

 このように、レベルを分けて情報を提供し、総合的な情報も、詳細の情報も見られるようになっているのが、よいレポートだと思います。

 なお、健康診断におけるステークホルダーは、まずは自分自身ですね。あと家族。
 会社員なら会社もステークホルダーと言えるかも。

7. 契約上、法律上、または規制上の要件や標準を遵守する、そして/またはテスト対象がそのような要件や標準に準拠していることを検証する。

 ソフトウェアのテストタイプの一つに、標準適合性テスト(compliance testing)があります。たとえば通信関係のソフトウェアに対し、「TCP/IPのRFC規格に準拠した実装になっている」ことを確認するためのテストをしたりします。もちろん手動ではなく、ツールを使った自動テストが多いでしょう。
 またたとえばVMWare関連のプラグインを開発する場合、VMWareの提示するスペックに準拠していることを証明するための認証キットが提供されたりしていますね。
 このような要件・標準を満たしていることを証明することも、テストの目的の一つです。

 健康診断のアナロジーでいうと・・・。
 たとえばパイロットには「身体検査基準」があり、満たすべき視力が設定されています。この場合の検査は、問題を発見することよりも、「基準を満たしていることの証明」が目的になりますね。

www.aeromedical.or.jp

4. テスト対象の品質に対する信頼を積み重ねて、所定のレベルにあることを確証する。

 信頼を積み重ねる、とはなかなか難しい言葉。
 たとえば考えられるテストケースが100件あったとして、20件中20件のpassよりは、90件中90件のpassの方が、そのソフトウェアを信頼できるといえるでしょう。また1回のテストでなく、同じテストを複数回passすることで安心できるようなテストケースもあるでしょう。
 (テスト)空間的、時間的にテストを重ねることで、対象のソフトウェアに対する信頼・安心感は増していきます*5
 健康診断も同様で、幅広く、かつ継続的に検査を受診することで、こちらも安心感が増します。

 ただし、「テストが全部通った」「総合判定がAだった」からといって、ソフトウェアや体に問題がないことの証明になるかというと、そうとは限らないですね。
 テストでいえば、やるべきテストケースが漏れていたかもしれない。テストケースの実行結果に見逃しがあるかもしれない。そもそも必要なテストアイテムを漏らしているかもしれない。
 そうならないように、健康診断の検査やテストの精度を少しずつでも上げていきたいものです。次の#2に通じるものがあります。

2. 明確にしたすべての要件を満たしていることを検証する。

 たとえば肝機能について、「ガンマGTPが51未満であること」ことは要件そのものではなく、「肝機能の働きが正常であると考えるための手がかりの一つ」に過ぎません。「働きが正常である」という判断は、いくつかの角度から観察して初めて、(それでも暫定的に)下すことができます。

 テストにおいても、個々のテストの pass / fail ではなく、それらを束ねて初めて、ソフトウェアや機能が「要件を満たす」を判断することができます。
 逆に言うとテストケースの集合は、「それらをpassすることで要件を満たしていると宣言できるような内容」になっていることが求められます。テスト分析やテスト設計が必要なのは、そのためです。

3. テスト対象が完成したことをチェックし、ユーザーやその他ステークホルダーの期待通りの動作内容であることの妥当性確認をする。

 たとえば発注したソフトウェアのユーザ受け入れテストなどに相当するでしょうか。発注で意図したものが確かにできあがっていることの確認ですね。
 この項目だけはちょっと、健康診断のアナロジーを当てはめづらそうです。健康診断に向けて体を「完成」させるわけではないので・・・。

まとめ

 長くなってしまいましたが、7つもあるテストの目的には大きく、「情報の提供」と「改善への足掛かり」の2つに分かれるようにも見えますね。

  • 情報の提供: 2、3、4、6、7
  • 改善への足掛かり: 1、5

 Version3.0から3.1で、9個から7個に集約されましたが、もう少し整理できそうな気もしています。
 なお2011年版ではとてもシンプルに、以下の4つなのです。

  1. Finding defects
  2. Gaining confidence about the level of quality
  3. Providing information for decision-making
  4. Preventing defects

追記

 ツイッターでいただいたコメントをぶら下げておきます!

*1:インフルエンザの検査のアナロジーを最初考えていたのですが、「インフルエンザの検査を予防的に受ける」というケースがまずないことに気づいて、健康診断にしました。

*2:ソフトウェアのデリバリーdeliveryと、人間の分娩deliveryをかけた高度なギャグです。

*3:「バグ」と「虫」をかけた高度なギャグです。

*4:精密検査済み、良性のモノでした。

*5:限界効用逓減の法則に従うかもしれませんが。

I/JSTQBで述べられている「テストの目的」のちょっとした変化について

Business of Software - DJ Wasabi

 I/JSTQBのシラバスで述べられている「テストの目的」が、Version2018の3.0と3.1で微妙に変わっていることに気づきました。
 まずシラバスへのリンクを貼っておきます。

jstqb.jp www.istqb.org

 このシラバスの1.1.1は「Typical Objectives of Testing」(テストの典型的な目的)を列挙しています。
 2018年6月のバージョンでは、以下の9つです。

2018r3.0

  • B1. To evaluate work products such as requirements, user stories, design, and code
  • B2. To verify whether all specified requirements have been fulfilled
  • B3. To validate whether the test object is complete and works as the users and other stakeholders expect
  • B4. To build confidence in the level of quality of the test object
  • B5. To prevent defects
  • B6. To find failures and defects
  • B7. To provide sufficient information to stakeholders to allow them to make informed decisions, especially regarding the level of quality of the test object
  • B8. To reduce the level of risk of inadequate software quality (e.g., previously undetected failures occurring in operation)
  • B9. To comply with contractual, legal, or regulatory requirements or standards, and/or to verify the test object’s compliance with such requirements or standards

2019年11月のバージョンでは、以下のように、9つから7つに減っています。

2018r3.1

  • C1. To prevent defects by evaluate work products such as requirements, user stories, design, and code
  • C2. To verify whether all specified requirements have been fulfilled
  • C3. To check whether the test object is complete and validate if it works as the users and other stakeholders expect
  • C4. To build confidence in the level of quality of the test object
  • C5. To find defects and failures thus reduce the level of risk of inadequate software quality
  • C6. To provide sufficient information to stakeholders to allow them to make informed decisions, especially regarding the level of quality of the test object
  • C7. To comply with contractual, legal, or regulatory requirements or standards, and/or to verify the test object’s compliance with such requirements or standards

 変更内容を確認するとともに、その意図を推測してみましょう。
 まず、B2・B4・B7・B9はそのまま、C2・C4・C6・C7に引き継がれていますね。
 これ以外の箇所で、大きく分けて2つの変更があります。

validateの意味を明確にしている・・・?

 まずC3は、B3のアップデートです。

  • B3: 「テスト対象が完成したことと、期待通りに動くこと」を validate する。
  • C3: 「テスト対象が完成したこと」を check し、「期待通りに動くこと」を validate する。

 この変更は、ソフトウェアテスト/品質の文脈で、validateという言葉が独特の意味を持っていることを意識しているように思えます。
 ISO/IEC 25000:2014 Systems and software Engineering の定義では、一つ目にこう説明されています。

validation.
(1) confirmation, through the provision of objective evidence, that the requirements for a specific intended use or application have been fulfilled

 たとえば「仕様書通りに作った」ことをもって、「完成」はcheckできるかもしれません。でもこれはvalidateではありません。
 ユーザの要件を仕様に落とし込めていないかもしれない。暗黙の要件を拾い切れていないかもしれない。できたものが、「顧客が本当に必要だったもの」になっているかを確認するのがvalidateです。
 そういう意図から、checkとvalidateを分けたのかなと思いました。

note.com

 なお ISO/IEC/IEEE 24765 では、V&Vを以下のように定義しています。

verification and validation (V&V).
(1) process of determining whether the requirements for a system or component are complete and correct, the products of each development phase fulfill the requirements or conditions imposed by the previous phase, and the final system or component complies with specified requirements

 この定義とC3は、かなり似ているように思えますね。

テストにより積極な意味を持たせている・・・?

 B1「評価する」とB5「欠陥を予防する」が、C1「評価することによって欠陥を予防する」と統合されています。
 同様に、B6「故障と欠陥を見つける」、B8「リスクを下げる」が、C5「欠陥と故障を見つけることで、リスクを下げる」に統合されています。

 これは単に統合したというものではないとわたしは考えています。
 「評価する」「見つける」という段階で終わるのではなく、品質を上げるための積極的なアクションにつなげることも含めてテストの目的である、という意志の表明だと感じます。

 「テストは品質を上げない」という意見もあります。テストでは「バグが見つかった」「バグが見つからなかった」ということがわかるだけで、それに対しアクションを起こさなければ、品質なんて変わらないだということでしょう。
 それは一理あるのですが、「アクションを起こす」まで含めてテストエンジニアの役割なんじゃないの?と思っているわたしには、この皮肉めいた言い方があまり好きではありませんでした。
 完全に自己流解釈ですが、今回の3.1での改訂は、そのモヤモヤを解消してくれるな!と感じています。

日本語版への反映について

 なお、マイナーチェンジのローカライズ(つまり日本語版への反映)については、JSTQBの中のひとである湯本さんから教えていただきました。