ソフトウェアテストの基本#
テストの種類#
粒度による分類#
単体テスト(unit test) :ソフトウェアの最小単位(モジュール)ごとの動作をテストする
結合テスト(integration test) :複数のモジュールを組み合わせて動作をテストする。モジュール間の実行順序も確認する
機能テスト(feature test) :機能として正しく役割を果たせているかを確認するテスト
システムテスト :製品として提供できるかを確認する
テスト観点による分類#
機能テスト :仕様通りの機能が動くかを確認する
例:
正しいID/PWならログインできる
間違ったPWならログインできない
必須項目が空ならエラーになる
非機能テスト :機能そのものではなく、性能・信頼性・安全性などを確認
種類 |
確認内容 |
|---|---|
性能テスト |
応答時間、処理速度 |
負荷テスト |
多数アクセス時に耐えられるか |
セキュリティテスト |
認可漏れ、SQLインジェクションなど |
可用性テスト |
障害時に復旧できるか |
ユーザビリティテスト |
使いやすいか |
互換性テスト |
ブラウザ・OS・端末差異で動くか |
テスト目的による分類#
回帰テスト#
回帰テスト(regression test) :ソフトウェアのコードを変更した際に、その変更が既存の機能に意図しない悪影響(デグレード)を及ぼしていないかを確認するためのテスト
例:
新しい検索条件を追加したあと、既存の検索が壊れていないか
認証処理を修正したあと、通常ログインが動くか
スモークテスト#
スモークテスト(smoke testing) :最低限、アプリが起動して主要機能が動くかをざっくり確認するテスト
例:
アプリが起動する
ログインできる
トップページが表示される
主要APIが200を返す
サニティテスト#
サニティテスト(sanity testing) :特定の修正箇所が妥当そうかを軽く確認するテスト
スモークテストが「全体の最低限確認」なのに対して、サニティテストは「変更箇所周辺の軽い確認」
探索的テスト#
探索的テスト :事前に細かいテストケースを固定せず、テスターが仕様理解や直感を使って不具合を探すテスト
例:
変な入力をしてみる
想定外の順番で画面遷移する
境界値を試す
実ユーザーっぽい操作をする
どれくらい内部構造を見て設計するかによる分類#
ブラックボックステスト#
ブラックボックステスト は内部実装を見ずに、入力と出力だけを見てテストする方法
つまり、関数やAPIや画面の中身がどう実装されているかは気にせず、「この入力をしたら、仕様通りこの結果になるか?」を確認する
技法 |
内容 |
|---|---|
同値分割 |
同じ扱いになる入力をグループ化する |
境界値分析 |
0、1、上限、下限など境界を重点的に試す |
デシジョンテーブル |
条件の組み合わせと結果を表で整理する |
状態遷移テスト |
状態の変化が正しいか確認する |
ユースケーステスト |
実際の利用シナリオで確認する |
Property-based testing#
型定義や制約に沿ってランダムな入力を大量生成し、「常に成り立つべき性質」を検証するテスト。
Pythonだと Hypothesis パッケージがある。
ホワイトボックステスト#
ホワイトボックステスト は内部実装、コード構造、分岐、ループなどを見てテストする方法。
「このコードの分岐や例外処理はちゃんと通っているか?」を確認する。
観点 |
内容 |
|---|---|
命令網羅 |
すべての文が一度は実行されたか |
分岐網羅 |
if/else の各分岐を通ったか |
条件網羅 |
複合条件の各条件が true/false になったか |
パス網羅 |
可能な実行経路を通ったか |
例外経路 |
例外処理やエラーハンドリングを通ったか |
テストの品質#
網羅性#
行カバレッジ
テスト実行時に、コードの各行がどれだけ実行されたかを示す指標。
未テストの処理を見つけるのに有用だが、行が実行されただけで正しく検証されているとは限らない。
分岐カバレッジ
if/else、switch、三項演算子などの分岐がどれだけ網羅されているかを示す指標。行カバレッジよりも、条件分岐のテスト漏れを発見しやすい。
重要機能カバレッジ
ユーザーや業務にとって重要な機能・フローが自動テストで守られているかを見る指標。
単なるコード量ではなく、リスクや業務価値に基づいてテスト対象を評価する。
検出力#
Mutation Score
コードに意図的に小さな変更、つまりミューテーションを加えたときに、テストがその異常を検出できる割合。
カバレッジよりも「テストが本当にバグを見つけられるか」に近い指標。
過去バグ再現テスト数
過去に発生したバグを再現するテストがどれだけ追加されているかを示す指標。
バグ修正時に回帰テストを追加することで、同じ不具合の再発を防ぎやすくなる。
信頼性#
Flaky率
コードを変更していないにもかかわらず、成功したり失敗したりするテスト「Flaky test」の割合。
Flaky test が多いと、開発者がテスト結果を信用しなくなるため、優先的に改善すべき。
再実行成功率
失敗したテストを再実行したときに成功する割合。
再実行で成功するケースが多い場合、テストや環境に不安定要因がある可能性が高い。
効率#
CI実行時間
Pull Request や main ブランチへのマージ時に、自動テストが完了するまでの時間。
長すぎると開発サイクルを遅くするため、テストの分割・並列化・実行対象の最適化が必要になる。
遅いテスト上位
実行時間の長いテストを特定するための指標。
ボトルネックになっているテストを把握し、モック化、データ削減、並列化などの改善につなげる。
保守性#
テストコード量
本番コードに対して、テストコードがどの程度あるかを見る指標。
多ければよいわけではなく、重複が多い、意図が不明、修正コストが高い場合は保守性が低い。
重複
テストデータ作成、セットアップ処理、アサーションなどが繰り返し書かれていないかを見る観点。
重複が多いと、仕様変更時に多数のテストを修正する必要があり、保守コストが上がる。
失敗時の原因特定時間
テストが失敗したときに、原因を特定するまでにかかる時間。
良いテストは、失敗メッセージやテスト名から「何が壊れたか」がすぐ分かる。
運用品質#
本番障害のうちテスト漏れ件数
本番障害の中で、自動テストがあれば検出できたはずの件数。
テスト戦略の弱点を見つけるために有効で、障害後の振り返りで確認するとよい。
PRでの検出件数
Pull Request の段階で、自動テストによって不具合やデグレードを検出できた件数。
自動テストが開発プロセス上どれだけ品質ゲートとして機能しているかを見る指標。
Mutation testing#
Mutation testing は、既存のテストコードの品質を測るためのテスト手法。
わざと本番コードに小さなバグを埋め込んで、「そのバグをテストが検出できるか」を確認する。
Mutation Score#
概ね次のように定量評価する
mutation score = killed mutants / total mutants
用語 |
意味 |
|---|---|
mutant |
意図的に変更されたコード |
killed mutant |
テストが失敗し、検出できた mutant |
survived mutant |
テストが通ってしまい、検出できなかった mutant |
mutation score |
検出できた mutant の割合 |
Pythonでの実践#
Pythonだとpytestでのテストに対し mutmut パッケージでmutation testingが実行できる
pip install mutmut
mutmut run