|
テストの計画を立てる時の第一歩は、テストのフェーズを決めることです。それなりの規模のシステムに対して、デバッガ上で動かすテストから本番環境での負荷テストまで、あらゆるテストをごっちゃにして行おうとすると、並みのマネジャーでは計画通りにいきません。それどころか、破綻してしまいます。すべからく仕事を上手に行うためのコツは、似たような仕事をまとめて行うことですね。
テストのフェーズで最も有名なのは、単体テスト、結合テスト、システムテスト、受け入れテストの4つのフェーズです。Boehm御大が1979年に書いた"Guidelines for Verifying and Validating Software Requirements and Design Specifications"という論文が初出でしょうか。
単体テストは、モジュールを対象としたテストです。C言語では関数、Javaではメソッド(もしくはクラス)、Pascalでは手続きのレベルですね。モジュールとして詳細設計し実装したロジックのバグを検出します。主に使う手法は、制御パステストや境界値テストです。データフローパステストを使う場合もあるかもしれません。ほとんどの場合、テストを実施するのは開発者になります。最近はテストファーストでテスト設計を行いますね。
結合テストは、モジュール間のインターフェースや組み合わせを対象としたテストです。C言語などではモジュールの呼び出しや戻り、Javaなどではメッセージのやり取りになります。モジュール間のインターフェースに食い違いがあるバグや、(単一のモジュールでバグが見つからないのに)複数のモジュールを組み合わせた時にだけ見つかるバグを検出します。モジュールを順次一つずつ組み合わせていくインクリメンタルテストという手法や、いきなり全てモジュールを組み合わせるビッグバンテストという手法が代表的です。もっともビッグバンテストが推奨される場合は、ほとんどありませんが。
構造化設計を用いている場合は、モジュール構造図の最上位、すなわちC言語におけるmain関数から組み合わせていくトップダウンテストや、デバイスドライバなど最下位のモジュールから組み合わせていくボトムアップテスト、両方同時に行うサンドイッチテストなどの方針で進めていきます。オブジェクト指向設計を用いている場合は、メッセージシーケンスにしたがって組み合わせたり、スレッドごとに組み合わせていきます。単体テストと同じように、開発者がテストを実施することがほとんどです。
システムテストは、全てのモジュールを結合した一つのソフトウェア(ビルド)を対象としたテストです。負荷をかけて初めて発生するバグ、デバイスやOS、他のソフトウェアなどとの組み合わせで発生するバグ、(単一の機能にバグが見つからないのに)複数の機能を組み合わせた時にだけ見つかるバグなどを検出します。もちろん単に機能が動かないというシンプルなバグも見つけなければなりません。また性能や操作性、セキュリティ、障害発生時のふるまいなどの評価も行います。開発者がテストを実施する場合もありますが、テストチームが担当することもありますね。仕様書を字面通り確認すればよいわけではなく、暗黙の仕様によって開発者が見落としている状況や、いかにもバグが発生しそうでユーザが操作してしまいそうな状況を想定できるか、が腕の見せどころです。
受け入れテストは、システムテストを通過したソフトウェアで問題ないかどうか、をユーザがチェックするテストです。検収と呼ばれることもありますね。ユーザ側で厳しい検収基準を用意していることもあれば、何となくユーザが触ってバグが出なければOKといった場合もあります。開発側(もしくはテストチーム)で用意したテスト項目でバグが無いことを、ユーザが監査するだけかもしれません。契約形態や作業の実態によって千差万別です。本番環境や実データでテストする場合は、並行で、または事前に移行作業が必要です。受け入れテストを実運用で行う時は、運用テストという名前で呼ばれることもあります。またパッケージソフトウェアや組込みソフトウェアの場合は特定のユーザがいない場合がありますので、サンプルのユーザ(βテスター)に頼むこともあるでしょう。
こうしてテストを複数のフェーズに分けると、なぜ混乱しないのでしょうか。それは、一度に多くの視点からテストを考えずに済むからです。各モジュールのロジックのバグを考えながら、負荷をかける環境を準備しつつ、操作性を評価するそばで、ユーザに受け入れテストをしてもらうタイミングを検討しなければならない状況を想像してみて下さい。それぞれの作業はおざなりになってしまいますね。人間は、一度に雑多な視点でモノを考えることがあまり得意ではありません。そのため似たような視点ごとにフェーズ分けを行い、一度に考える視点を絞ることで、テストの質を向上させるわけです。
視点を絞ると、網羅的なテストが楽になります。一度に雑多な視点で考えようとすると、どうしても一つ一つの視点できっちり考え抜くことが難しくなります。そのため網羅的なテストをしたつもりでも、テストに漏れが生じてしまいます。
またフェーズ分けによって、バグの切り分けコストも減少します。単体テストや結合テストをせずに全てシステムテストでまかなおうとすると、バグが見つかっても原因の特定に時間がかかってしまいます。例えば負荷テストを行ってバグを見つけたとしても、単なるロジックのミスなのか、モジュールのインターフェースがおかしいのか、メモリリークを起こしたのか、など原因の候補を一つ一つ切り分けていかねばなりません。しかしきちんとフェーズ分けを行うと、ロジックのミスは単体テストで全て潰しており、モジュールのインターフェースは結合テストで全てチェックしているはずです。したがって負荷のみに起因するバグだと絞り込むことができ、時間を節約することが可能になります。
テストマネジメントの面では、マイルストーンが決めやすいというメリットがあります。フェーズ分けを行うことで、特定の視点によるテストを一つのフェーズのみで実施するようにすると、マイルストーンをそのテストが完了したかどうかという基準にできます。フェーズ分けをしないと、どこにマイルストーンを定めてよいか、を判断するのが難しいですね。どうしてもズルズル進んでしまい、進捗管理も難しくなってしまうかもしれません。
フェーズ分けで気を付けておかねばならないのは、単体テスト・結合テスト・システムテスト・受け入れテストという4つのフェーズが、必ずしも自分の組織に合っているとは限らない点を理解しておくことです。組織によっては、単体テストの前にコードインスペクションのフェーズを設けた方がよいかもしれませんし、結合テストの後に内部状態遷移など設計に着目したテストのフェーズが必要な場合もあります。システムテストの前に機能テストというフェーズを置いている組織もあるようです。自分の組織では、どんなソフトウェアを、どんな作り方で開発しているか、をしっかり考えて、自分の組織にあったテストのフェーズを確立し、継続的に改善して下さいね。
投稿者 nishi : June 29, 2004
| コメント (0)
| トラックバック
|