ソフトウェアテストの形式化された/数学的な理論はありますか?


12

グーグルの「ソフトウェアテスト理論」は、言葉のソフトな意味での理論を与えるようだ。数学、情報理論、またはその他の科学分野の意味で、理論として分類できるものを見つけることができませんでした。

私が探しているのは、テストとは何か、使用される概念、テストケースとは何か、テストの実行可能性、テストの実用性、テストの範囲、正式な定義/説明コードカバレッジなど

更新:また、正式な検証と私が尋ねたものとの関係について、直感的にはわかりませんが、明らかに何らかの関係があります。


1
ソフトウェアテストは非常に価値があります(たとえば、ユニットテストを実行する)が、その理論には常にいくつかの穴があります。数学の先生double pihole(double value) { return (value - Math.PI) / (value - Math.PI); }から学んだこの古典的な例を考えてみましょう。このコードには、ブラックボックステストだけでは自動的に発見できないホールが1つだけあります。数学では、そのような穴はありません。微積分では、片側の制限が等しい場合、穴を閉じることができます。
rwong

4
-これは、あなたが探しているものの一部である可能性がありますen.wikipedia.org/wiki/Formal_verification
enderland

1
@enderlandの提案を2回目にします。テストに対するあなたのアプローチがどれほど厳格であるかは問題ではありません。いくつかのバグはまだクラックをすり抜けてしまい、テストでコードの多くをカバーするにつれて、新しいバグを見つけるコストが上がります。これはおそらく、誰もテストの概念を形式化する手間をかけなかった理由です。「ヒューリスティック」アプローチは、少ないトレーニングでほぼ同様に機能します。
ドーバル

それ以来、依存型を介した正式な検証の分野に慣れ親しんでおり、@ Dovalとenderlandに完全に同意することができます。
エリックカプルン

1
@rwong分子と分母の両方がゼロになる可能性をほのめかしていると思います。部分的に問題は、この関数の設計が悪いためです。数学的形式検証について話すときは、関数を任意ではなく、正しいデータ型に基づいて形式規則に従って構成する必要があります。この例では(a,b)=>a/b、正しく構成できるように、オーバーフロー関数で拡張する必要がある除算関数を使用する必要があります。
ドミトリ・ザイツェフ

回答:


8

ソフトウェアテストの背後にある数学を探求する本については...取得すべき独創的な本は、コンピューターシステムのパフォーマンス解析の技術:実験設計、測定、シミュレーション、およびモデリングの手法です。

1991年に最初に公開されましたが、パフォーマンス分析、シミュレーション、および測定のみに焦点を当てた応用数学の本であるため、今日でも人気があります。


5

優れたオンラインリソースを指すことはできません(これらのトピックに関するウィキペディアの英語の記事は改善される傾向があります)が、基本的なテスト理論についても説明した講義を要約できます。

テストモード

単体テスト統合テストなど、さまざまなクラスのテストがあります。単体テストでは、コヒーレントなコード(関数、クラス、モジュール)自体が期待どおりに機能することを確認しますが、統合テストでは、このような複数の部分が正しく連携することを確認します。

テストケースとは、特定のテスト入力を使用したり、他のクラスをモックしたりすることにより、コードが実行される既知の環境です。次に、コードの動作を、特定の戻り値などの予想される動作と比較します。

テストでは、バグの存在のみを証明できますが、すべてのバグが存在するわけではありません。テストはプログラムの正確性に上限があります。

コードカバレッジ

コードカバレッジメトリックを定義するために、ソースコードを制御フローグラフに変換して、各ノードにコードの線形セグメントを含めることができます。これらのノード間の制御フローは各ブロックの最後でのみ行われ、常に条件付きです(条件の場合はノードAに、そうでない場合はノードBに移動します)。グラフには、1つの開始ノードと1つの終了ノードがあります。

  • このグラフでは、ステートメントカバレッジは、訪問したすべてのノードとすべてのノードの比率です。完全なステートメントカバレッジは、徹底的なテストには不十分です。
  • ブランチカバレッジは、すべてのエッジに対するCFG内のノード間のすべての訪問済みエッジの比率です。これではループのテストが不十分です。
  • パスカバレッジは、すべてのパスに対する訪問済みのすべてのパスの比率です。パスは、開始ノードから終了ノードまでのエッジのシーケンスです。問題は、ループでは無限の数のパスが存在する可能性があるため、完全なパスカバレッジを実際にテストできないことです。

したがって、条件カバレッジを確認すると便利な場合があります。

  • では、簡単な条件カバレッジ、各原子の条件が真と偽のワンスである-しかし、これは完全なステートメントカバレッジを保証するものではありません。
  • では、複数の条件カバレッジ、アトミックな条件は、すべての組み合わせで撮影してきたtruefalse。これは完全なブランチカバレッジを意味しますが、かなり高価です。プログラムには、特定の組み合わせを除外する追加の制約がある場合があります。この手法はブランチカバレッジを取得するのに適していますが、デッドコードを見つけることはできますが、間違った状態に起因するバグを見つけることはできません。
  • 最小複数の条件カバレッジ、各原子及び複合条件が真と偽回です。それはまだ完全なブランチカバレッジを意味します。複数の条件カバレッジのサブセットですが、必要なテストケースは少なくなります。

条件カバレッジを使用してテスト入力を構築する場合、短絡を考慮する必要があります。例えば、

function foo(A, B) {
  if (A && B) x()
  else        y()
}

でテストする必要がありfoo(false, whatever)foo(true, false)およびfoo(true, true)完全な最小限の複数の条件カバレッジのために。

複数の状態にできるオブジェクトがある場合、制御フローに類似したすべての状態遷移をテストするのが賢明なようです。

いくつかのより複雑なカバレッジメトリックがありますが、それらは一般的にここに示されているメトリックに類似しています。

これらはホワイトボックステスト方法であり、部分的に自動化できます。ユニットテストスイートを持ってすることを目指すべきであることに注意してください高を、選択したメトリックによってコードカバレッジますが、100%が常に可能であるとは限らない。特定の場所にフォールトを挿入する必要がある例外処理をテストすることは特に困難です。

機能テスト

次に、実装をブラックボックスとして表示することにより、コードが仕様に準拠していることをアサートする機能テストがあります。このようなテストは、単体テストと統合テストの両方に役立ちます。考えられるすべての入力データでテストすることは不可能なので(たとえば、考えられるすべてのストリングで文字列の長さをテストする)、入力(および出力)を同等のクラスにグループ化すると便利ですlength("foo")foo("bar")おそらく仕事に同様です。入力と出力の等価クラス間の可能な組み合わせごとに、少なくとも1つの代表的な入力が選択され、テストされます。

さらにテストする必要があります

  • エッジケースlength("")foo("x")length(longer_than_INT_MAX)
  • 言語で許可されているが、機能の契約では許可されていない値 length(null)、および
  • 可能性のあるジャンクデータlength("null byte in \x00 the middle")

数値では、これはテストを意味します 0, ±1, ±x, MAX, MIN, ±∞, NaN、浮動小数点の比較では2つの隣接するフロートをテスト。別の追加として、ランダムなテスト値を等価クラスから選択できます。デバッグを容易にするために、使用したシードを記録する価値があります…

非機能テスト:負荷テスト、ストレステスト

一部のソフトウェアには機能以外の要件があり、それらもテストする必要があります。これらには、定義された境界でのテスト(負荷テスト)と、それを超えたテスト(ストレステスト)が含まれます。コンピュータゲームの場合、これは負荷テストで1秒あたりの最小フレーム数をアサートしている可能性があります。Webサイトは、予想される2倍の訪問者がサーバーを攻撃している場合の応答時間を観察するために、ストレステストされる場合があります。このようなテストは、システム全体だけでなく、単一のエンティティにも関連しています-ハッシュテーブルは、100万エントリでどのように低下​​しますか?

他の種類のテストは、シナリオをシミュレートするシステム全体のテスト、または開発契約が満たされたことを証明する受け​​入れテストです。

非テスト方法

レビュー

品質保証に使用できる非テスト手法があります。例は、ウォークスルー、正式なコードレビュー、またはペアプログラミングです。一部の部品は自動化できますが(たとえば、リンターを使用して)、これらは一般に時間のかかる作業です。ただし、経験豊富なプログラマーによるコードレビューはバグの発見率が高く、自動テストが不可能な設計時に特に価値があります。

コードレビューが非常に優れているのに、なぜテストを作成するのですか?テストスイートの大きな利点は、(ほとんど)自動的に実行できることであり、回帰テストに非常に役立ちます

正式な検証

正式な検証が行われ、コードの特定のプロパティが証明されます。手動検証は、プログラム全体ではなく、重要な部分に対してほとんど実行可能です。証明により、プログラムの正確性に下限が設定されます。証明は、静的型チェッカーなどを介して、ある程度自動化できます。

特定の不変式は、assertステートメントを使用して明示的にチェックできます。


これらの手法はすべてその場所にあり、補完的なものです。TDDは機能テストを事前に記述しますが、コードが実装されると、カバレッジメトリックによってテストを判断できます。

テスト可能なコードを作成するということは、個別にテストできる小さなコード単位を作成することを意味します(適切な粒度、単一の責任原則を持つヘルパー関数)。各関数が取る引数が少ないほど良い。このようなコードは、依存オブジェクトの挿入などを介して、モックオブジェクトの挿入にも役立ちます。


2
私は精巧な答えを感謝し、私はそれが私が尋ねた何を行うにはほとんど何もありません怖い:)しかし、幸いにも、 programmers.stackexchange.com/questions/78675/...は、それは私が何であったかになるにつれて近くにあると思われます目指して。
エリックカプルン

これは素晴らしいものです。本や何かを推薦できますか?
マルチン

4

「仕様ベースのテスト」でも質問に答えられるかもしれません。これらのテストモジュールを確認します(まだ使用していません)。選択された単一のデータ値を使用して単体テストを作成するのではなく、テスト値のセットを指定するためにmathy式を作成する必要があります。

テスト:: Lectrotest

著者が言うように、このPerlモジュールはHaskellのQuick-Check Moduleに触発されました。このページにはさらにリンクがあり、そのうちのいくつかは死んでいます。


2

1つの数学ベースのアプローチは、すべてのペアのテストです。アイデアは、ほとんどのバグは単一の構成オプションの選択によってアクティブになり、残りのほとんどは同時に実行される特定のオプションのペアによってアクティブになるということです。したがって、ほとんどは「すべてのペア」をテストすることで捕捉できます。数学的説明(一般化あり)はこちらです:

AETGシステム:組み合わせ設計に基づくテストへのアプローチ

(そのような参照はもっとたくさんあります)


2

いくつかの数式が使用されていますが、使用しているソフトウェアテストの種類によって異なります。たとえば、Critical Fault Assumptionは、障害が2つ以上の同時障害の産物ではないことを前提としています。以下の式は、F = 4N + 1 F変数(所与の数のテストケースの数を計算=関数N) + 1は、すべての変数が公称値をとる一定の一方の添加です。

数学的な方程式を必要とする別のタイプのテストは、堅牢性テストです。堅牢性テストは、テストプロセスでのテストケースの堅牢性または正確性をテストします。このテストでは、正当な入力範囲内の変数を入力し(クリーンテストケース)、入力範囲外の入力変数を入力します(ダーティテストケース)。次の数学方程式を使用します:f = 6n + 16nは、各変数が6つの異なる値をとる必要があり、他の値は公称値をとることを示します。* + 1 *定数1の追加を表します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.