凪瀬 Blog
Programming SHOT BAR

目次

Blog 利用状況
  • 投稿数 - 260
  • 記事 - 0
  • コメント - 46945
  • トラックバック - 192
ニュース
広告
  • Java開発者募集中
  • 経歴不問
  • 腕に自信のある方
  • 富山市内
  • (株)凪瀬アーキテクツ
アクセサリ
  • あわせて読みたい
凪瀬悠輝(なぎせ ゆうき)
  • Java技術者
  • お茶好き。カクテル好き。
  • 所属は(株)凪瀬アーキテクツ
  • Twitter:@nagise

書庫

日記カテゴリ

 

Programming SHOT BARへようこそ。 完全なテストは不可能だ といってしまった手前、現実的なテストについて考えて見ましょう。
なお、今回は数学側への分岐だった メソッドは写像だ側の概念も含んでいます。
伏線回収だと思って読んでいただけると幸いです。

完全なテストのテストケース数

システムに対して完全な仕様書があると想定します。 こういう場合はこう動く、ということが明確に規定されているとします。 すると、テストというのは、実装が想定する動きと同じかを検証する行為ですから、 システムを関数Fで、仕様を関数Gで表現すると、

F(x) = G(x)

であることを、全てのxについて確認することになります。 ここで、xの取りうるパターン数が、そのままテストケース数になることになります。

今、入力xがn bitの情報量だとします。 すると、テストケース数は2n となります。 入力bit数に対して、検証は指数関数時間を要することになるわけです。 (ということはテストはNP困難ということに…?)

さて、ここで、入力が数種類あったとします。 システムに画面が5つあると想像してみてください。 互いの画面が連携しないのであれば、個別にテストすればいいわけです。 (している場合は、それも入力の一部としてテストを要する)

各画面での入力x1 ~ x5 が n1 ~ n5 bitの情報量だとすると、 テストケース数は

2n1 + 2n2 + ... + 2n5

となります。 つまり、完全なテストにおいては画面数の増加は、テストケースの増加にそれほど強く作用しない。 テストケース数にもっともインパクトを与えるのは、入力される情報量ということになります。

ホワイトボックステストでテストケースを削る

さて、ここまでは、完全なテスト、つまり、取りうる状態全てを仕様と つき合わせて検証することを考察してきました。

しかし、入力される情報量に対して指数関数的にケース数が増えるため、 現実的には完全網羅してのテストは現実的ではありません。 そのため、バグを効率よく検出する工夫を凝らして実用的な手間で品質を確保しようとするわけです。

完全なテストの場合、テストケース数に一番インパクトを与えているのは、入力の情報量でした。
入力がint値ひとつであれば32 bitの情報量を持ちますから、約40億のテストケースを要します。 int値ふたつだと1600京であることは「完全なテストは不可能だ」の稿で述べたとおりです。

ところが、プログラムの内部ではこの40億のパターン個別に関心を持っているわけではなく、 このパターンを内部でたかだか数パターンに分類して処理を行っていることが殆どです。
例えば、負の数の場合、0、正の数の場合といった、3パターンに分けてロジックを書くことがあるわけです。 たいてい、バグというのはこの分類のどこかがバグるとその範囲全てでバグるか、もしくは境界近辺のみバグります。 このそれぞれのパターンをサンプリングしてテストすることで効率よくバグを検出することが出来ます。

これはいわゆるホワイトボックステストと呼ばれるものですが、 内部での分類の仕方を正確に把握していないと、網羅することが出来ない場合があります。
40億パターンから数パターンまで劇的に削るわけですから、このサンプリングの仕方が テストケースの量と質(つまり、バグを取りこぼさないこと)に強く影響することになります。

ホワイトボックステスト下でテストケース数に作用するものは?

さて、bit数から劇的にパターン数を削りましたが、入力を複数とる場合、 個々の値を数パターンに絞ったところで、やはりそのパターンの組み合わせだけテストする必要があります。
例えば、int値を10個引数にとるメソッドがあるとして、 それぞれの値が内部でそれぞれふたつに分類されていたとしましょう。 その場合、

210 = 1024

と、1024パターンのテストが必要になるわけです。 もちろん、ふたつに分類というのは最小のケースでしょうから、 最低でも 2引数の数 以上のテストケース数となります。

このことから、テストケース数は

Σ 2 Fiの引数の数

よりも大きいぐらいであることがわかります。 入力引数の数を一定以下に抑えることで、多項式時間でのテストが可能となるわけですね。

(上記の考察を踏まえると、構文解析木からメソッド数および、その引数の数を集計することで step数などからテストケース数を推定するよりもよほど意味のある推計ができるように思います。 もちろん、入力とは引数のみではなく、参照するインスタンスフィールドなども含むので正確な推計は やはり難しいものになるとは思われますが。)

サンプリングの難しさ

int値がふたつあるだけで組み合わせが1600京にも上るわけですが、 テストケースを作成するということは、この1600京というパターン数をたかだか数パターンに集約し、 それでいてかつ、1600京の空間に潜む可能性のあるバグを取り漏らさないようにするということです。

これがテストの難しさであり、バグを完全に取り除いてソフトウェアを出荷することが いかに難しく、非現実的かということです。 ソフトウェアテストとはこの不可能問題に対していかに近似解を提示するかという難問なのです。

投稿日時 : 2007年10月24日 22:21
コメント
  • # re: 現実的なテスト
    softest
    Posted @ 2007/10/26 15:04
    はじめまして。通りすがりです。

    「完全なテスト」という用語をそのまま受け取ると

     2^n1 + 2^n2 + ... + 2^nk

    ではなく組み合わせになるのでテストケース数は積の形になるような気がします。(実際問題、完全なテストが不可能、ということがわかればいいので大差はないですが)


    また、ご指摘のとおり全数テストが現実的ではないので、「ソフトウェアテスト」というものがこういった動作検証などの「動的テスト」とともにレビューや設計での検証など「静的テスト」を併用していくことと定義してもいいかもしれません。


  • # re: 現実的なテスト
    凪瀬
    Posted @ 2007/10/26 16:04
    まず、前提として、ある機能が参照する内部状態も入力として扱っています。
    そして、ある一連の入力から出力までの塊をテストするのであれば、
    内部状態のバリエーションも含めて全ての入力の組み合わせをテストすればよく、
    その機能が参照しない内部状態は無視できると考えました。

    そのため、2^n1 + 2^n2 + ... といった加算になるという見解です。
  • # re: 現実的なテスト
    softest
    Posted @ 2007/10/26 20:07
    おっしゃるとおり、参照しない内部状態は無視できると思うのですが、「"完全な"テスト」という意味で言うと、この分析自体が「効率化」の一面を持っていると思ったのです。
  • # re: 現実的なテスト
    凪瀬
    Posted @ 2007/10/26 20:44
    なるほど、完全なブラックボックスではないと言えばそうなりますね。
  • # re: 現実的なテスト
    masa
    Posted @ 2007/10/30 18:20
    4つの1bitの引数a,b,c,dを持ち、a*8+b*4*c*2+d の値を7セグメントのLEDで表示する処理 led7(a,b,c,d) のテストケースの数は8ではなく16なのは自明かと思いますが。
  • # re: 現実的なテスト
    凪瀬
    Posted @ 2007/10/30 21:08
    メソッドled7(a,b,c)と別のメソッドled7b(a,b,c,d)があった場合に
    16*16とならず、16+16となるよね、という話。

    また、引数がled7(a,b,c)で内部状態としてdがある場合も、
    led7(a,b,c,d)とテストケース数は同じだろうという話です。
  • # re: 現実的なテスト
    masa
    Posted @ 2007/10/31 9:05
    そうですね。複数のメソッドがあるときは足し算ですね。
タイトル
名前
Url
コメント