テスト:決定論的または非決定論的?


17

どちらかを持っている方が良いですか

  • 同じテストが成功する確定的なテストスイート
  • 非決定的テストスイート。これは、より多くのケースをカバーする可能性があります。

例: テストスイートを作成して、MVCアプリケーションのコントローラー機能をテストします。コントローラーは、テスト中の入力としてデータベースからのアプリケーションデータを必要とします。これを行うには2つのオプションがあります。

  • テストデータベースのどの行を入力として選択するかをハードコーディングします(10行目と412行目など)
  • 乱数ジェネレーターを使用して、データベースからデータを擬似ランダムに選択します(乱数ジェネレーターによって選択された2行)

1つ目は決定論的です。同じリビジョンのコードに対してテストを実行するたびに、同じ結果が得られます。2番目は非決定的です。テストスイートを実行するたびに、異なる結果が得られる可能性があります。ただし、ランダムに選択されたデータは、データエッジケースのより適切な表現である可能性があります。予測不可能なデータをコントローラーに送るユーザーをよりよくシミュレートするかもしれません。

どちらか一方を選択する理由は何ですか?


5
そのテストは時々失敗するだけです。 martinfowler.com/articles/nonDeterminism.html

そのリンクをありがとう。この記事を念頭に置いて、このテストスイートのコンテキストで非決定性が意味することを明確にする必要があると感じました。データはデータベースからランダムに選択されるため、コントローラーに供給されるすべてのデータはデフォルトで有効なデータです。これは、非決定論に関しては、テストスイートに偽陰性が存在しないことを意味します。ある意味では、このランダム性は、ユーザーがコントローラーで使用するデータを「ランダムに」選択することをシミュレートします。これは、必ずしも記事で説明されている非決定論と同じではありませんよね?
DCKing


10
@DCKing:テストが失敗した場合にどうなるかを検討してください。さて、バグがあります。ええと、今何?デバッグモードでもう一度実行してください!成功する場所!次の100回は実行するように、宇宙線の衝突として問題を取り消します。テストでの非決定性は、絶対に機能しません。テストケースでより多くの地面をカバーする必要があると感じる場合は、より多くの地面をカバーします。シードを設定してRNGを初期化し、一貫してランダムな値で「テスト」を数百回実行します。
Phoshi

1
(最終的に私はきちんとさえずりを検索することができ、マシンに周りました- 「これテストはちょうど時々失敗は、」Twitterで#FiveWordTechHorrorsからである-それを正しくクレジットに望んでいた)

回答:


31

テストスイートを実行するたびに異なる結果が得られる可能性がある場合、テストはほぼ完全に価値がありません。スイートでバグが表示された場合、再現できない可能性が高く、修正しようとするとバグ、修正が機能するかどうかを確認できません。

したがって、テストデータの生成に何らかの種類の乱数ジェネレーターを使用する必要があると思われる場合は、ジェネレーターを常に同じシードで初期化するか、テストにフィードする前にランダムテストデータをファイルに保存してください。そのため、以前の実行とまったく同じデータでテストを再実行できます。このようにして、非決定論的テストを決定論的テストに変換できます。

編集:乱数ジェネレーターを使用していくつかのテストデータを選択することは、良いテストデータを選択するのが面倒だという兆候です。100,000のランダムに選択されたテスト値をスローする代わりに、これが偶然すべての重大なバグを発見し、脳をよりよく使用し、10から20の「興味深い」ケースを選択し、テストスイートに使用するのに十分であることを願っています。これにより、テストの品質が向上するだけでなく、スイートのパフォーマンスが大幅に向上します。


ご回答有難うございます。私が質問に対して行ったコメントに対するあなたの意見は何ですか?
DCKing

1
@DCKing:ランダムジェネレーターがあなたよりも良いテストケースを選ぶ方が良いと思う場合(疑いがある)、それを一度使用して、プログラムが失敗するテストデータの組み合わせを見つけ、それらの組み合わせを「ハードコード」された部分に入れるテストスイートの。
Doc Brown

再度、感謝します。MVCアプリだけに適用されないように、私の回答を更新しました。
DCKing

1
ランダムキーエントリを生成するテストプログラムを持つ一部のUIコンテキスト(たとえば、コントローラー入力を取得するゲーム)では、ストレステストに役立ちます。意図的な入力では見つけにくい欠陥を発見できます。
ロボット

@StevenBurnap:さて、私が質問を理解する方法は、OPが従来の回帰テストを念頭に置いていたと思います。もちろん、ストレステストはハードウェアに依存する特殊なケースであり、ランダムジェネレーターを使用しない場合でも非決定的な動作を引き起こす可能性があります。これは、質問の下の最初のコメントでMichaelTによってリンクされた記事で説明されているものです。また、ランダム入力を使用したスト​​レステストでも、定義済みのランダムシードを使用することで、少なくとも動作をより決定的にすることができます。
Doc Brown

4

決定論的と非決定論的の両方に場所があります

次のように分割します。

単体テスト。

これらには、毎回まったく同じデータを使用した確定的で反復可能なテストが必要です。単体テストは、特定の分離されたコードセクションに付随し、確定的な方法でテストする必要があります。

機能および入力ストレステスト。

これらは、以下の警告を伴う非決定的アプローチを使用できます。

  • その事実は明確に描かれ、呼び出されています
  • 選択されたランダムな値はログに記録され、手動で再試行できます

3

どちらも。

決定論的テストと非決定論的テストには、異なるユースケースとスイートに対する異なる値があります。一般的に非決定論決定論テストと同じ精度を提供することはできません。これは誤りです。それらはそれほど正確ではないかもしれませんが、はるかに広くなる可能性があり、独自の利点があります。

例を見てみましょう。整数のリストをソートする関数を作成します。あなたが有用だと思う決定論的な単体テストは何でしょうか?

  • 空のリスト
  • 要素が1つだけのリスト
  • すべて同じ要素のリスト
  • 複数の一意の要素を持つリスト
  • いくつかが重複している複数の要素を持つリスト
  • とリストNaNINT_MININT_MAX
  • すでに部分的にソートされているリスト
  • 10,000,000要素のリスト

そして、それは単なるソート関数です!確かに、これらのいくつかは不必要である、またはこれらのいくつかは非公式の推論で除外できると主張することができます。しかし、私たちはエンジニアであり、非公式の推論が顔を出しているのを見てきました。私たちは、構築したシステムを完全に理解したり、頭の中で複雑さを完全に維持したりするほど頭が良くないことを知っています。そもそもテストを書く理由です。非決定論的なテストを追加することは、事前に良いテストのすべてを知るのに必ずしも十分に賢くないかもしれないと言うだけです。セミランダムデータを関数にスローすることで、見落としたエッジケースを見つける可能性が高くなります。

もちろん、それは決定論的なテストも除外しません。非決定論的なテストは、プログラムの膨大な範囲でバグを見つけるのに役立ちます。ただし、バグを発見したら、それを修正したことを示す再現可能な方法が必要です。そう:

  • コードのバグ見つけるには、非決定的テストを使用します。
  • 確定的テストを使用して、コードの修正確認します。

これは、単体テストに関する多くの堅実なアドバイスが必ずしも非決定論的なテストに適用されるわけではないことに注意してください。たとえば、高速でなければなりません。低レベルのプロパティテストは高速である必要がありますが、「ユーザーがWebサイトのボタンをランダムにクリックしてシミュレートし、500エラーが発生しないことを確認する」などの非決定的テストは、速度よりも包括性を優先する必要があります。ビルドプロセスとは独立して実行するようなテストを行うだけで、開発が遅くなることはありません。たとえば、専用のステージングボックスで実行します。


-1

あなたは本当に決定論的対非決定論的が欲しくありません。

あなたが望むのは、「常に同じ」対「常に同じではない」です。

たとえば、ビルドごとにビルド番号が増える場合があります。また、乱数が必要な場合は、ビルド番号をシードとして乱数ジェネレーターを初期化します。そのため、ビルドごとに異なる値でテストを行い、バグを発見する機会を増やします。

ただし、バグが見つかったら、同じビルド番号でテストを実行するだけで、再現性があります。


1
または、使用するビルド番号がない場合は、テスト実行の出力にシードの初期値を配置して、同じシードでテストを再実行できるようにします。
RemcoGerlich 16
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.