はじめてのソフトウェアテスト技法【全てのエンジニアが知るべき最重要テスト技法を、丁寧な解説と演習問題で身につけよう】の覚書

https://www.udemy.com/course/software-test-design/
↑これを見ながらメモったことをまとめておきます。

## ソフトウェアテストとは
ソフトウェアの品質保証のための手段。
エンジニアが予想した通りにソフトウェアが動くことを確認する。

* ソフトウェアテストの分類例  
ユニットテスト：メソッド(モジュール)単位  
統合テスト：メソッド(モジュール)の組み合わせのテスト  
UI/システムテスト：DB,UI部品を組み合わせたテスト

## ソフトウェアテスト技法
テストケースは多いほど信頼できるけど
「完璧なテストはできない」
→少しでも多くのバグを見つけるための技術が**ソフトウェアテスト技法**

>現実的に実行できるレベルの量までテストケースを削減し、少ないテストケースで品質保証できるような最適なテストケースを設計するための知識,手段

**技術**であって,**目的**ではない！！

### テストの例
* 同値クラステスト
* 境界値テスト
* ドメイン分析テスト
* デシジョンテーブル
* ペア構成テスト
* 状態遷移テスト


## ソフトウェアテストの考え方
「**網羅性**」：抜け漏れをなるべくなくす
「**ピンポイント**」：怪しいところを入念に

怪しいところを見つけるには
①間、逆、類推、外側
②意地悪な条件
③当たり前を疑う
を考える。

1. **契約によるテスト**  
事前条件(メソッドが正しく呼び出される際の条件)の範囲内だけを考える
2. **防御的テスト**  
事前条件の範囲外も調べる

## テスト設計アプローチ

→どっちでやるかは明確に！

* **同値クラステスト**  
「同値クラス」：テスト的には同じ意味になる値のこと
* **境界値テスト**  
同値クラスの境界とその前後を調べるテスト。  
「境界値にはバグが潜みやすい」という考え。  

「欠陥は他の欠陥を隠す」→1つずつ見つけて繰り返し修正していく

複雑な論理を扱うケース→条件(変数)が多いので、漏れが出やすい場合
問題の性質を考えた上でテストケースを考えていく

* **ドメイン分析テスト**
条件同士が相互作用を持つ場合
4つのポイント「on」(境界上)「off」(境界に隣接する値で開集合の方)「in」(ドメイン内)「out」(ドメイン外)
境界値テストはon/offポイントのテストとも言えることも
「ドメインテストマトリクス」on/off/in→1つの条件以外はinポイントにして検証
→列がそのままテストケースになるので便利。

* **デシジョンテーブル**
複数条件が論理式で結ばれている場合
単純に、組み合わせは2^条件数
→条件に従って指数関数的にテストケースが増えていく。
テストケースは圧縮できる場合がある。
→条件判定の順番がわかっていれば圧縮できる。

* **ペア構成テスト**
「条件のすべてのペアをテストする」
例えば、３つの条件であれば、すべての組み合わせは2^3=8通り→2^N
すべてのペアは3C2=3通り→それぞれのペアだけを見て網羅できていればよい。
根拠は、ほとんどの欠陥が「**シングルモード欠陥**」(モジュール単体がおかしい)「**ダブルモード欠陥**」(2つのモジュールの組み合わせによる欠陥)→70～85％らしい。
**直行表**を書く、というか使う。→作られているものから選ぶ。
①条件の洗い出し→②条件値の数→③直交表の選択(なければ大きめ)→④テスト条件を当てはめる
PICTとかを使うと直交表を使わなくても行ける
※重要な組み合わせやバグがありそうな組み合わせはさらに追加テストが必要！

* **状態遷移テスト**
「現在の状態とその遷移でふるまいが変わるようなソフトウェアをテストする」
状態遷移図：状態、遷移、イベント
→最低限すべての遷移をテストする必要→すべての状態は必然的にテストされる
→でも、仕様にない動作に対策が必要。N/A(Not Applicable)も含めてテスト
**状態遷移表**：状態とイベントから遷移を考える
→仕様の抜け漏れもチェックできる
遷移が2段階についてはテストできていない→内部状態が変わっている場合もある
* **Nスイッチカバレッジ**
**関係行列**：前状態、後状態が行と列を意味し、要素はイベント
行列とみなして2乗→1スイッチカバレッジ(経由状態を1スイッチ)
スイッチがN個ならNスイッチカバレッジ→関係行列をN+1乗する

## カバレッジについて

* **ブラックボックステスト**：コード内部のロジックを考慮しないで仕様だけからテストケースを作る

* **ホワイトボックステスト**：コード内部のロジックを考慮してテストケースを設計(コードを読める前提
「**データフローテスト**」: 変数の「生成→使用→廃棄」を守っているか。最近はIDE、静的解析ツールがやってくれたりする.
「**制御フローテスト**」: コード中の処理がどれだけ実行されたか。100行あったら100行全てが一度は実行されるようにテストケースを設計。
どの観点でテスト設計をしているかを意識する.

#### カバレッジ
テスト可能なコードのうち、実際にテストされたコードの割合(制御フローテストの考え方に基づく)
※判定式と条件式の区別は大事

* 「**ステートメントカバレッジ**」(命令網羅, C0)  
実行可能な行のうち何行実行したかの割合
* 「**デシジョンカバレッジ**」(判定網羅, C1)  
判定(if文の判定)の分岐をどれだけ網羅したか(if文の判定式が条件式の組み合わせでも1つと考える)→それぞれの判定に限って真偽を網羅する→100%デシジョンカバレッジ⇒100%ステートメントカバレッジ
* 「**コンディションカバレッジ**」(条件網羅, C2)  
条件式の真偽をどれだけ網羅したか→必ずしも、100%C0,C1にはならない
* 「**マルチプルコンディションカバレッジ**」(複合条件網羅, MCC)  
条件式の真偽の組み合わせ全て→2^条件式数→テストケースが多くなりがち
* 「**MC/DC**」(modified condition/decision coverage)  
条件式の真偽の組み合わせを網羅しないで、100%C1,C0を達成する。→andとかorで省略できるから実現可能。→各判定式については、条件式の数+1で行ける。
→**ミッションクリティカル**なソフトウェアに採用されるカバレッジレベルがMC/DC→ミッションクリティカルではないときは、C0かC1が基準

カバレッジの計算はカバレッジ計測ツールを使うと便利


#### 注意点
1. カバレッジが高い⇒品質が保証できている、わけではない
→ゼロ除算とか、コードがない、境界値がおかしい、などはわからない。
2. カバレッジが100%に近づくほど、バグ検出の費用対効果が下がる
→テストケースが多くなるほど、徐々にバグが見つかりにくくなる
3. カバレッジの数値が目的になってはいけない
→売上ではない。品質保証のための手段。


## 実際のテスト設計のポイント
1. テストケースはテスト技法の考え方をもとに設計→カバレッジはテストが足りていそうか判断する(まずはテストケースから)
2. 85%程度のカバレッジを「努力目標」に  
Googleでは85%ステートメントカバレッジが1つの目安  
言語による→静的型付け言語(Javaとか)よりも、実行までバグがわからない動的型付け言語(Python)の方がカバレッジを高くすることが多い.  
ミッションクリティカルでない場合は、「ユーザーに使ってもらってバグを見つける」という方針にするのもあり。

* テストの目的を意識→バグを見つけてソフトの品質向上。
* 品質の向上も手段→ソフトはビジネスの成功のための手段。

## 参考
Djangoでのテスト書き方
https://nwpct1.hatenablog.com/entry/how-to-write-unittest-on-django
PICTについて
https://qiita.com/bremen/items/6eceddc534d87fc797cc#:~:text=%E3%80%8CPICT%EF%BC%88Pairwise%20Independent%20Combinatorial%20Testing,%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%EF%BC%88MIT%20License%EF%BC%89%E3%81%A7%E3%81%99%E3%80%82