「はじめて学ぶソフトウェアのテスト技法」まとめ①

ソフトウェアの名著として名高い名著「はじめて学ぶソフトウェアのテスト技法」について、重要だと感じたポイントをまとめてみました。


## 第1章　テストのプロセス　

### テストとは何か

テストの定義：
「テストとは、テストされるソフトウェアの品質を測定して改善するために、テストウェアをエンジニアリングし、利用し、保守しながら同時並行的に進めるライフサイクルプロセスである。」（Rick Craig, Stefan Jaskiel）

テストの成熟度には５つのレベルがある。（Boris Beizer）

**レベル0**
「テストとデバッグには何の差もない。デバッグ以外にはテストには特別な目的はない」
欠陥は偶然見つかるかも・・・でもそれを検出する努力はしない。

**レベル1**
「テストの目的は、ソフトウェアが動くことを示すことである」ソフトウェアが（基本的に）正しいという前提から始まっているため、欠陥を見つけ出そうとする我々の眼を曇らせる可能性があります。

**レベル２**
「テストの目的は、ソフトウェアが動かないということを示すことである」ソフトウェアが動かないという前提のため、テスト担当者は欠陥を見つけ出そうと努力しなければならない。

**レベル３**
「テストの目的は、何かを証明することではなく、プログラムが動かないことによって発生する危険性をある許容範囲まで減らすことである」
ここでの目的は、欠陥という観点からソフトウェアの品質を理解し、どれぐらい不完全かという情報をプログラマに提供するとともに、もしシステムを顧客に提供したら、自社にとってどれだけのマイナスがあるのかを経営陣に伝えることです。

**レベル４**
「テストは行動ではない。大袈裟なテストをすることなく品質の高いソフトウェアを作るための精神的な規律である」
このレベルになると、よりテストしやすいソフトウェアを開発することに重点が置かれます。そこには要件定義、設計、コードのレビューとインスペクションまでが含まれます。さらには自己診断可能で、テスト担当者が検出しなくても自らエラーをレポートするようなコードを書くことをも意味します。

### テストケース

きちんと設計されたテストケースは、以下の３つの部分で構成される。
- 入力
- 出力
- 実行の順番

**入力**
キーボード、インターフェースシステムやインターフェース機器からのデータ、ファイルやデータベースからのデータ読みだしなど。

**出力**
コンピュータ―画面に表示されたデータ以外にも、インタフェースシステムや外部機器に送られたデータ、ファイルやデータベースへの書き込みなど。

**実行の順番**
テストケース設計には次の２つのやり方がある。

①順番どおりのテストケース
作成されたテストケースが相互に影響し合っている場合。
例）データベースのテスト（レコードを作成⇒読みだす⇒更新）

②互いに独立なテストケース
各テストケースは相互に依存関係を持っておらず、完全に自己完結しています。
◎良い点：どんな順番でもテストを実行できる。
△難点：テストケースが大きくて複雑になる傾向があり、その設計、作成、メンテナンスが難しくなる。

### テストの種別

**「ホワイトボックステスト」**
テスト対象ソフトウェアの内部パス、構造、実装にもとづいてテストを実施する戦略。テスト担当者はプログラミングの詳細なスキルを必要とする。

**「ブラックボックステスト」**
要件や仕様にもとづいてテストを実施する戦略。
テスト担当者はテスト対象ソフトウェアの内部パス、構造、実装に関する知識を必要としない。

### テストのレベル
テストは通常、次の４つのレベルで実施されます。

**単体テスト**
単体は、開発者が作成するソフトウェアの最も小さい部品を指す。通常、１人のプログラマの作業成果物であり、１個のファイルとして保管される

**結合テスト**
結合テストでは、単体をサブシステム、最終的にはシステムとして統合する。単体としては完全に機能していても、結合すると障害が起こることがある。

**システムテスト**
システムテストは最も高いレベルの結合時に起こる欠陥に焦点を絞っておこなう。

**受け入れテスト**
顧客がソフトウェアを受け入れて行うテスト。

### すべてをテストすることはできない
例えば、次のプログラムをテストする場合・・・

```
int blech (int j) {
  J = J - 1;
  J = j / 30000;
  return j;
}
```

整数が16ビットで実装されていれば、このコードを実行した場合、入力の最小値は-32768、最大値は32767になる。つまり、テストケースは全部で65,536個もあり、全てのテストケースを作成している時間はない。
65,536個のうち、上記の欠陥を見つけてくれるデータは４個だけみたいです。

色々と自分なりに考えてみた結果、以下の４つのテストケースが答えになるようです。

| 入力 | 期待される結果 | 実際の結果 |
|:-:|:-:|:-:|
| -30000 | 0 | -1 |
| -29999 |  0 | -1  |
| 30000  | 1  | 0  |
| 29999  | 1  | 0  |

## 第２章　ケーススタディの説明
※本書の付録に関する説明なので省略

## 第３章　同値クラステスト

### はじめに
同値テストクラスは、**充分なテストカバレッジを保ちながら、テストケースの数を管理可能な程度に減らすための技法の一つ。**

:::note info
※テストカバレッジとは、ソフトウェアテストの進捗を表す尺度の一つで、テスト対象のソースコードのうち、どの程度の割合のコードがテストされたかを表すもの。
:::

例えば、次のような人材管理システムのモジュールを考えてみます。

```
0歳～16歳：雇用しない
16歳～18歳：パートタイムでのみ雇用
18歳～55歳：正社員として雇用
55歳～99歳：雇用しない
```

また、以下に示すようなコードで実装されていると仮定します。
```
If (applicantAge >= 0 && applicantAge <= 16)
	hireStatus = "雇用せず";
If (applicantAge >= 16 && applicantAge <= 18)
	hireStatus = "パート";
If (applicantAge >= 18 && applicantAge <= 55)
	hireStatus = "正社員";
If (applicantAge >= 55 && applicantAge <= 99)
	hireStatus = "雇用せず";
```

※上記のコード例では条件式が不適切ですが、「第4章　境界値テスト」で欠陥のあるコードとして取り上げられており、そこでの伏線として、あえてこのようにしていると考えられます。

**このモジュールを1〜99まで順番にテストする必要はないことは明らか。実はどの値を選んでも、範囲内の他の値と同じく有効。ここで言う範囲のことを同値クラスと呼ぶ。**

したがって、同値クラスは以下の条件を満たす必要がある。

- 同値クラス内のあるテストケースで欠陥が検出された場合には、同じ同値クラスの他のすべてのテストケースで同じ欠陥が検出される
- 同値クラス内のあるテストケースで欠陥が検出されない場合には、同じ同値クラスの他のどのようなテストケースでも欠陥が検出されない

**◎同値クラスを使うと、テストケースの数を大幅に削減できる。**

### 技法の解説

①まず、同値クラスが何かを識別する
②それぞれの同値クラスに対して、テストケースを１つ作成する（時間と予算が許すなら追加で作ってもOK）
③有効値と無効値の両方を入力する（モジュールはどんな入力でも受け付けるように設計されていると想定）

**▼CASE01**  
グーフィーモーゲージ社（Goofy Mortgage Company: GMC）は、収入が月額1,000ドルから 83,333ドルまでの人に対して、住宅ローンの契約を結ぶ。

有効値の入力例：月額1,342ドル
無効値の入力例：月額123ドル、月額90,000ドル

**▼CASE02**
GMCは、個人に対してのみ住宅ローンを結ぶ。企業やトラスト、パートナーシップに対しては提供しない。

有効値の入力例：個人
無効値の入力例：企業、トラスト、パートナーシップ

**▼CASE03**
GMCは、マンション、タウンハウス、一戸建てを対象にしている。メゾネットやトレーラーハウス、樹上ハウス、その他のタイプは取り扱わない。

有効値の入力例：マンション、タウンハウス、一戸建て
無効値の入力例：メゾネットやトレーラーハウス、樹上ハウス

上記の各ケースから、有効な入力項目を同時にテストする「単一」のテストケースを作成します。

**有効なデータ値の組み合わせに対するテストケース**
| 月収 | 申請者 | 住宅のタイプ | 結果 |
|:-:|:-:|:-:|:-:|
|  1,342ドル |  個人 |  マンション |  有効 |

無効値についても、次の表のように同じアプローチを使いたくなりますが、**問題点があります。**

| 月収 | 申請者 | 住宅のタイプ | 結果 |
|:-:|:-:|:-:|:-:|
|  123ドル |  パートナーシップ |  樹上ハウス |  無効 |

**システムがこの入力を無効とみなして拒否した場合には、どの項目が拒否されたのかテスト担当者には判別できない。** また１つの入力項目のエラーが別の項目のエラーを帳消しにしたり、覆い隠したりした結果、無効なデータが有効なデータとして受け入れられる可能性もある。

なので**正しいアプローチは、１回に１つの無効値をテストすること。**

**無効値の項目を１回ごとに変えた１組のテストケース**
| 月収 | 申請者 | 住宅のタイプ | 結果 |
|:-:|:-:|:-:|:-:|
|  **123ドル** | 個人  |  一戸建て |  無効 |
|  1,342ドル |  **企業** | 一戸建て  | 無効  |
|  1,342ドル |  個人 |  **樹上ハウス** | 無効  |

**無効値の項目を１回ごとに変え、さらに有効値も変化させた１組のテストケース**
| 月収 | 申請者 | 住宅のタイプ | 結果 |
|:-:|:-:|:-:|:-:|
|  **123ドル** | 個人  |  一戸建て |  無効 |
|  1,342ドル |  **企業** | マンション  | 無効  |
|  5,432ドル |  個人 |  **樹上ハウス** | 無効  |

## まとめ・感想など
同値クラステストについては、とても単純な手法で、ほとんどの人が無意識のうちに利用しているものです。
改めて、その意義について丁寧に言語化されることで、テスト技法についての理解が深まったと感じました。