ソフトウェアテスト超基本　これだけは開発者でも知っておきたい

## はじめに
Webアプリエンジニア→QA（テスト自動化なども）というキャリアを経て、開発をしている人でも、ソフトウェアテストについてある程度知っておくとQAと喧嘩になる事も少なくなるのでは…と思いソフトウェアテストの基礎についてまとめてみた。
※「[知識ゼロから学ぶソフトウェアテスト 【改訂版】](#参考文献)」という良書が分かりやすいのでそれを参考にまとめている。

### ソフトウェアテストを行う上での心得
- バグを全部見つけるのは無理だと心得ろ！[^1]
- エラーは見つからないだろうという仮定のもとにテストの計画を立ててはいけない
- プログラムのある部分でエラーがまだ存在している確率は、既にその部分で見つかったエラーの数に比例する（バグはプログラム中に均一に部分布しているわけではなく、特定の部分に偏在している）[^2]

[^1]: 多くのエンジニアは自分が書いたソースコード・自分が関わっている製品にバグがなければいいなという希望的観測を持って開発・テストをしている
[^2]: ある研究によると、バグの47％はプログラムの4％の部分に偏在している、と言われている<br>また別の研究では、80％のバグは20％のコードに含まれている、と言われている

### ソフトウェアテストにおいて重要な事
十分な品質（市場に出しても問題ない）ものにするために、

1. どの部分にバグが出やすいか？
1. バグが出やすい部分にどんなテスト手法を適用するべきか？

という2つの問いの答えを見つける事が重要。
ソフトウェアテスト関連の色々な理論は、この2つの根源的な問いに答え、十分な品質を実現するための理論体系というイメージでいいだろう。
実際、以下の[ソフトウェアテストの手法について](#ソフトウェアテストの手法について)は「どんなテスト手法を適用するべきか？」に関するものである。

### ソフトウェアテストの論理構成は多分こう
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/bbefff05-7ec7-5d22-4b2c-3f955fcb1954.png)

### ソフトウェアテストでよく言われる事
#### マーフィーの法則
- 品質向上のための投資は、投資額が修正にかかる必要を超過するorもっとましな事をすべきだと誰かが言い出すまで増加する<br>→本当に完全な品質のソフトウェアを作るには、無限大の時間・コストが必要<br>→**十分な品質**を目指すべし

#### 時間がない…そんな時のテクニック　同値分析・境界値分析編
同値分析法・境界値分析法できちんとテストケースを作成する事がベストだが、色々な事情でそうは言っても…のような状況はある。
その際には、**良いデータ(値)・悪いデータ(値)**でテストをするとよい。

- 良いデータ
 - ユーザが良く使うようなデータ（よく使うと想定するデータ）
 - そのソフトウェアのプログラムが許す最小のデータ
 - そのソフトウェアのプログラムが許す最大のデータ
 - 0（ゼロ）
- 悪いデータ
 - 非常に小さなデータ（-99999999, 0.0000001など）
 - 非常に大きいデータ（99999999, 109999999）
 - 長いデータ（abcdefghijklmnopqrstuvwxyz.txtなど）
 - ソフトウェアが無効とするデータ

# ソフトウェアテストの手法について
ソフトウェアテスト
├ [ホワイトボックステスト](#ホワイトボックステスト)
│ └ [制御パステスト（カバレッジテスト）](#制御パステストカバレッジテスト)
│ 　 ├ [ステートメントカバレッジ(テスト)](#ステートメントカバレッジテスト)
│ 　 └ [ブランチカバレッジ(テスト)](#ブランチカバレッジテスト)
└ [ブラックボックステスト](#ブラックボックステスト)
　├ [同値分析法(テスト)](#同値分析法テスト)
　├ [境界値分析法(テスト)](#境界値分析法テスト)
　│└ [On-Offポイント法(テスト)](#on-offポイント法テスト)
　├ [デシジョンテーブルテスト](#デシジョンテーブルテスト)
　└ [状態遷移テスト（GUIのテスト）](#状態遷移テストguiのテスト)

# ホワイトボックステスト
プログラムの論理（内部）構造が正しいか？を解析するテストで、ソースコードを見て行うテスト。

## 制御パステスト（カバレッジテスト）
プログラムがどのように振る舞い、どのように制御され実行されるか？をテストする手法。
（フローチャートのロジックツリーをテストするイメージ。）
![フローチャート.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/fe9ca698-d02b-ae35-3fd2-a1d9f0b4853f.png)

| カテゴリ | 内容 |
|:-:|---|
| 基本情報 | ・テスト手法の中では基礎的かつ必須の手法<br>・カバレッジ率(coveragerate)の値の明示化に使われる<br>・（制御パステストによる）カバレッジテストの本質は、フローチャートのロジック（枝分かれ・経路）を通りカバーする事 |
| ネガティブな情報 | ・面倒で皆やりたがらない |

### ステートメントカバレッジ(テスト)
命令文（ステートメント）[^3]を少なくとも1回は実行するテスト手法。

| カテゴリ | 内容 |
|:-:|---|
| ネガティブな情報 | ・非常に弱いテスト（全く役に立たないわけではないものの）<br>・プログラムによっては、ステートメントよりも分岐でのエラーが多く発見されにくい傾向がある<br>・常識的には、ステートメントカバレッジだけでテストを終わらせるのは非常に危険 |

**※注意点**
命令文の処理の正しさを確かめるのがこのステートメントカバレッジテストの本質なので、ただ単に命令文をカバー（呼び出して通過する）だけではあまり意味はない。
ex) 
消費税率10％を上乗せする命令文（処理）があった時に、
処理後の価格が10倍になっていたらNGで、そのために命令文のテスト（ステートメントカバレッジテスト）を実施する。

[^3]: if文の中の普通のロジックコード

### ブランチカバレッジ(テスト)
分岐（if・switch文）に対して、それぞれの判定条件が`true/false`になるような条件を少なくとも1回はテストする手法。
（フローチャートの◇の分岐のYes・Noの両方を少なくとも1回は通るようにするテスト。）

| カテゴリ | 内容 |
|:-:|---|
| 基本情報 | ・ステートメントカバレッジより強い<br>・最低でもブランチカバレッジを実行すべしという学者が大勢 |
| ネガティブな情報 | ・テストの数（テストケース）が多くなる |

**※テストケースが多くなるに対する効果的なアプローチ**
プログラムの全体からある部分だけに対してのみブランチカバレッジを実施するなどして作業コストを減らす
（[バグはプログラムの全体に均一に存在するのではなく、ある特定の部分に存在する傾向がある](#ソフトウェアテストを行う上での心得)）

### カバレッジについて
カバレッジとは、

- ソースコードの全行の内、どれだけの割合がテストでカバー（テストにより実行）されたか？を示す数値

であり、これについて少し整理する。

#### カバレッジ基準
- 一般的には60～90％で十分（と言われている）
- （平均ではあるが）実情としては60％程度のカバレッジで出荷されている
- HP（ヒューレットパッカード社）のデータによれば、低くて20％、高くても80％という調査結果もある

※カバレッジ基準を用いると、時間的に余裕がある場合には、以下のように考える・分析する事もできる
　カバレッジが70％の時、残りの30％がなぜカバーできないのか？
　→これによりソースコードの問題が見つかったりする事もある

#### カバレッジを考える時の注意
[^4]: ループなし・ループ1回・最も典型的なループ回数・最大ループ数に-1,+0,+1した回数、などループ処理を異なるループ回数で実行させる
- あくまでテスト手法の一部なので、〇〇カバレッジテストでカバレッジ〇％にすべきなどの絶対的な目標値はない<br>（振り返りサイクルの中で最適なカバレッジ率を模索する他ない） 
- 以下のようなカバーされない（実行されない）可能性が高いコードが残るリスクがある
 - エラー処理
 - 使われていないコード
- 検出できなバグがある
 - プログラムのループに関するバグ<br>※これは別アプローチ[^4]でテストする or `iterator`を用いてループをなくす
 - 要求仕様自体の誤り・バグ
 - 機能不備のバグ
 - データに関するバグ<br>（排他制御、データベースの処理、外部とのデータ連携）
 - マルチタスクや割り込みに関するバグ 

### TDDについて
アジャイルの流行りとともに、ホワイトボックステストの手法の一種であるTDDで開発する事も多くなってきている。
が、TDDの本質は、

- 確実に品質保証をというよりは、スピード感を持って開発し、度重なる変更に対しても耐性を持つようにする

であり、TDDだけでは「十分な品質」を達成できない[^5]ので注意が必要。
[^5]: TDDはホワイトボックステストの一部しか実施していない

# ブラックボックステスト
プログラムの振る舞いからそのプログラムの正しさを検証するテストで、ソースコードは見ずに、外部から様々な入力・操作行うテスト。
（最も重要で、最も時間を費やすべき、最も簡単なテスト。）
背景にある考え方としては、

- ソフトウェアの仕事は4つ（**入力・出力・計算・保存**）しかなく、その4つの振る舞いをテストすればいい

というもの。この4つの振る舞いをテストする手法として以下に挙げるようなテスト手法がある。
![フローチャート (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/add28d11-8f13-0ed0-3638-05b0278c2ac7.png)

## ブラックボックステストでは何をテストすればいいか？
ブラックボックステストの手法には様々なものがあり、どのテスト手法を使えばいいのか？分からないという事もある。
その場合、以下のような考え方でテストを実施するとよい。これは最もベーシックなテスト戦略でこれだけでも結構なバグを検出でき、十分な品質に大きく近づける。

- もし`入力項目（コンポーネント）`があれば[境界値テスト（同値・境界値を混ぜたテスト）](#同値境界値分析表)を行う
- もし`複数の入力項目（コンポーネント）`があれば[デシジョンテーブルテスト](#デシジョンテーブルテスト)を行う
- もし画面の遷移など`状態が遷移する`ようであれば[状態遷移テスト](##状態遷移テストguiのテスト)を行う

※上記のテストをやってもまだバグが出るようであれば、そのばぐは非機能系のバグであり、その数は非常に少ないはず。
　非機能系のバグではなく機能系のバグが見つかるようであれば、考えられる原因は以下の2つ。

- 境界値テストなどのブラックボックステストのアプローチが間違っている
 - 対策：境界値テストなどのテスト手法を見直しつつ、なぜバグが出るのか？自分の作ったテスト内容を見直す 
- ホワイトボックステストでしか見つからないバグである
 - 対策：一旦は仕方がないと割り切りつつ、ホワイトボックステストの導入を検討する

## 同値分析法・境界値分析法について
2つとも4つの振る舞いの内、`入力・出力`の部分に対するテストで用いられる。

| カテゴリ | 内容 |
|:-:|---|
| 基本情報 | ・ユーザによる様々な入力に対し、ソフトウェアが十分対応できるか？（意図しない動きをしてエラーで止まったりしないか？）を確認する<br>・ここで言う「入力」はネットワーク経由のデータ受信など人による入力以外も含む<br>・テストしなければならないケース数を最小限にしつつも、**より効果的なテスト（多くのバグが見つかるテスト）にするための方法論** |

#### ※補足
以下でそれぞれのテスト手法を見ていくと分かるが、同値分析法のテストケースと境界値分析法のテストケースは同じになる部分が出てくる。
そのため、現場では同値分析・境界値分析を一緒に行い、1つのテストケースにする事が多い。一緒に考えた結果出来上がるテストケースは[ここを参照](#同値境界値分析表)。

### 同値分析法(テスト)
入力値の集まりを同値クラスという部分集合に分割し、その部分集合の中の値は等価（同じもの）と見なしてテストする手法。

#### 何をテストしているのか？
同値クラスではソフトウェアの挙動・振る舞いが期待通り同じであることをテストする。

#### テスト手法の内容詳細
「入力値の集まりを…に分割」というのは、有効同値・無効同値という2つに入力値を振り分ける事で、これによりテストする入力値を決める。

※有効・無効とは？

- 有効：ソフトウェアの仕様の中で正常系（普通に使った時に行われる処理）に該当するものというイメージ。
- 無効：仕様の中で異常系（その使い方は想定されておらずユーザにそれはできない・無効だよを伝えるエラー処理）に該当するものというイメージ。

ex1)　1～999（の自然数）を入力すると素数か判定するが、それ以外だと何もしないソフトウェア
この場合、`有効同値：1～999`、`無効同値：～0と1000～`と考えられる。
したがって、以下のような①～④の入力値がテストケースになる[^同値ex1]。
[^同値ex1]: ①・④：同値クラス内の数値であれば何でもいいので、これらの値は違った値でもOK<br>③：有効同値のテスト値については、一般的に中央値付近のユーザが最も使いそうなものを選ぶという慣例のようなものがある<br>②：0は特殊な値なので有効・無効に関わらず必ずテストすべき
![フローチャート (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/a9671e6e-ea05-7910-d94c-da2e83677b35.png)

ex2)　1～999（の自然数）を2つ(A・Bとする)を入力するとA×Bが出力され、それ以外ではエラーが出力されるソフトウェア
この場合も、A・Bそれぞれについて`有効同値：1～999`、`無効同値：～0と1000～`と考えられる。
今回は2つの値があるが考え方は値が1つの時と全く同じ。テストケースに選ぶ値を考える時は、図の色塗りされている部分のように、その値がどの同値クラスをカバーするものか？を考えると分かりやすい[^塗り絵]。
[^塗り絵]: 塗り絵をするイメージで同値クラス（有効同値・無効同値）をカバーできているか？を考えるという事
今回のテストケースは、以下のような①～④の入力値になる。
![フローチャート (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/1682326a-92f5-1de9-a0b7-3a024c5a03e3.png)

### 境界値分析法(テスト)
ソフトウェアの挙動が変わる境目（有効同値と無効同値の境目）の振る舞いが正しいか？を確認するテスト手法。

#### 何をテストしているのか？
境界値で期待通りにソフトウェアの挙動・振る舞いが変化するか？をテストする。

#### テスト手法の内容詳細
境界値を見極めその値でテストする事が重要になるが、その境界値がどの値であるか？（テストすべき境界値）を決めるには[On-Offポイント法](#on-offポイント法テスト)を用いる。

### On-Offポイント法(テスト)
異なる処理が行われる（挙動になる）一番近い2値をテストする手法。

ex) 1～999（の自然数）を入力すると素数か判定するが、それ以外だと何もしないソフトウェア
この場合は、`0・1`、`999・1000`が処理が変わる境目になるので、この4つの値がテストすべき値になる。

### 同値・境界値分析表
[上記の補足](#補足)で最初に取り上げたが、同値分析・境界値分析をするとテストケースとしては被る部分が出てくる。
そのため、この2つの分析手法をまとめて行い、1つのテストケースを作る事が多いが、それを作るのに使うのが同値・境界値分析表。
![フローチャート (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/2eea859c-4fab-b34e-8449-a2b9fb72537e.png)
この表のように整理すると、上記で取り上げた`ex)のソフトウェア`に対するテストケース（2つの分析手法をまとめて行ってできるもの）としては以下の5つになる。

① 0：ゼロは常にバグになりやすい数。同値・境界値に無関係にテストされるべき値（無効な値の下限）
② 1：有効な値の下限
③ 499：有効な値の中央
④ 999：有効な値の上限
⑤ 1000：無効な値の下限

### デシジョンテーブルテスト
入力値が複数ある時に、その入力値のパターンを全て列挙し、そのパターンごとのソフトウェアの挙動(出力)が期待通りであるか？をチェックするテスト手法。

#### 何をテストしているのか？
入力値の組み合わせで変わるソフトウェアの挙動が期待通りであるか？をテストする。

#### テスト手法の内容詳細
| カテゴリ | 内容 |
|:-:|---|
| 基本情報 | ・項目は少ないが複雑な動きをするソフトウェアではかなり有効 |
| ネガティブな情報 | ・入力項目が多くなると使えない |

「入力値のパターン」とは、以下の例で示すようにソフトウェアは入力値に対して何らかの判定・状態（入力値が有効値or無効値のような）を下すが、その入力値に対して下す判定・状態の組み合わせの事。

ex)　1～999（の自然数）を2つ(A・Bとする)を入力するとA×Bが出力され、それ以外ではエラーが出力されるソフトウェア
まず、2つの入力値に対して判定される可能性のある状況（状態）としては、

1. A・Bともに無効（A・Bともに1～999でなく正しくない）
1. Aは有効だが、Bは無効（Aは1～999で正しいが、Bは1～999でなく正しくない）
1. Aは無効だが、Bは有効（Aは1～999でなく正しくないが、Bは1～999で正しい）
1. A・Bともに有効（A・Bともに1～999で正しい）

の4つである。この4つに対して、ソフトウェアの結果としては、

1. 計算結果を出力
1. 入力エラーを出力

の2つが考えられ、上記の1～4がこの結果のどれに該当するか？のマッピングが作れる。
このように考えて、入力値のパターンに対するソフトウェアの挙動として期待する結果を表にマッピングしたものがデシジョンテーブル。
![フローチャート (5).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/e6e06f8f-f729-10be-4051-bfcdcabd1eb0.png)

※上記の例では一見、同値分析・境界値分析と変わらないように見えてしまうかもしれないが、それらとの違いは**入力値の組み合わせに対する挙動の正しさ**をテストしている部分。

### 状態遷移テスト（GUIのテスト）
ソフトウェアの状態の変化をモデル化してテストする手法。

#### 何をテストしているのか？
あるユーザの操作などのイベントが発生した時に期待通りの状態に遷移するか？をテストする。

#### テスト手法の内容詳細
| カテゴリ | 内容 |
|:-:|---|
| 基本情報 | ・見つかるバグとしては以下のようなもの<br>　＊期待していない状態に遷移するバグ<br>　＊遷移すべきだがしないバグ（ある状態からある状態に遷移しないバグ）<br>・以下のようなものには適している<br>　＊GUIソフトウェア<br>　＊オブジェクト指向ソフトウェア<br>　＊通信プロトコルテスト |
| ネガティブな情報 | ・状態の数が多くなると状態遷移のモデル・図が複雑化し、テスト項目が増えすぎてテストできなくなる |

「状態」について、Word文書を印刷する場面を考えてその意味を解説する。
Wordで印刷をする時、印刷ボタンをクリック(ctrl+P)で印刷ダイアログが開くが、この時ソフトウェアの状態は、

- 編集（入力操作）状態 → ダイアログ操作状態

のように変化している。 印刷ダイアログが表示されている時は、Word文書の編集をする事はできない。

このように、ソフトウェアは常に同じ状態にあるわけではなく、状態を変化させてユーザの操作を簡単にしたり、ソフトウェアの仕様が複雑化しないようにしている。ある程度ユーザの操作に制限をかけるために状態遷移があると言っても過言ではない。

[^ページ遷移]: ソフトウェア上でできる操作が制限されたある状態に切り替わる事とも言える
ex) 
何かの申請をする時に、
ログイン画面 → ダッシュボード画面 → 入力画面 → 確認画面 → 申請完了画面
のようにページ遷移[^ページ遷移]をしてソフトウェアを使うようになっている

## 参考文献
- [知識ゼロから学ぶソフトウェアテスト 【改訂版】](https://www.amazon.co.jp/gp/product/4798130605/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)