初めまして、1月に入社した新巻です。最近はコードを書くよりも、システムの品質管理やテストに時間を割くことが多いので、書籍を参考にしつつ、私自身の開発経験も踏まえた上で、私なりにまとめてみました。テストは何のためにやるの?テストの目的よく勘違いされますが、テストの目的は「バグがないことを証明するため」ではありません。シンプルなプログラムでない限り、取りうるパターンや状態は無限大といってよいほどあります。したWebサービスでも機能の正常、異常以外に、以下のような外的要因に左右されます。明らかに仕様違反の結果を返すetc...上記のような様々な状態、事前条件をすべて網羅するのは現実的には無理でしょう。何のためにテストをするのでしょうか。テスターのメンタル・ライフ以下の表は、テスターの精神的な成長を5段階で表す「テスターのメンタル・ライフの5つのフェーズ」というものです。テストは活動ではない。そもそもテスト以前にバグを潰すマインド・セットを養成するための精神修行である。フェーズ4だけは特殊で精神論のようですが、フェーズ3の「リスク管理の一環としてのシステムの品質のモニタリング活動である」というのは、システム開発で重要なものは何なのかを示唆しています。次は、今回挙がった「システムの品質」とはそもそも何なのかを深堀します。システムの品質とは?深くて難しい「品質」そもそもシステムの品質とは何なのでしょうか。「システムがステーク・ホルダの要望、期待を満たしているかどうか」ということになります。小規模なWebサービスでも、システムのステーク・ホルダはたくさんいます。開発者etc...それぞれのステーク・ホルダがシステムに対する要望や期待を持っており、相反する要件を満たさなければならないこともあるでしょう。長くなるのでIEEEが定義するソフトウェアの品質モデルの詳細は割愛しますが、前述のステーク・ホルダがシステムに何を期待しているのかを考えれば、システムとしてどんな品質特性を定義、維持管理することが必要か想像がつくと思います。セキュリティ性etc...例えば、重大なバグやセキュリティの問題で、顧客への損失補填が必要なケースもありえますし、レスポンスが遅いと、ユーザーが使ってくれないかもしれません。システム開発というと、プログラミングやデザイン・パターンなどのツールの話ばかりが注目されがちですが、システム開発の目的は「ステーク・ホルダの要望、期待を満たすこと」なので、ツールの話をする前に、そもそも何のために仕事をしているのかをよく考える事が大事です。次はシステムの品質に対するアプローチについて見ていきたいと思います。Approaches」というものです。上にいくほど定性的で計測が難しく、下に行くほど定量的で計測が容易です。客観的に評価できないフィーリング。ユーザーのニーズを最も良く満足させたものが、最も品質が高い。品質≠満足度なので、品質が低くても問題ないこともある。製品のコストと、満たせている要求を比較する。製品が持つべき品質特性と、現状の品質との差分。システムの製造工程(=実装)に着目する。バグ密度、バグ収束曲線もちろん、どのアプローチが有効なのか、どの程度の品質が必要なのかは、開発するシステムの要件によって様々だと思いますが、どのアプローチも非常に重要で無視できないことがわかります。次は、各アプローチとシステムのライフサイクルの関連について見ていきます。システムのライフサイクルと品質に対するアプローチの関連付け同一システムであったとしても、システムの現在のライフサイクルによって、重視すべきアプローチは変わってきます。Webサービスの立ち上げを例に見てみます。以下の表は品質特性に対するアプローチの考え方をWebサービスの開発に適用した例です。approachに力点をシフト。顧客がつき始めているので、セキュリティ、性能などの品質特性が重要になります。approachも重要に。大量の顧客がいるし、重大なバグ=サービスが即死の可能性があるので、製造業的な品質管理が重要に!一度立ち上がったサービスは、品質を管理し、バグを出さないことがとても重要であることがわかります。次はバグとコストの関係について見ていきます。バグが見つかった時のコストシステムのバグは、見つかるタイミングによって大雑把に以下の2つに分類できます。Failure(内部故障)システムの開発組織内部で見つかったバグ。Failure(外部故障)」と比較して、相対的に影響が少ない。Failure(外部故障)システムのリリース後に、開発組織の外部で見つかったバグ。バグの修正、再テストなどのコストに加えて、以下のコストもかかります!再リリースのコスト顧客への説明のコストサポート、ヘルプデスクが問い合わせを捌くコストビジネス機会損失のコストもちろん、完璧な品質を作りこむのは無理ですし、バグの内容にもよりますが、要するに一度リリースしてしまった後にバグが発覚するコストは非常に高くつくのです。下手をすると、ちょっとしたつまらないバグでも、Webサービスが消し飛びかねません。UTの勧め前述の通り、一度リリースしたサービスでは品質を管理することが重要です。品質管理の対象、手法ともに様々ですが、コードを書くのが仕事のエンジニアにとっては、ソースコードが主な成果物になるでしょう。Test)」を見ていきます。Testとは何か?UTの位置づけ以下の図は有名なソフトウェア開発におけるVモデルと呼ばれるものです。活動と、各活動で作成された成果物を確認するテストの対比を表します。要するにUT(上記の図における単体テスト)とは、詳細設計の成果物=クラス、関数単位の振る舞いを確認するためのテストになります。プログラマにとっては一番身近で、結合テストやシステムテスト、受け入れテストと比べて相対的に低コストで実施できます。一般的にはより上流のテストよりも粒度が細かく、UTでの品質を担保できていないとより上流のテストでの品質の確保も難しいでしょう。普通は受け入れテストや結合テストでUT観点のテストは実施しません。UTもとにかくやれば良いというものではないので、次は「良いUTの条件」を見ていきます。良いUTは以下の特性を持つ必要があります。自動化され、繰り返し実行可能性であること実装が容易であること一度書いたら、将来にわたって維持管理できること誰でも簡単に実行できること高速に実行できること要するに手動で画面を直接叩いて確認するようなものではなく、専用の自動実行ツールを活用したほうが効率が良いということです。Nunit)があります。プロトタイプや、作り捨て前提のツールならば、xUnitは必ずしも必要ではありませんが、導入しておくと仕様変更による影響箇所の確認などが非常に楽になります。UTとカバレッジxUnitを実施するときの効果的な指標としてカバレッジがあります。カバレッジはテストの実行によって、テスト対象プログラムをどの程度網羅的に実行できたかどうかを確認するための指標になります。あるテストの実行の結果、実行行数100行のプログラムのうち、50行しか実行されていなければ網羅率は50%です。(C0の命令網羅の場合)一般的にカバレッジは以下の3段階があります。その行が少なくとも一回以上実行されたかどうかを確認します。分岐の結果がtrueの場合とfalseの場合をそれぞれ、少なくとも一回以上実行されたかどうかを確認します。一般的にはここまで確認することが多いです。複数の分岐の分岐結果の組み合わせを確認します。カバレッジはプロブラムの内部構造に着目したホワイトボックス・テストの手法で、外部仕様からみた観点は含まれません。そのため、カバレッジが100%でも安心はできませんが、テストの網羅性を定量的に把握するための指標として使えます。(「100%だから安心!」ではなくて、「100%でないと問題」という見方をする)本来ならば、プログラムの外部仕様に着目したブラックボックス・テストを一通り実施してから、どうしてもカバレッジが通らないところだけホワイトボックス・テストを実施したほうが効果的なのですが、効果的なブラックボックス・テストは難しく、定量化しづらいため、カバレッジを重視することが多いようです。スクリプト言語の場合、わずかな記述ミスでスクリプティング・エラーなどが発生するリスクがあるため、とりあえず命令網羅性を見てるだけでも安心感があります。UTの例UTの一例として、以下のシンプルな関数を考えてみます。引数の数値に1を足してインクリメントした数値を返します。{...}上記の関数をテストする場合、少なくとも以下のケースを考える必要があります。同値分割の有効値の中から、代表値として選択。仕様に記載がないので、どう振る舞うべきか、仕様を決める必要がある。同値分割の無効値の中から、代表値として選択。同値分割の無効値の中から、代表値として選択。備考欄に記載のある「同値分割」というのはブラックボックス・テストの手法の一つであり、入力値をプログラムが受けつける「有効値」と受けつけない「無効値」に分類して、それぞれから代表値のみを用いてテストします。上記の例でいうと、取りうる値=有効値はNumber型全てなので、数値ならなんでもよいということになります。null、文字列のときはそれぞれ無効値で、分類上はどちらも無効値ですが、nullだけ特別に扱うことが多いようです。テストケースの内容から、以下のことが読み取れます。引数が一つで振る舞いが単純な関数でさえ、数パターンのテストが必要となる引数が複数あったり、テスト対象が状態を持つオブジェクトの場合、テストが非常に難しくなります。テスト性を考えると、プログラムは極力シンプルにすべきです。プログラムの振る舞い、仕様を理解しないと、効果的なテストを実施することは難しい上記の例でいうと、引数がNumber型のならば全ての値が有効値で仕様に記載がないですが、プログラムの振る舞いを考えると最大値のみ特殊なケースであることがわかります。抜け漏れが全くない仕様や、設計、実装するのは不可能なので、プログラムの利用シナリオ(ユースケース)を考えながらテストするのが効果的です。まとめこの記事のまとめは以下のとおりです。繰り返しになりますが、「テストとはリスク管理の一環としてのシステムの品質のモニタリング活動」であり、システム開発において極めて重要です。自動化されたUTはバグやデグレを防ぐのに有効xUnitを導入することで効率的にバグやデグレを防止できます。カバレッジを測定することで、品質の管理状況を定量的に見ることもできます。良いUTを書いて継続的に維持管理していくことが極めて重要xUnitのようなツールを効果的に活用して良いUTを書いて、維持管理していくことが非常に重要です。書き捨てではなく、維持管理してこそ意味があります。ProfessionalPragmaticのタイトルのとおり、トップダウンで効果的な手法を学ぶことができるため、とてもためになります。C#サンプルコードや実践的な手法が解説されており、記述が非常に簡潔で理解しやすいのでお勧めです。Controlソフトウェアの品質管理の最新の手法が紹介されており、大変参考になります。新巻洋一フレームワークとか、ソフトウェア・アーキテクチャが大好きな、元SIerのシステム・エンジニアです。US私たち”アライドアーキテクツのエンジニア”は”世界をよりよく変えたい”という想いを強く持ちながらWebサービスを創っています。”日本発、世界的なWebサービスを創る”ことをエンジニアチームは本気で考え、毎日チャレンジしています。