読書メモ:はじめて学ぶソフトウェアのテスト技法
はじめに
テストと聞くと、ITエンジニアであれば、その業務内容によって、それぞれ思い浮かべることが違うかもしれません。
また、システムインテグレータのテスト担当者やシステム運用の受け入れテスト担当者ならば、徹夜でエクセルシートどおりシステムを動かすという、辛い体験を思い浮かべるかもしれません。
一方、プログラマーならば、ユニットテストや結合テストなどのテストプログラムを想像するかもしれません。
テストという言葉自体が非常に広範であり、エンジニアリング的には抽象的で、具体的な作業内容は、現場によって求められるレベルが違うのが現状だと思います。
今回、評判の良い書籍で「テスト」とは何なのかを体系的に学び直そうと思い「はじめて学ぶソフトウェアのテスト技法」を購入しました。
しかし、原題は、「A Practitioner’s Guide to Software Test Design」となっており、直訳すると「ソフトウェアのテスト設計における実践ガイド」です。
よく技術書のタイトルで「はじめて学ぶ」という言葉がよく使われますが、今回も同様にエンジニアがはじめて学ぶというような内容ではなく、ある程度経験した人の知識の整理に役立つ内容となっていました。
以下、学んだことを章立てで簡単にまとめます。
第1章 テストのプロセス
「テストとは何なのか?」とう定義から入ります。
テストとは、IEEE標準規格610.12-1990で「ある特定の条件下でシステムまたはコンポーネントを操作するプロセスであり、その結果を観察または記録して、システムまたはコンポーネントのある側面を評価すること」と定義されています。
またCraigとJaskielの著書では、「テストとは、テストされるソフトウェアの品質を測定して改善するために、テストウェアをエンジニアリングし、利用し、保守しながら、同時並行的に進めるライフサイクルプロセスである。」としています。
しかし、テスト付け足し扱いにして「安心」するためだけにテストケースを作成するとソフトウェアの完全性という意味で、わずかな保証しか得られません。
最小の時間と労力でエラーを検出する可能性が最も高くなるようにテストケースを作成する必要があります。
テストには、大きく2つのカテゴリーがあります。
- ブラックボックステスト・・・要件や仕様にもとづいてテストを実施する戦略
- ホワイトボックステスト・・・テスト対象の内部パス、構造実装にもとづいてテストを実施する戦略
またテストは、4つの異なるレベルで実施されます。
- 単体テスト・・・プログラム単体のテスト
- 結合テスト・・・各モジュールを組み合わせたテスト
- システムテスト・・・システムを構築した後に実行するテスト
- 受け入れテスト・・・システムの納品時に行うテスト
第2章 ケーススタディの説明
当書籍では、各章末で学んだことを、オンライン証券会社の「ブラウン&ドナルドソン」と「ステートレス大学の登録システム」の2つのケーススタディ(テスト用のシステム)を通して演習できます。
セクション1 ブラックボックステスト技法
ブラックボックステストは、要件と仕様書だけをよりどころにします。
単体、結合、システム、受け入れすべてにおいて適用することができますが、全ての実行パスを実施するこはできません。
以下の章立てで、ブラックボックステストにおける技法を実施して有効なサブセットで最大限の効果を引き出します。
第3章 同値クラステスト
同値クラステストは、十分なテストカバレッジを保ちながら、テストケースの数を管理可能な程度に減らすことができます。
同値クラスは、モジュールで同等に処理されるデータ、あるいは同じ結果を与えるデータの集合を意味します。
クラスの中のどのデータも、テストの観点からは、他のデータと「同じ値」と見なします。
第4章 境界値テスト
同値クラステストと同様に、十分なテストカバレッジを保ちながら、テストケースの数を管理可能な程度に減らすことができます。
境界値テストは、境界に注目するテストです(例えば、100~120円のお菓子を取得するクエリであれば、99円や121円など)。
これらの境界には、沢山の欠陥が潜んでいるのが理由です。
第5章 デシジョンテーブルテスト
デシジョンテーブルは、システムが実装しなければならない複雑なビジネスルールをテーブル形式で記録するのに用います。
デシジョンテーブルの条件、アクション、ルールをテストケースを作成する際の指針に利用します。
- 条件・・・様々な入力条件を表す。
- アクション・・・上記の入力条件が合わさったときに実行される処理(アクション)を表す。
- ルール・・・テストケースに該当する。ルールに従ってテストケースを少なくとも1つは作成する。
条件が2値であれば、各組合せに対して1つのテストケースを用意すれば十分となります。
一方、条件が値の範囲で定義される場合は、範囲の下端と上端の情報のテストを考える必要があります。
第6章 ペア構成テスト
テストをする組み合わせが非常に大きいときに、すべての変数とすべての値をテストすることは現実的ではありません。
変数値のすべてのペアをテストすることで、作成・実行しなければならないテストケースを大幅に減らすことができます。
テストに関する研究成果では、シングルモード欠陥(テスト対象が単に動かない)、ダブルモード欠陥(ある機能の欠陥がペアでおこる)かのどちらかであると事実があり、テストケースの最小のサブセットである「ペア」を構成してテストします。
このペアの構成に、「直行表」を利用します。
オイラーによる数学的な直行表は、公開されているものをダウンロードして利用できます。
全ペアアルゴリズムをつかってアルゴリズム的に導き出すには、オープンソース等で公開されている全ペアアルゴリズム使うことができます。
第7章 状態遷移テスト
状態遷移図を使ってテストを考えます。
状態遷移図は、テストすべき状態、イベント、アクション、遷移を明確にしてくれます。
そのため、テスト作業としての指針として役立ちます。
さらに、外部の世界、システムが処理するイベント、そのイベントの有効・無効な順番などに対して、システムがどう相互作用を持つのか明確にできます。
状態遷移図での抜け漏れを伏せぐために、状態遷移表が役立ちます。
状態遷移図を使ったテストで推奨されるのは、すべての遷移を少なくとも1回実行するような1組のテストケースを作成することです。
リスクの高いシステムでは、全てのパスを網羅する追加のテストケースの作成する方がベターです。
第8章 ドメイン分析テスト
ドメイン分析は、複数の変数を同時にテストするための技法です。
ある種の欠陥は、変数を1つ1つ独自にテストしても検出できません。
これは、ある変数の値が、他の変数が取れる値の範囲を制約するためです。
ドメンイ分析では、上記のような状況を、n次の多次元に拡張して一般化(公式化)し、同値クラステストや境界値テストと同様に、境界値が不正確に定義・実装された状況を見つけることが目的です。
1×1ドメイン分析技法では、一般化(数式化)したものから「ドメインマトリックス」という表を作成し、on/offポイントを選択してテストします。
第9章 ユースケーステスト
UML (Unified Modeling Language) をご存知の方なら、ユースケース図は知っていると思いますが、開発ドキュメントの一部であるユースケースからトランザクションを抽出し、テストをします。
ユースケースは、アクターがある特定の目的を達成するためにシステムをどう使うかを示すシナリオです。
ここで言う「アクター」とはユーザーを意味しています。
ユースケースから、少なくとも1つのテストケースを作成します。
また、ユースケースの拡張にたいして少なくとも1つのテストシナリオを作ります。
これで、ある程度のテストカバレッジを達成できます。
ユースケーステストは、入力データを規定せずに行うため、入力値の組み合わせはほとんど未テストのままであることには注意してください。
セクション2 ホワイトボックステスト技法
ホワイトボックステストは、ソフトウェアの内部パス、構造、実装の知識をよりどころにします。
そのため、プログラミング言語の詳細な知識が必要になります。
単体テスト、結合テスト、システムテストの3つのレベルで適用可能です。
ホワイトボックステストには、全てのパスを実行するのが非現実的になることがあります。
また、パスにないバグは発見できません(変数のオーバーフロー・アンダーフローなど)。
しかし、内部構造に焦点を当てているため、すべてのパスをテストできる利点があります。
テスト担当者に、プログラミング言語に対する高いスキルが求められます。
第10章 制御フローテスト
制御フローテストでは、プログラムコードのモジュール内の実行パスを識別して、それらのパスを網羅するようにテストケースを作成して実行します。
制御フローグラフを制御フローテストの基盤にします。
コードのモジュールをフローグラフに変換し、そのパスを分析します。
テストケースは分析結果に基づいて作成します。
基礎パスの組み合わせが制御フローグラフのすべてのリンクとノードを網羅することから、構造化テストは自動的にブランチカバレッジとステートメントカバレッジを保証します。
第11章 データフローテスト
データフローダイアグラムによって、モジュールの処理の流れを記述します。
また、モジュールのすべての変数に関して、定義、使用、消滅の状態を詳細に示します。
これにより、「定義ー使用ー消滅」のパターンが正しいかどうかを確認します。
よくあるプログラミングの間違いとして、最初に値を代入せずに変数を参照することです(C言語などで該当)。
このような間違いを見つけるために、制御フローグラフと同様にモジュールを通過するパスを列挙し、各変数について、すべての「定義ー使用」のペアを少なくとも1回は網羅するテストケースを作ります。
セクション3 テストのパラダイム
パラダイムとは、ルールと規範であり、境界を明確にし、成功するために境界内でどう行動すればよいか教えてくれるもの、もしくは志向の枠組みであり、現実のいくつかの側面を理解し説明する体系です。
3つのパラダイム(スクリプトテスト・探索的テスト・テストの計画)を章に分けています。
第12章 スクリプトテスト
IEEE標準規格829-1988 「IEEE Standard for Software Test Documentaion」がスクリプトテストを明確に要約しています。
テスト設計仕様書、テストケース仕様書、テスト手順書、テスト項目移管レポート、テストログ、テスト不具合レポート、テストサマリーレポートなど各ドキュメントにまとめて計画してテストを実行します。
第13章 探索的テスト
スクリプトテストでは、計画書に沿ってテストを実施するため、柔軟性にかけたり、終了することが目的になってしまうことがあります。
探索的テストは、フットボールなどのスポーツの試合を行っている選手のように、状況に応じて戦略を変えます。
経験豊かなテストエンジニアが、テスト設計と実行を同時平行に実行し柔軟に進めていきます。
第14章 テストの計画
この章では、スクリプトテストのように計画を立てて順番通りに実行していく方法と、探索的テストのようにテストの実行と設計を同時並行にすすめる適応型計画を比較します。
スクリプトテストにおいても、計画は実行時によって常に変わるものなのでアップデートすることの重要さを説いています。
セクション4 支援技法
支援技法は、テストを「どこから開始するか」「いつ終了するか」等、判断が非常に難しいと状況において、有益なツールになります。
第15章 欠陥の分類
「ISO 9126による品質属性の分類」や、「Beizerによるバグ分類」などをの分類を利用して、欠陥を分類することで、テストの方向性、重要度の決定、開発プロセスの改善、上司や経営者への説明に役立てることができます。
第16章 テストの終了判定
テストを終了するには、終了を判定するには以下のような基準が必要です。
・事前に決めた目標カバレッジを達成
・欠陥検出率が事前に決めたものより下回った
・次の欠陥を見つけるための限界コストが、システムによって発生する損害コストを上回った
・プロジェクトチームによる、リリースのしても良いという合意
・上司による「いいかげんに出荷しろ」との命令
セクション5 最後の考察事項
上記まで、多くのテスト技法を学んできました。
しかし、全ての技法を使おうとしてはいけません。
必要な道具を必要な場面で使える熟練した職人になることが重要です。
まとめ
非常に濃い内容であったため、長くなってしまいました。
有能なプログラマの方や、熟練のテストエンジニアの方なら、仕様から有効なカバレッジを達成しつつテストに対するアクションアイテムを高速で生成できると思うと尊敬の念から頭が上がりません。
また、多くのエンジニアが経験しているかもしれませんが、テスト技法を駆使しないと、テスト項目が多くなりすぎてブラックな職場になったり、質の低いシステムによって運用時に地獄を見ることになることは確かです。
個人的には、ペア構成テストがかなりテストケースを減らすことができるので有用であると思いました。
ここまで読んでくださりありがとうございました。