開発するのに30分、テストするのに10万年山浦恒央の“くみこみ”な話(13)

基本的な出荷基準の1つ「未実行コードがない」について詳しく解説するとともに、実践的な“パス・カバレッジ”の方法を紹介する

» 2009年11月20日 00時00分 公開
[山浦恒央 東海大学 大学院 組込み技術研究科 准教授(工学博士),@IT MONOist]

 前回のコラム「『品質での手抜き』と『駐車違反』の共通点」では、7つの「基本的な出荷基準」を挙げ、「1.全機能をテストした」と「2.境界条件をテストした」の2つについて解説しました。今回はその続き、「3.未実行コードがない」について紹介します。

 まずは前回と同様に、7つの基本的な出荷基準について再掲します。

  1. 全機能をテストした 
    ブラックボックス/ホワイトボックス・テストで同値分割を実施した。
  2. 境界条件をテストした 
    ブラックボックス/ホワイトボックス・テストの境界値分析を実施した。
  3. 未実行コードがない 
    ホワイトボックス・テストのC0パス網羅を満足した。
  4. エラー・ゲシング(Error Guessing)を実施した 
    バグを想定し、それを摘出するためのテスト項目を設計・実施した。
  5. 長時間耐久テスト、過負荷テストを実施した 
    48時間の連続運転や、過負荷状態での稼働テストを実施した。
  6. バグの発生が頭打ちになった 
    いわゆる「バグ摘出曲線」がフラットになった。
  7. 未修正のバグが残っていない 
    摘出したバグは全件修正した。

 今回の主題「3.未実行コードがない」は、非常に誤解しやすい基準ですので、例と図を用いながら詳しく見ていきたいと思います。

3.未実行コードがない

 ソフトウェアのテストには、プログラム全体をブラックボックスと見なし、ソースコードやプログラムの構造を無視して検証する「ブラックボックス・テスト」と、ソース・プログラムをベースに検証する「ホワイトボックス・テスト」の2種類があります。

 一般的に、エンド・ユーザーやQA(Quality Assurance)技術者は、ブラックボックス・テストを実施し、ソフトウェアを開発したエンジニアは、ブラックボックス・テスト、および、ホワイトボックス・テストの両方を実施することが多いようです。

 このホワイトボックス・テストの“永遠の王様”が、「パス網羅(パス・カバレッジ)」です。

 パス網羅の基本的な考え方は、「すべてのソース・コードを実行することにより、バグをたたき出す」です。常識的に考えると、非常にまっとうな正しい考え方です。中には、さらに一歩踏み込んで、「すべてのプログラム文を実行すれば、全部のバグを検出できるはずだ!」と考える人がいますが、本当にそうなのでしょうか?

 以降で、パス網羅の詳細を見ていきましょう。これを検証することによって、パス網羅の限界や弱点が見えてきます。

ホワイトボックス・テストの“永遠の王様”−パス網羅−

 パス網羅をざっくりと分類すると、以下の4種類になります。

・C0:命令語網羅(全命令語を1回は実行)
・C1:分岐網羅(条件文の真と偽を実行)
・C2:複合条件網羅(真偽の組み合わせを実行)
・C∞:全パス網羅(すべての可能なパスを実行)

(1)C0:命令語網羅

 これは、「全命令語を1回は実行する」というもので、最も緩い基準です。図1に例を示します。

C0網羅(命令網羅) 図1 C0網羅(命令網羅)

 このチャートで、オレンジの●印は命令語を表します。条件文としてA、Bの2つがあり、A1、B1のパスを通ると、以下に続く命令語を実行し、A2B2はスキップします。C0カバレッジでは、このチャートの全命令語、すなわち、●印をすべて網羅すればよいので、A1B1のパス1本だけで網羅できることになります。プログラマの常識として、「命令語は最低限1回は実施して、テストすべし!!」です。

(2)C1:分岐網羅

 C0網羅よりもワンステップ厳しいのがこの基準です。条件文が「真」と「偽」になる両方を実行するものです。その例を図2に示します。

C1網羅(分岐網羅) 図2 C1網羅(分岐網羅)

 C1カバレッジを100%網羅するには、A1B1とA2B2の2本のパスを実行しなければなりません。

(3)C2:複合条件網羅

 そして、C1網羅よりもさらに厳しいのが、このC2カバレッジで、条件文の「真」と「偽」の組み合わせを実行します。図3の例では、C2カバレッジを100%網羅するには、A1B1、A1B2、A2B1、A2B2の4本のパスを実施する必要があります。

C2網羅(複合条件網羅) 図3 C2網羅(複合条件網羅)

 このように解説すると、「C2網羅を100%実施するのは難しいかもしれないけれど、C0カバレッジは簡単じゃないか!」「これなら、すぐにできそうだ!!」「最低限、C0は100%網羅しなきゃね」などと考える人がたくさんいます。しかし、実際には、そう単純ではありません……。

 プログラマは本能的に、「作成したソース・コードは、最低1回は実行してみないと、正しく動作するか不安だ」と考えます。確かにそのとおりで、エンド・ユーザーにしてみれば、1回もテストしていない機能は恐ろしくて使いたくもありません。これが、C0網羅の根底にある考え方です。

 しかし、最も緩い基準といえるC0網羅でさえ、実際は簡単ではありません。その理由を以下に挙げていきます。

理由1:パス網羅ツールなしにパス・カバレージは不可能

 簡単なプログラムであれば、ソース・コードを印刷して、通過したパスに色を付ければ、パスの網羅状況がすぐに分かりますが、通常のソフトウェアはものすごく複雑で、パス網羅用のツールなくしては、実行不可能といえます。

理由2:通常では起こり得ない条件をどう発生させるか

 パス網羅を開始すると、最初は1日であっという間に50%も網羅できるのですが、そこから先がなかなか進まず、80%前後で頭打ちになります。これは、発生条件を簡単にそろえられる正常ケースを実行し尽くし、発生条件の難しいエラー・ケースが残るためです。

 こうなると、1本のパスを通すのに何時間も苦労して、発生条件や環境を設定する必要が出てきます。ましてや、「ディスクに入力障害が発生し、それを回復するために30回リトライしたが障害が続くので、その旨をコンソールに通知しようとしたら、コンソールにハードウェア障害が起き、それを回復しようとしたら……」や「原子炉で炉心溶融が発生した場合、以下の処理を実施する……」などのケースは、実際に、その事象を発生させることは不可能です。

 「最低限、作ったソース・コードは、1回は実行したい」。しかし、それは簡単なことではない……。では、どうすればいいか?

 取り得る方法は、2つしかありません。それは、「実行しない(手を抜く)」と「何とかして実行する」です。

実行しない(手を抜く)

 戦略として「手を抜く」を選択することも、時と場合によっては可能です。その場合、漫然と手を抜くのではなく、どの部分のテストを割愛し、それによってどんなリスクがあるかをきちんと把握しておく必要があります。前回のコラムで述べた“駐車違反をする場合の心得”のようなものです。

何とかして実行する

 良識と常識のあるエンジニアは、これを選択するはずです。マシン上で発生させることが難しい条件は、例えば、机上テストで実施すればよいのです。マシン・テストより、机上テストの方が効率もよくバグをたくさんたたき出せます。マシン・テストと机上テストを併用して、C0カバレッジは100%網羅すべきです。

(4)C∞:全パス網羅

 そして、最後に紹介する究極のパス・カバレッジが、「全パス網羅(C∞)」です。これは、すべての実行し得るパスをテストするものです。「全パスを網羅すれば、すべてのバグを摘出できる」と考える人は多いのですが、話はそんなに簡単ではありません。図4をご覧ください。

古典的な全パス網羅 図4 古典的な全パス網羅(C∞)の例

 こんな単純な構造のプログラムであれば、初心者でも30分でコーディングできてしまいそうですね。では、このプログラムに対し、全パス網羅を実施すると、どれぐらいの時間がかかるでしょうか?

 ループをせずに抜ける場合、5通りのプログラム・パスがあります。1回ループすると、5×5=25通りです。ループ回数が0〜18回まで、すべてを加えると、4.77×10の12乗となります。1パスの実行に1秒しかかからないとして、単純に見積もっても全パス実施には10万年以上かかることになります……。

――『開発に30分、テストに10万年』。まじめにテストしようとすると、時間はいくらあっても足りないし、サボろうとすれば、いくらでもサボれる。これがテストの難しいところです。そして、テストには、きちんとした“テスト戦略”が必要であり、そのテスト戦略には“エンジニアのセンス”が表れるのです。

 また、残念なことに、仮にC∞を100%網羅できたとしても、バグはしっかりと残っています。それはなぜでしょうか?

 C∞カバレッジは、ソース・コードの実行パスを網羅しただけにすぎません。ソース・コードに現れるバグは検出できますが、ソース・コードにない欠陥、例えば「機能漏れ」は、C∞を100%実施しても摘出できません。頑張って10万年以上かけてテストしたとしても、バグは必ず残るものなのです。ですから、C∞網羅は万能ではありません(そもそも、カバレッジによるテストは万能ではないのです)。まずは、この弱点を十分認識することです。そして、これを補う方法として、ブラックボックス的なテスト、例えば、前回解説した「同値分割」や「境界値分析」などの手法を併用することが大切です。

 すべての機能、すべてのモジュールに対し、例えば「C0カバレッジは100%、C1は80%」のような実施基準を一律に設定することは、非現実的・非効率的です。

 最後に、実践的なパス・カバレッジの方法を以下に示します。

A.機能やモジュールの重要度に応じて、C0、C1、C2を適用する
B.例えば、あるモジュールにC1カバレッジを適用すると決めた場合、さらに、トリアージュの考え方を導入し、「70%網羅は必須、努力して80%を網羅し、時間的余裕があれば90%以上を目指す」のように、目標品質の「松竹梅」も決めておくとよい
C.パス網羅では、マシン・テストだけに頼らず、机上テストでの網羅も考慮する
D.必ず、カバレッジ・ツールを使う
E.パス・カバレッジの弱点(機能漏れを検出できない)を認識し、その弱点を補うために、ブラックボックス・テストを併用する

 さて次回は、7つの基本的出荷基準の4つ目、「4.エラー・ゲシング(Error Guessing)を実施した」について詳細に説明したいと思います。ご期待ください! (次回に続く)

【 筆者紹介 】
山浦 恒央(やまうら つねお)
東海大学 大学院 組込み技術研究科 助教授(工学博士)

1977年、日立ソフトウェアエンジニアリングに入社、2006年より、東海大学情報理工学部ソフトウェア開発工学科助教授、2007年より、同大学大学院組込み技術研究科助教授、現在に至る。

主な著書・訳書は、「Advances in Computers」 (Academic Press社、共著)、「ピープルウエア 第2版」「ソフトウェアテスト技法」「実践的プログラムテスト入門」「デスマーチ 第2版」「ソフトウエア開発プロフェッショナル」(以上、日経BP社、共訳)、「ソフトウエア開発 55の真実と10のウソ」「初めて学ぶソフトウエアメトリクス」(以上、日経BP社、翻訳)。


Copyright © ITmedia, Inc. All Rights Reserved.