2

これまで単体テストを使用したことがないので、CxxTest を試してみます。関数が std::vector を正しくソートするかどうかを確認するテストを作成しました。最初に、ベクターがソートされていないときにテストが失敗することを確認し、次に健全性チェックとして std::sort が機能するかどうかをテストしました (もちろん、機能しました)。ここまでは順調ですね。

次に、独自のソート関数を書き始めました。しかし、私は間違いを犯し、関数が正しくソートされませんでした。私のテストでは、並べ替え中のベクトルの中間状態が出力されなかったため、並べ替え関数のどこで問題が発生したかを判断するのが困難でした。私はcout自分のバグを見つけるためにステートメント (デバッガーを使用することもできた) を使用することになり、並べ替え関数が機能することを確認するまで単体テストを使用しませんでした。

ここで何か間違ったことをしていますか?単体テストは次のように簡単だと思いました

1) テストを書きます
2) 関数を書きます
3) テスト関数を書きます
4) テストが失敗したら関数を修正します
5) テストが通るまで 3 と 4 を繰り返します

私が使用したプロセスはもっと似ていました

1) テストを書く
2) 関数を書く
3) 関数をテストする
4) テストが失敗した場合、正しく動作するまで関数をデバッグする
5) 3 を繰り返す (関数が動作することが既にわかっている場合でも)

私のソート関数の設計は、私が書いたテストによって駆動されていなかったので、私のプロセスは真の TDD ではなかったように感じます。もっとテストを書くべきでしたか? たとえば、ベクトルがソートされているときの中間状態をチェックするテストなどです。

4

5 に答える 5

4

テストはコードをデバッグするものではありません。

私のプロセスは真の TDD ではなかったように感じます

あなたはテストを書きました。バグが見つかりました。バグを修正しました。テストに合格しました。システムは動作します!

これがテスト駆動開発の本質です。テストは、バグがあることを示し、テストが完了したことを示します。

とにかく、純粋な TDD や純粋な OOP などの精神障害を達成していないことに罪悪感を覚えます。進んで生産的になりましょう。

于 2009-11-23T15:52:29.950 に答える
2

ユニットテストは、あなたが書いているものの特定の外部の振る舞いに焦点を合わせており、アルゴリズムの中間状態を実際に理解することはできません。ソート関数はかなり特殊なケースです。

より一般的には、この種のビジネスロジックを扱っています

「注文価格は、合計金額が20ポンドを超える場合は10%の割引、顧客がゴールドメンバーの場合はさらに5%の割引で差し引かれた、注文アイテムの価格の合計です。」

次のようなテストをすぐに書くことができます

  • 注文アイテムはありません
  • 1つの注文アイテムの価値£20.00
  • 1つの注文アイテムの価値£20.01
  • 2つの注文アイテムの合計値£20.00ゴールドの顧客
  • ..。

など-これらのテストがコードのさまざまなブランチに適用され、正しく実行するのに役立つことは明らかです。

ソートコードについては、次のようなテストを行うと役立つ場合があります。

  • {0}
  • {1、2}
  • {2、1}
  • {1、1}

などですが、テストでは、QuickSortまたはBubbleSortなどを実行しているかどうかは実際にはわかりません。

于 2009-11-23T15:55:38.540 に答える
2

TDDプロセスは

  1. 赤: テストを書き、失敗することを確認する

  2. GREEN 合格するのに十分なだけのコードを書き、合格することを確認する

  3. コードのリファクタリング - テスト コードと本番コードの両方

ステップ 2 でデバッガーを使用する必要がある場合は、一度にテストしすぎている可能性があります。分割統治。並べ替えアルゴリズムの場合、分割はそれほど簡単ではありませんが、最初に空のベクトル、次に 1 つの要素を持つベクトル、次に 2 つの要素が既に順序付けされているベクトル、2 つの要素が間違った順序であるベクトルの並べ替えから始めましたか?

于 2009-11-24T07:42:28.490 に答える
2

すべての中間状態をテストしようとしないでください。ソート アルゴリズムがどのように機能するかは、誰も気にしません。ただ、その仕事を確実かつ迅速に行うことだけです。

代わりに、多くの異なるデータ セットの並べ替えをチェックするテストを記述します。すべての典型的な問題セットをテストします: 既にソートされたデータ、逆ソートされたデータ、ランダム データなど。

アプリケーションが安定した並べ替えを必要とする場合は、チェックをより慎重にする必要があります。並べ替えの比較関数が並べ替え時にテストしないテスト目的のためだけに、並べ替えられる各アイテムに一意のタグを追加することができますが、それ以外の場合は等しい 2 つの値が最終的に同じ相対順序になるようにするために使用できます。出力。

最後のアドバイス: テストでは、起こりうるすべての失敗ケースを前もって考える努力をしてください。ただし、成功するとは期待しないでください。後でより多くのエッジ ケースを発見したら、テストを追加する準備をしてください。テスト スイートは、正しいはずであるという数学的な理由がない限り、正確さに向かって進化する必要があります。

于 2009-11-23T15:47:53.110 に答える
1

上記のシーケンスの #4 の間に根本的な違いは見られません。TDD では、単体テストを記述して、合格した場合にコードが確実に機能することを確認します。合格するまでコードに取り組みます。バグが見つかった場合は、それを見つけるために別のテストを作成し、テストに合格すると、コードの作業が完了します。(それでも自信がない場合は、さらにテストを作成してください。) あなたのケースでは、コードをテストに適合させるのが予想以上に困難でした。

利点は、コード単位を機能させることよりも、物事を変更しても機能すること、および機能するタイミングを明確に定義できることです。(他にも利点があります。たとえば、テストは、コードが何を行うべきかのドキュメントとして機能します。)

いくつかの小さなテストを書きたいと思うかもしれませんが、並べ替え関数の途中で役立つものを書くかどうかはわかりません。関数の実装方法に大きく依存しているように思えますが、それはTDDの精神に反しているように思えます。

ところで、なぜ独自のソート関数を作成しているのですか? これは、ソート関数を作成したかったため (クラス、楽しみ、または学習のため) であって、生産上の理由からではないことを願っています。標準機能は、ほぼ確実に、これから作成するものよりも信頼性が高く、理解しやすく、通常は高速になります。正当な理由なく独自のコードに置き換えることはできません。

于 2009-11-23T15:49:57.367 に答える