見出し画像

テスト技法再訪 -- 境界値分析、状態遷移テスト (T3:Pt2:Ch02)

具体的な題材をまな板に載せて、これをどうテストするか、どの技法をどんな風に使うか、複数のテスト技法を適用してみるとどうなるか、などを考えてみましょう。



題材は『ソフトウェア作法』の「語数を数える」

『ソフトウェア作法』第1章1.4の「語数を数える」を取り上げます。「語」や「語数」を本稿では「ワード」「ワード数」と呼び替えます。

プログラムの仕様

『ソフトウェア作法』で提示されている仕様は:

  • 入力を1文字ずつ読み取り、ワードを数え上げ、入力が終わった後にワード数を出力する。

    • ワード数の初期値は0

    • 出力は、入力中のワード数。実装例では“エラー処理”はない

  • “ワード”の定義。空白文字(スペース(半角スペース)、タブ、改行)以外の任意の文字から成る任意の長さの文字列(Fig.01)。

    • ワードとワードは1文字以上の空白文字で区切られる

Fig.01: 入力と空白文字とワード(非空白文字の並び)

以下の前提事項があります。

  • 入力は、Unix系OSやC系のプログラミング言語で標準入力と呼ばれる「プログラムにとって常に開かれている入力源」
    (従って、「ファイルを開く/閉じる」といった操作はない)

  • 読み込んだ文字がEOFという特殊な値だったら、入力の終わりと判断する


対象の振舞いを詳らかにする

筆者は『ソフトウェア作法』の“解答例”を知ってしまっていますが、極力頭から振り払って一から考えてみます。
(なお、ここでの検討例は「異常時の振舞い」の想定は含んでいません)

「同値クラス」を手がかりに

「どの場合にどんな振舞い/処理をするか」「振舞い/処理を変えるのはどういう場合か」= テスト対象にどんな同値クラスが考えられるか、という観点でテスト対象の振舞いを精細化していきましょう。
なお本稿では昔よく使われていた呼称「同値クラス」を用います。(ISTQB-FL v4.0では「同値パーティション」とのみ呼ばれます([2] 4.2.1))

おさらい・同値分割と同値クラス

同値クラスは、簡単にいうと「これらの要素はテスト対象が同じように扱うから、同じ仲間ね」という集まりのことです。テスト対象の扱い(その要素に対するテスト対象の振舞い)が異なる要素は別の同値クラスに属すると考えます。
入力、出力、内部データの値、時間に関連する値など、ソフトウェアのさまざまな側面についてそれぞれ同値クラスを考えることができます。主に同値分割というテスト技法で用いられる概念です。([2] 4.2.1)

同値分割は他の多くの技法でテストを考える際の基盤にもなっています。私見ですが、テストの技法というよりは「対象の振舞いを場合分けする」という基本的なものの見方と捉えるのが適切なように感じています。(「ひとつの同値クラスからは、たかだかひとつテストすればよい」という割り切りがテスト技法としての同値分割の真髄かなと)

入力自体の同値クラス、入力文字/文字列の同値クラス

入力自体について次の同値クラスEPiが識別できます(Fig.02)。

  • EPi-0: 入力がない(入力が0文字=いきなりEOFを読み取る)

  • EPi-1: 入力がある(入力が1文字以上ある)

Fig.02: 入力自体の同値クラスEpi

“ワード”の定義から入力文字(列)にはふたつの同値クラスがあります(Fig.03)。

  • EPs-0: 空白文字(スペース(半角スペース)、タブ、改行のいずれか)、またそれらのみからなる文字列

  • EPs-1: ワード(非空白文字列)。空白文字を除く文字のみからなる文字列

Fig.03: 入力文字/文字列の同値クラスEps

くどいですが、非空白文字は空白文字の補集合、「空白文字でない文字は非空白文字=ワード」と認識されます(Fig.04)。

Fig.04: 空白文字と非空白文字

(空白文字が0文字以上続く中で)非空白文字に出会ったら、ワード(の始まり)と認識してワード数を加算。ワードが1文字以上続く中で空白文字に出会ったら、ワードが終わったと認識する。という具合に動きます。

ワード数の同値クラス

ブラックボックス視点で見ると、プログラムは入力中のワードを数えるだけです。ワード数によって扱いや処理が変わることはありません。
また、入力中のワード数に関わらず、プログラムは数えたワード数を出力します。ワード数が0でも特別なメッセージを出力するなどはしません。
従って、入力の同値クラスとしても出力の同値クラスとしても、 ワード数はすべてが有効同値クラスと考えることができます(「有効同値クラス」は、ISTQB-FL v4.0では「有効パーティション」)。

  • EPw: 入力中のワード数(0以上)

(。´・ω・)? それで十分でしょうか。

「ワードを数える」というプログラムのロジックを考えると、入力中のワード数=0はやはり“特別な場合”と言えます。「ワードに出会ったらワード数を加算する」という仕事をしないで終わるからです。
その裏返しで、ワード数>=1は「ワードに出会ったらワード数を加算する」というロジックが一度以上働く場合です。

この観点を踏まえると、以下の場合分けがありそうです(Fig.05)。

  • EPw-0: 「ワード数=0」は、「ワードを数える」ことを全くせずに終わる

  • EPw-1: 「ワード数>=1」は、「ワードを数える」を一回以上する。

Fig.05: 入力中のワード数の同値クラスEPw

境界を探そう

出典では「“境界”を狙ってテストするとよいぞ」というのが基本方針になっています。
このプログラムにはどんな境界があるでしょうか。

おさらい・境界値分析

境界値分析は、「同値クラスの境界となる値を見つけ、それをテストケースとして取り上げる」技法です。([2] 4.2.2, [3] 5.2.3)

この技法が適用できるには、その同値クラスが順序集合(順序づけられた集合)である必要があります。
“順序づけられた集合(ordered set)”というのは、集合の任意の2要素の大小関係が定まっている集合のことです(典型例は「連続する数値の範囲」)。この時構成要素の最小値と最大値がその同値クラスの境界(境界値)になります(最小値/最大値は、それぞれ、見つかる場合もあれば見つからない場合もある)。

入力自体(EPi)

  • EPi-0: 入力がない=0文字、が唯一の要素であり、隣接する同値クラスとの境界値でもあります。

  • EPi-1: 入力が1文字、が最小値であり、下限の境界です。
    ただしこれは「入力中のワード数EPw」に含めて考えられます。

入力自体(の長さ)に着目するテストとしては、EPi-0の「入力がない」だけ、となるでしょう。

入力文字(列)(EPs)

EPs-0(空白文字列)、EPs-1(ワード)はどちらも文字の集合ですが、要素が順序づけられてはいません(想定する文字コードによっては「文字を表す数値」に大小関係がありますが、必ずしも連続しているとは限りません)。なので「空白文字の最小値と最大値でテスト」「空白文字と非空白文字の境界を狙ってテスト」という作戦はありません。

境界を考えるなら、それぞれの長さでしょう。EPs-0、EPs-1ともに1文字が最小値であり、下限の境界です。最大値はありません。
空白文字が1文字でもあったら、ワードの区切りと正しく判定してくれなければ困ります。
非空白文字が1文字でもあったら、ワードと認識してくれなければ困ります。

どちらも「有効同値クラス」の外側に長さ0の「無効同値クラス」(=文字列がない)があります。これはワードにとっては意味を成しませんが、最初のワード前の空白文字と、最後のワードの後の空白文字では意味があります(「空白文字列がない」という場合)。もちろんその場合でもプログラムは適切に動作してくれないと困ります。

ワード数(EPw)

EPw-0(ワード数=0)は構成要素がひとつであり、隣接する同値クラスの境界値でもあります。
EPw-1(ワード数>=1)は最小値が下限の境界値になります。上限の境界はありません。

2値BVAと3値BVA

ISO 29119-4やISTQB-FL v4.0では、カバレッジアイテムの違いから2値法(2値BVA)と3値法(3値BVA)の2種が紹介されています。

入力文字列EPs-1を考えると、

  • 2値BVAなら:長さ=1

  • 3値BVAなら:長さ=1, 2

EPsの節で長さ=1の場合を挙げましたが、長さ=2の場合のテストもしておきたいところです。

  • 空白文字を、それが続く間読み飛ばすこと(⇒連続する2文字以上の空白文字)

  • ワード(非空白文字)が続く間、ワードと認識すること(⇒連続する2文字以上の非空白文字)

ワード数EPw-1(ワード数>=1)では、以下がテストケースとして挙がるでしょう。

  • 2値BVAなら:ワード数=1

  • 3値BVAなら:ワード数=1, 2

同値クラスを考える段で、EPw-1は「『ワードに出会ったらワード数を加算する』というロジックが一度以上働く場合」と述べましたが、もう少し考えると、ワード数=1 と ワード数>=2 は、このロジックが働く回数に違いがあります(一度だけか、二度以上か)。

プログラムが最初のワードを認識した後に空白文字に出会っても、もし何かの間違いで(まあ、大抵はバグでしょうけど)「まだワードの続き」と判定したら、ふたつめのワードを加算しそこなう可能性があります。(そしてこの間違い(まあ大抵は……ね)はその後も続き、「ワードがいくつあっても1個」と出力する可能性が)
そう考えると、「空白文字とワードの判定の切り替えが正しく動作している」ことの確認として、ワード数=2の場合はテストしておきたくなりますね。ワードふたつの場合で期待通りに動けば、それ以上は同じ処理の繰り返しですから、同じように動くだろうと見込めます。

このようなループ処理に関わる故障の有無を見つけるには、境界値に加えて「境界の内側」をテストしてみるのがよい場合があります。ISTQB-FL v4.0で解説している「3値BVAは、2値BVAでは見落とされる欠陥を検出する可能性がある」の別例と言えるでしょう。


境界値視点からのテストまとめ

表にまとめます(Fig.06)。

Fig06: 検討結果まとめ(境界値視点)

眺めてみると、「自分がプログラムを書いたら、ここまでやるかな?」という気はします。テスト#2や#5は割愛しそうです。
ワード前後の空白の有無は「前後ともなし、前後ともあり」を合わせてテストするように考えています。またワード数=1で確認したことはワード数=2では省いています。これはテストの手間(テスト実装・実行)と故障が生じた場合の切り分け調査、対応の手間を天秤にかけて、「合わせてテストするのでいいか」という考えが働いています。
半面?、#3、「空白文字は種類が限られているから1種類1文字で分けてテストしてよいのでは?」という気もします。


“答合わせ”

『ソフトウェア作法』では、Fig.07のような場合のテストを挙げ、「これらすべての場合に対して正しかったら、プログラムが正しいことについてはかなりの自信をもってよい」としています。([1] pp.30-31)

Fig.07: 『ソフトウェア作法』の“解答例”と、本稿での検討結果

同書ではワード前後の空白の有無を個別にテストするかどうかについては明言していません。「2語から成る種々の配置」という書きぶりからすると、細かく場合分けするべきと考えている節があります。それに対しては、筆者の検討例は“ざっくり”考えています。


状態遷移テストはどうか?

(実は本稿出発点の意図ではここからが「本番」でした……)
出典では「ワード数を数える」プログラムを状態遷移モデルで考えたと示唆しています。

われわれはwordcountを「語の中」と「語の外」という二つの状態を基礎とするアルゴリズムを使って書いた。もし状態間の遷移を正しく設定し……(後略)

([1] p.30)

実際に、状態遷移モデルを使って表してみましょう(Fig.08)。

Fig.08: 状態遷移モデルで捉えた「ワード数を数える」

状態遷移モデルは、テスト対象の振舞いを視覚化して理解を促進するにはとても有用です。「ワード数を数える」のような比較的単純なプログラムでも、状態遷移図で表せれば動きを把握しやすいことはFig.08で判るかと思います。

状態遷移モデルを適用できるなら、状態遷移テストを考えてみることができます。「“境界”に着目して考えたテスト」と「状態遷移テストを適用して考えたテスト」とでは、その結果にどんな違いが出るでしょうか。

イベント網羅(ISTQB-FL v4.0では「有効遷移カバレッジ」)を意識しながら、境界値視点での検討結果に対応するように考えたものを Fig.09に示します。

Fig.09: 状態遷移テスト(イベント網羅)の検討結果

テスト #7, #8(ワードふたつ)に至らずに、全イベントを実行できることになります(イベント網羅100%なら、STT #2, #4, #5で達成)。

イベント網羅(有効遷移カバレッジ)は「すべての有効なイベントを実行して網羅度100%」とする考え方ですから、この基準を達成することが目的なら、テスト数が境界値視点のものより減るのはおかしくありません。


結び

発端は、この「ワード数を数える」プログラム(に限りません)が“境界”に着目してテストされている一方で、「状態遷移の考え方で作ったよ」とも言っていることでした。じゃあ、状態遷移テストを適用してみたらどうなるだろう……

今回の試みから再確認できた“教訓”は:

①「テスト対象/テスト条件のテストしたい側面に適したテスト技法を選択することが重要」という、当たり前のはなし(´・ω・`)

②(一見①と矛盾して見えるかも知れませんが)「テスト技法は必要に応じて組み合わせて使う」という、これも当たり前のはなし(´・ω・`)

組み合わせるといっても、テスト設計結果に直接反映されることばかりでもないでしょう。
常にそうできるわけでも、常にそうしなければいけないわけでもありませんが、テスト設計をチェックないしレビューするのに状態遷移モデルに当てはめてみるというのは悪くない“組合せ方”に思えます(テストが然るべき遷移イベントを通ることを状態遷移モデルをなぞって確認する)。

今回のプログラムでは動作を切り替える“境界”をテストするのが重要でした。それと併せて、「ワードの外(空白文字(列))」と「ワードの中」のふたつの状態間の遷移が適切になされることが確認できればなお安心です。
境界を意識して考えたテストケースが状態の遷移も満たすことが、状態遷移モデルと照合することで確認できました。もちろん、それで足りなかったら状態遷移テスト視点の出番ということになります。


参考文献・参考情報

刊行文献

  • [1] Brian W.カーニハン, P. J. Plauger (木村泉・訳) 『ソフトウェア作法』 (原著1976, 日本語訳1981) 共立出版

    • 原著 (日本語訳の扉記載の情報に基づく)

    • Software Tools

    • Brian W. Kernighan, P. J. Plauger

    • 1976初版 (Addison-Wesley)

  • [2] International Software Testing Qualifications Board,
    "Certified Tester Foundation Level Syllabus v4.0" (2023)

    • 日本語訳

    • Japan Software Testing Qualifications Board (JSTQB)・訳

    • 『テスト技術者資格制度 Foundation Level シラバス Version 2023V4.0.J01』(2023)

  • [3] ISO/IEC/IEEE 29119-4:2015 "Software and Systems Engineering - Software Testing - Part 4: Test Techniques"

Webページ


(2024-01-15 R001)

この記事が気に入ったらサポートをしてみませんか?