開発するのに30分、テストするのに10万年:山浦恒央の“くみこみ”な話(13)
基本的な出荷基準の1つ「未実行コードがない」について詳しく解説するとともに、実践的な“パス・カバレッジ”の方法を紹介する
前回のコラム「『品質での手抜き』と『駐車違反』の共通点」では、7つの「基本的な出荷基準」を挙げ、「1.全機能をテストした」と「2.境界条件をテストした」の2つについて解説しました。今回はその続き、「3.未実行コードがない」について紹介します。
まずは前回と同様に、7つの基本的な出荷基準について再掲します。
- 全機能をテストした
ブラックボックス/ホワイトボックス・テストで同値分割を実施した。 - 境界条件をテストした
ブラックボックス/ホワイトボックス・テストの境界値分析を実施した。 - 未実行コードがない
ホワイトボックス・テストのC0パス網羅を満足した。 - エラー・ゲシング(Error Guessing)を実施した
バグを想定し、それを摘出するためのテスト項目を設計・実施した。 - 長時間耐久テスト、過負荷テストを実施した
48時間の連続運転や、過負荷状態での稼働テストを実施した。 - バグの発生が頭打ちになった
いわゆる「バグ摘出曲線」がフラットになった。 - 未修正のバグが残っていない
摘出したバグは全件修正した。
今回の主題「3.未実行コードがない」は、非常に誤解しやすい基準ですので、例と図を用いながら詳しく見ていきたいと思います。
3.未実行コードがない
ソフトウェアのテストには、プログラム全体をブラックボックスと見なし、ソースコードやプログラムの構造を無視して検証する「ブラックボックス・テスト」と、ソース・プログラムをベースに検証する「ホワイトボックス・テスト」の2種類があります。
一般的に、エンド・ユーザーやQA(Quality Assurance)技術者は、ブラックボックス・テストを実施し、ソフトウェアを開発したエンジニアは、ブラックボックス・テスト、および、ホワイトボックス・テストの両方を実施することが多いようです。
このホワイトボックス・テストの“永遠の王様”が、「パス網羅(パス・カバレッジ)」です。
パス網羅の基本的な考え方は、「すべてのソース・コードを実行することにより、バグをたたき出す」です。常識的に考えると、非常にまっとうな正しい考え方です。中には、さらに一歩踏み込んで、「すべてのプログラム文を実行すれば、全部のバグを検出できるはずだ!」と考える人がいますが、本当にそうなのでしょうか?
以降で、パス網羅の詳細を見ていきましょう。これを検証することによって、パス網羅の限界や弱点が見えてきます。
ホワイトボックス・テストの“永遠の王様”−パス網羅−
パス網羅をざっくりと分類すると、以下の4種類になります。
(1)C0:命令語網羅
これは、「全命令語を1回は実行する」というもので、最も緩い基準です。図1に例を示します。
このチャートで、オレンジの●印は命令語を表します。条件文としてA、Bの2つがあり、A1、B1のパスを通ると、以下に続く命令語を実行し、A2B2はスキップします。C0カバレッジでは、このチャートの全命令語、すなわち、●印をすべて網羅すればよいので、A1B1のパス1本だけで網羅できることになります。プログラマの常識として、「命令語は最低限1回は実施して、テストすべし!!」です。
(2)C1:分岐網羅
C0網羅よりもワンステップ厳しいのがこの基準です。条件文が「真」と「偽」になる両方を実行するものです。その例を図2に示します。
C1カバレッジを100%網羅するには、A1B1とA2B2の2本のパスを実行しなければなりません。
(3)C2:複合条件網羅
そして、C1網羅よりもさらに厳しいのが、このC2カバレッジで、条件文の「真」と「偽」の組み合わせを実行します。図3の例では、C2カバレッジを100%網羅するには、A1B1、A1B2、A2B1、A2B2の4本のパスを実施する必要があります。
このように解説すると、「C2網羅を100%実施するのは難しいかもしれないけれど、C0カバレッジは簡単じゃないか!」「これなら、すぐにできそうだ!!」「最低限、C0は100%網羅しなきゃね」などと考える人がたくさんいます。しかし、実際には、そう単純ではありません……。
プログラマは本能的に、「作成したソース・コードは、最低1回は実行してみないと、正しく動作するか不安だ」と考えます。確かにそのとおりで、エンド・ユーザーにしてみれば、1回もテストしていない機能は恐ろしくて使いたくもありません。これが、C0網羅の根底にある考え方です。
しかし、最も緩い基準といえるC0網羅でさえ、実際は簡単ではありません。その理由を以下に挙げていきます。
理由1:パス網羅ツールなしにパス・カバレージは不可能
簡単なプログラムであれば、ソース・コードを印刷して、通過したパスに色を付ければ、パスの網羅状況がすぐに分かりますが、通常のソフトウェアはものすごく複雑で、パス網羅用のツールなくしては、実行不可能といえます。
理由2:通常では起こり得ない条件をどう発生させるか
パス網羅を開始すると、最初は1日であっという間に50%も網羅できるのですが、そこから先がなかなか進まず、80%前後で頭打ちになります。これは、発生条件を簡単にそろえられる正常ケースを実行し尽くし、発生条件の難しいエラー・ケースが残るためです。
こうなると、1本のパスを通すのに何時間も苦労して、発生条件や環境を設定する必要が出てきます。ましてや、「ディスクに入力障害が発生し、それを回復するために30回リトライしたが障害が続くので、その旨をコンソールに通知しようとしたら、コンソールにハードウェア障害が起き、それを回復しようとしたら……」や「原子炉で炉心溶融が発生した場合、以下の処理を実施する……」などのケースは、実際に、その事象を発生させることは不可能です。
「最低限、作ったソース・コードは、1回は実行したい」。しかし、それは簡単なことではない……。では、どうすればいいか?
取り得る方法は、2つしかありません。それは、「実行しない(手を抜く)」と「何とかして実行する」です。
実行しない(手を抜く)
戦略として「手を抜く」を選択することも、時と場合によっては可能です。その場合、漫然と手を抜くのではなく、どの部分のテストを割愛し、それによってどんなリスクがあるかをきちんと把握しておく必要があります。前回のコラムで述べた“駐車違反をする場合の心得”のようなものです。
何とかして実行する
良識と常識のあるエンジニアは、これを選択するはずです。マシン上で発生させることが難しい条件は、例えば、机上テストで実施すればよいのです。マシン・テストより、机上テストの方が効率もよくバグをたくさんたたき出せます。マシン・テストと机上テストを併用して、C0カバレッジは100%網羅すべきです。
(4)C∞:全パス網羅
そして、最後に紹介する究極のパス・カバレッジが、「全パス網羅(C∞)」です。これは、すべての実行し得るパスをテストするものです。「全パスを網羅すれば、すべてのバグを摘出できる」と考える人は多いのですが、話はそんなに簡単ではありません。図4をご覧ください。
こんな単純な構造のプログラムであれば、初心者でも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%」のような実施基準を一律に設定することは、非現実的・非効率的です。
最後に、実践的なパス・カバレッジの方法を以下に示します。
さて次回は、7つの基本的出荷基準の4つ目、「4.エラー・ゲシング(Error Guessing)を実施した」について詳細に説明したいと思います。ご期待ください! (次回に続く)
東海大学 大学院 組込み技術研究科 助教授(工学博士)
Copyright © ITmedia, Inc. All Rights Reserved.