34

プログラマーとして、私はTDDの哲学に真摯に取り組み、自分が書いた重要なコードに対して広範な単体テストを行うように努力してきました。この道は時々苦痛になることがあります(複数の単体テストの変更をカスケードする原因となる動作の変更、大量の足場が必要です)が、全体として、変更のたびに実行できるテストなしでプログラミングすることを拒否し、コードのバグははるかに少なくなります結果。

最近、私はHaskellで遊んでいます、そしてそれは常駐テストライブラリ、QuickCheckです。TDDとは明らかに異なる方法で、QuickCheckは、コードの不変条件、つまり、入力のすべて(または実質的なサブセット)を保持する特定のプロパティのテストに重点を置いています。簡単な例:安定ソートアルゴリズムは、2回実行した場合でも同じ答えが得られ、出力が増加し、入力の順列である必要があります。次に、QuickCheckは、これらの不変条件をテストするためにさまざまなランダムデータを生成します。

少なくとも純粋関数(つまり、副作用のない関数-そして正しくモックを作成すればダーティ関数を純粋関数に変換できる)の場合、不変テストはそれらの機能の厳密なスーパーセットとして単体テストに取って代わる可能性があるように思われます。各単体テストは、入力と出力で構成されます(命令型プログラミング言語では、「出力」は関数の戻りだけでなく、変更された状態でもありますが、これはカプセル化できます)。おそらく、手動で作成したすべての単体テスト入力をカバーするのに十分なランダム入力ジェネレーターを作成することができます(そして、それはあなたが考えもしなかったケースを生成するので、いくつか)。境界条件が原因でプログラムにバグが見つかった場合は、ランダム入力ジェネレーターを改善して、そのケースも生成するようにします。

したがって、課題は、すべての問題に対して有用な不変量を定式化できるかどうかです。私はそれがそうだと思います:最初に答えを計算するよりも、それが正しいかどうかを確認するための答えが得られたら、それははるかに簡単です。不変条件について考えることは、アドホックテストケースよりもはるかに優れた複雑なアルゴリズムの仕様を明確にするのにも役立ちます。これにより、問題のケースバイケースの考え方が促進されます。以前のバージョンのプログラムをモデルの実装として使用することも、別の言語のプログラムのバージョンを使用することもできます。最終的には、入力または出力を明示的にコーディングしなくても、以前のすべてのテストケースをカバーできるようになります。

私は気が狂ったのですか、それとも何かに取り組んでいますか?

4

4 に答える 4

24

1年後、私はこの質問に対する答えがあると思います:いいえ!特に、単体テストは回帰テストに常に必要であり、有用です。回帰テストでは、テストがバグレポートに添付され、コードベースに残り、バグが再発しないようにします。

ただし、単体テストは、入力がランダムに生成されるテストに置き換えることができると思います。命令型コードの場合でも、「入力」は命令型ステートメントの順序です。もちろん、ランダムデータジェネレーターを作成する価値があるかどうか、およびランダムデータジェネレーターに適切な分布を持たせることができるかどうかは別の問題です。ユニットテストは、ランダムジェネレーターが常に同じ結果をもたらす退化したケースです。

于 2010-09-06T02:39:02.883 に答える
9

あなたが提起したことは、関数型プログラミングにのみ適用される場合、非常に良い点です。あなたは命令型コードでこれをすべて達成する手段を述べましたが、なぜそれが行われないのかについても触れました-それは特に簡単ではありません。

それが単体テストに取って代わらないまさにその理由だと思います。命令型コードにはそれほど簡単には適合しません。

于 2009-04-20T04:24:59.613 に答える
1

疑わしい

私はこれらの種類のテストについて聞いたことがあります(使用されていません)が、2つの潜在的な問題があります。それぞれについてコメントをお願いします。

誤解を招く結果

私は次のようなテストについて聞いたことがあります:

  • reverse(reverse(list))等しい必要がありますlist
  • unzip(zip(data))等しい必要がありますdata

これらが幅広い入力に当てはまることを知っておくとよいでしょう。ただし、関数が入力を返すだけであれば、これらのテストは両方とも合格します。

たとえば、少なくとも1つのケースで正しい動作を証明するのとreverse([1 2 3])同じであることを確認してから、ランダムデータを使用してテストを追加したいと思うようです。[3 2 1]

テストの複雑さ

入力と出力の関係を完全に説明する不変テストは、関数自体よりも複雑になる可能性があります。複雑な場合はバグがある可能性がありますが、テスト用のテストはありません。

対照的に、優れた単体テストは単純すぎて、読者を台無しにしたり誤解したりすることはできません。reverse([1 2 3])「等しいと期待する」のバグを作成できるのはタイプミスだけ[3 2 1]です。

于 2013-11-19T13:48:34.433 に答える
0

元の投稿に書いたことは、この問題を思い出させました。これは、ループが正しいことを証明するためにループ不変条件が何であるかについての未解決の質問です...

とにかく、あなたが正式な仕様でどれだけ読んだかはわかりませんが、あなたはその考えに向かっています。デビッド・グリースの本は、この主題の古典の1つですが、私はまだ、日常のプログラミングでそれを迅速に使用するのに十分な概念を習得していません。正式な仕様に対する通常の対応は、その困難で複雑なものであり、セーフティクリティカルなシステムで作業している場合にのみ努力する価値があります。しかし、クイックチェックが公開しているものと同様の、使用可能なエンベロープ手法の裏側があると思います。

于 2012-03-20T01:03:15.653 に答える