22章 デベロッパーテスト
moch5oMaki.icon
導入
本章で扱う「テスト」は開発者によるテスト(デベロッパーテスト)を指す。また「ホワイトボックステスト」を中心に話を進める
単体テスト・・・単体のクラスやルーチンなどに対して全体とは切り離した状態で行うテスト
コンポーネントテスト・・・クラス、パッケージなどに対して全体とは切り離した状態で行うテス
統合テスト(結合テスト)・・・2つ以上のクラス、パッケージ、コンポーネントを組み合わせて行うテスト
基本的には上の3つだけど、一部次の項目も含む
回帰テスト・・・以前に実行したテストケースを繰り返し実行する
システムテスト・・・他のソフトウェアシステムやハードウェアシステムとの統合を含めて最終構成をテストする
22.1 ソフトウェア品質におけるデベロッパーテストの役割
テストは、ソフトウェア品質保証プログラムにおいて重要な位置を占める。
テストの目標はエラーを見つけることである。効果的なテストとは、ソフトウェアを壊すことだ。
テストでは、エラーがないことは決して証明できない。
テスト自体はソフトウェアの品質を改善しない。品質の指標となるだけである。
テストでは自分のコードからエラーが発見されることを前提にしなければならない。(そうでないと見逃す)
最大の問題は、一般的なプロジェクトでデベロッパーテストにどれくらいの時間をかけるかである。〜中略〜 デベロッパーテストにはプロジェクト全体の8~25%の時間が割かれるべきだろう。
22.1.1 コンストラクション時のテスト
コンストラクションの際には、一般にルーチンやクラスを作成し、頭の中でチェックしてからレビューやテストにかける
他のコンポーネントと組み合わせる前に、単体のままで徹底的にテストすべきである
テストの問題の1つは、テストが正しく実行されないために実力が発揮できないことである
22.2 デベロッパーテストへの推奨アプローチ
次の基本項目を必ず盛り込むこと
関連する要求をそれぞれテストして、それらの要求が実装されていることを確認する
関連する設計項目をそれぞれテストして、設計が実装されていることを確認する
「基礎テスト」を使って要求や設計をテストするテストケースに詳細なテストケースを追加する
プロジェクトですでに判明しているエラーと過去のプロジェクトで検出されたエラーのチェックリストを使用する
22.2.1 テストは先か、それとも後か
テストは先に書いた方が良い
手間がかからない
エラーが早く見つかる
コードを書く前に要求と設計について考えることになる
要求に問題があったり不明確な場合にそれに気付ける
いつからテストファーストとかテスト駆動開発とか言い出したんだろうって思ったらだいぶ古かったmoch5oMaki.icon
22.2.2 デベロッパーテストの限界
クリーンテストになりがちで、あらゆる角度からコードの不備をテストする「ダーティーテスト」の割合が低くなる
テストカバレッジを楽観的に見る傾向にある
高度なテストカバレッジを避ける傾向にある(全分岐カバレッジを満たすものが理想)
22.3 テストの知恵袋
完全なテストはケースが多すぎて無理ですっていう話。
22.3.1 不完全なテスト
完全なテストは不可能なので、テストのコツはエラーを検出しやすいテストケースを選ぶことである。
22.3.2 構造化された基礎テスト
効率の良いテストケースの設計について具体的なコードをもとに解説。
基礎テストに最低限必要なテストケースの数を計算する方法(下記を足していく)
ルーチンの直線パスを1
if, while, repeat, for, and, or などのキーワードで1
case文のcaseとdefaultに1
上記をもとにして手取り給与の計算プログラムを見ると、最低限必要なテストケースは6になる
あくまで最低限なのでこれでカバーできると考えてはいけない。
ここからの項目はテストの種類を紹介しながら、最初の6つにテストケースをどんどん追加していく。最終的にはテストケースは17になる。
22.3.3 データフローテスト
プログラムの中のデータの状態
定義された
使用された
破棄された
(ルーチンに)入った
(ルーチンを)抜けた
上記を組み合わせた怪しいパターン(割愛)
複数回定義されたり破棄されたりするのはもちろんおかしい
定義されて使われなかったり、後から定義されたりするのもおかしい
テストでチェックすべきデータの状態は下記の2つ
全ての「定義された」
全ての「定義されたー使用された」
これをチェックすることでデータフローを効率よくテストできる
22.3.4 同値分割
これを使うことで必ずしも新しいテストケースを思いつくわけではないが、データが複雑でプログラムのロジックにあまり反映されてないようなケースでは、有効かもしれないとのこと。
(補足)同値分割法というのはブラックボックステストの手法の一つ。
同値分割法
入力領域を同値クラスという部分集合として考え、その部分集合に含まれる値を同値とみなす
入力値に連続した有効な範囲が1つあるということは、無効値の部分集合が2つと、有効値の部分集合が1つある状態
テストケースの数を減らしながら有効なテストを書くことが可能
22.3.5 エラーの推測
優秀なプログラマは公式のテスト手法だけでなく、それほど公式でないヒューリスティックな手法を使ってコードのエラーを暴き出す。ヒューリスティックな手法の1つは、エラーを推測することである。
リファクタリングという本でも「コードの不吉な臭い」という表現があったのを思い出したmoch5oMaki.icon
インスペクションなどを活用してエラーのリストを活用すると良い
22.3.6 境界分析
境界条件を調べるテストケースを作成する
複合境界・・・複数の変数の組み合わせを考慮する
22.3.7 悪いデータ
境界条件付近のエラーを推測する他に、データが不正なケースをいくつか推測することが可能である。
データが小さすぎる・大きすぎる・またはデータがない
データの種類が正しくない
データのサイズが正しくない
データが初期化されていない
22.3.8 良いデータ
代表的なケースについてもエラーが潜んでいる可能性を見落としがち
期待される値の中間あたりの値
正常構成の最小値と最大値
古いデータとの互換性
22.3.9 手元でチェックしやすいテストケースの使用
テストケースを実行するときに、手元で正しい結果なのかどうかがわかりやすいものを使いましょうという話。
22.4 典型的なエラー
22.4.1 最もエラーを含んでいるクラスとは
プロジェクトのエラーの80%はプロジェクトのクラスまたはルーチンの20%で見つかる
プロジェクトのエラーの50%は、プロジェクトのクラスの5%で見つかる
プログラムのエラーは全てのルーチンにまんべんなくばらまかれている訳ではなく「プログラムにおいて最も高価な部分」に集中している
22.4.2 エラーの分類
エラーの分類は調査によって結果が大きく異なるので、おそらく意味のあるデータは得られないだろうとのこと(載せてるけど)
とはいえ、エラーについて、下記のような一定の示唆は得られる
エラーの範囲が限られている
エラーの多くはコンストラクション以外に原因がある
コンストラクション時のエラーはプログラマのミス
タイポ多い
設計の誤解や理解できていないことが原因
ほとんどのエラーは簡単に修正できる
22.4.3 不完全なコンストラクションによるエラーの割合
第1章より、改めてコンストラクションってなんだっけ、を書いておく。
コンストラクション(construction):ソフトウェアの開発フェーズの中で、ほぼ詳細設計からテストまでの部分を指す。その中心は、コーディングとデバッグである。
コンストラクションをしっかりやりましょうという話。コンストラクションのエラー解消はそれぞれは低コストでも全体で見るとコストがかかる。
22.4.4 データの紹介なので割愛
22.4.5 テスト自体のエラー
テストケースそのものにもエラーが含まれている可能性がある。
テストケースはテストするコードよりもエラーが紛れ込みやすいくらいである。
作業をチェックする
ソフトウェアの開発と同様にテストケースを準備する
テストケースを保管する
単体テストをテストフレームワークに統合する
22.5 テストサポートツール
一部割愛しながらまとめます。
足場足場って、なんだったっけ?と思って英訳したらscaffoldだった。
22.5.1 足場固め
テスト対象のクラスが使用するダミーのクラスを用意する
モック(擬似)オブジェクト、もしくはスタブオブジェクトという
同様にスタブルーチンを使う
テスト対象のルーチンを呼び出す偽のルーチンを用意する
ドライバ、テストハーネス
ダミーファイルを用意する
22.5.3 テストデータジェネレータ
ランダムデータジェネレータを正しく設計することでプログラマが思いつかなかった組み合わせのテストデータを用意することができる
ランダムデータジェネレータを使うことでプログラムを徹底的に調査することができる
22.5.4 カバレッジモニタ
コードカバレッジを測定せずに行ったテストではコードの50~60%しか調査されないというデータ。
単純にカバレッジだけでは判断できないけど、入れておくのは一定の効果がある
22.5.7 システム混乱ツール
こういうのあるの知らなかった。絶対パスのコードがこけるようになってるとか面白いですねー。
22.6 テストの改善
主に自動テストについて。
内容的にははそうですねっていう感じ。
22.7 テスト記録の保管
テスト記録の保管と分析っていうのは個人的にはやったことがないけど、品質管理とか進捗管理的な文脈で開発中のシステムのテストカバレッジとかエラー検出率を時系列でグラフに出したりしてるようなあれですよね。
まとめ
開発者によるテストは重要
先にテストケースを書くと欠陥検出・修正サイクルが短くなる
コラボレーティブ開発プラクティスと併用することで、より効果的
テストケースの作成にはコツがあるのでポイントを押さえて多くのテストケースを確実に生成しよう
エラーは一部のクラスやルーチンに集中することを念頭に、エラーを発生しやすいコードを突き止めて設計の見直しや書き換えを検討する
テストデータにはテスト対象のコードよりもエラーが紛れ込みやすい
自動テストは回帰テストに欠かせない
テストプロセスの改善に最も良い方法はテストを日常化し、評価し、それを改善するための手法を用いることである