4

ベイジアン分類器がスパムをフィルタリングする効果的な方法であることはよく知られています。これらはかなり簡潔にできますが (私たちのものは数百の LoC にすぎません)、結果を得る前にすべてのコア コードを事前に記述する必要があります。

ただし、TDD アプローチでは、テストに合格するための最小限のコードしか記述できないことが義務付けられているため、次のメソッド シグネチャが与えられます。

bool IsSpam(string text)

次のテキスト文字列は、明らかにスパムです。

"Cheap generic viagra"

私が書くことができるコードの最小量は次のとおりです。

bool IsSpam(string text)
{
    return text == "Cheap generic viagra"
}

ここで、別のテスト メッセージを追加するかもしれません。

"Online viagra pharmacy"

コードを次のように変更できます。

bool IsSpam(string text)
{
    return text.Contains("viagra");
}

...などなど。ある時点までは、コードは文字列チェックや正規表現などでごちゃごちゃになってしまいます。最初から考えたり、別の方法で書いたりするのではなく、コードを進化させたからです。

では、可能な限り単純なコードからコードを進化させてテストに合格することが適切なアプローチではない、このような状況で TDD はどのように機能するのでしょうか? (特に、最良の実装を自明に進化させることができないことが事前にわかっている場合)。

4

9 に答える 9

4

スパム フィルター アルゴリズムの低レベル部分のテストを作成することから始めます。

まず、アルゴリズムがどうあるべきかの大まかな設計を心に留めておく必要があります。次に、アルゴリズムのコア部分を分離し、そのテストを作成します。ベイズの定理を使用して単純な確率を計算するスパム フィルターの場合 (ベイズの分類器については知らないので、間違っている可能性があります)。最終的にアルゴリズムのすべての部分が実装され、それらを組み合わせるのが簡単になるまで、ボトムアップで段階的に構築します。

TDD を十分に小さいステップで実行できるようにするには、どのテストをどの順序で作成するかを理解するために多くの練習が必要です。1 つの新しいテストに合格するのに 10 行をはるかに超えるコードを記述する必要がある場合は、おそらく何か問題があります。小さなものから始めるか、いくつかの依存関係をモックします。大きすぎるステップを試みてひどく失敗するよりも、ステップが小さすぎて進行が遅くなるように、小さい側でエラーを起こす方が安全です。

あなたが持っている「安価なジェネリックバイアグラ」の例は、受け入れテストに適しているかもしれません. 最初にサンプル データを使用してスパム フィルターを初期化する必要があるため、TDD テストとしては役に立ちません。TDD テストはFIRSTである必要があります(F = 1 秒あたり数百または数千のテストのように高速)。

于 2009-04-20T09:23:41.313 に答える
2

私の見解は次のとおりです。テスト駆動開発とは、コーディングの前にテストを作成することを意味します。これは、テストを作成するコードの各ユニットが自明である必要があるという意味ではありません。

さらに、賢明で効果的な方法でタスクを実行するようにソフトウェアを計画する必要があります。単純に文字列を追加するだけでは、この問題に最適な設計にはならないようです。

つまり、可能な限り最小の機能からコードを作成 (およびテスト) しますが、そのように (疑似コードで、または好きな方法で) アルゴリズムを設計することはありません。

あなたと他の人が同意するかどうかを見るのは興味深いでしょう。

于 2009-04-20T08:51:24.277 に答える
0

ここでの問題は、テスト駆動開発ではなく、テストにあります。単一のテストに対してコードの開発を開始する場合、テストで行っていることは、文字列チェック関数を指定することだけです。

TDD の主なアイデアは、コードを書く前にテストについて考えることです。スパム フィルターを徹底的にテストすることはできませんが、数万または数十万のテスト ドキュメントによって妥当な近似値を見つけることができます。多くのテストが存在する場合、単純なベイズ アルゴリズムは、10 万行の switch ステートメントよりも単純なソリューションです。

実際には、100% の単体テストに合格することはできないため、できるだけ多くの単体テストに合格するように努める必要があります。また、テストが十分に現実的であることを確認する必要があります。このように考えると、テスト駆動開発と機械学習には多くの共通点があります。

于 2009-04-23T10:08:02.600 に答える
0

私にとって、テストに合格するための最小量のコードとは、関数全体IsSpam()です。これは、そのサイズと一致しています (わずか数百の LoC と言います)。

あるいは、インクリメンタル アプローチは、最初にコードを書いてから考えるとは主張しません。ソリューションを設計してコーディングし、特殊なケースまたはより優れたアルゴリズムで設計を改良できます。

とにかく、リファクタリングは単に古いものの上に新しいものを追加するだけではありません。私にとって、これはより破壊的なアプローチであり、単純な機能の古いコードを破棄し、洗練されたより精巧な機能の新しいコードに置き換えます。

于 2009-04-20T09:32:09.407 に答える
0

単体テストはありますよね?

つまり、コードをリファクタリングしたり、書き直したりして、単体テストを使用して何かが壊れていないかどうかを確認できるようになりました。

最初に動作させてから、きれいにします-2番目のステップの時間です:)

于 2009-04-20T09:34:47.153 に答える
0

(1) 数字が素数かどうかを言うのと同じように、文字列が「スパムである」または「スパムではない」とは言えません。これは黒でも白でもありません。

(2) テストに使用されたまさにその例を使用して文字列処理関数を記述することは正しくなく、TDD の目的ではないことは確かです。例は、一種の値を表す必要があります。TDD はばかげた実装を防げないので、何も知らないふりをしてはいけませんreturn text == "Cheap generic viagra"

于 2009-04-20T09:39:42.570 に答える
0

ベイジアン スパム フィルターを使用する場合は、既存の方法を使用する必要があるように思えます。特に、ベイズの定理、およびおそらく他の確率論を使用するでしょう。

その場合、最善のアプローチは、これらの方法に基づいてアルゴリズムを決定することです。これは、試行およびテストするか、場合によっては実験的に行う必要があります。次に、ユニット テストは、ispam が決定したアルゴリズムを正しく実装しているかどうかをテストするように設計する必要があります。また、結果が 0 と 1 の間にあることを確認する基本的なテストも行う必要があります。

重要なのは、単体テストは、アルゴリズムが適切かどうかをテストするようには設計されていないということです。それが賢明かどうかを確認するために、プログラムが実験として設計されているか、またはおそらくプログラムが実験として設計されていることを知っている必要があります。

isspam 関数のパフォーマンスが重要でないと言っているわけではありません。ただし、単体テストの一部である必要はありません。データは、アルファ テストからのフィードバック、新しい理論上の結果、または独自の実験から得られたものである可能性があります。その場合、新しいアルゴリズムが必要になる可能性があり、新しい単体テストが必要になります。

乱数ジェネレーターのテストに関するこの質問も参照してください。

于 2009-04-20T11:20:48.520 に答える
0

あなたが説明している問題は理論的なものであり、テストに応じてクラフトを追加すると、大きくて厄介な泥のボールができます。欠けているものは非常に重要です。

サイクルは次のとおりです: 赤 --> 緑 --> リファクタリング

赤と緑の間を行き来するだけではありません。テストに合格 (緑) したらすぐに、本番コードとテストをリファクタリングします。次に、次の失敗したテスト (赤) を記述します。

リファクタリングしている場合は、重複と乱雑さを排除し、それが大きくなるにつれてスロップします。メソッドの抽出、スコアリングと評価の構築、そしておそらく外部ツールの導入のポイントにすぐにたどり着きます。それがうまくいく最も簡単なことであるとすぐにあなたはそれをするでしょう.

赤と緑の間を行き来しないでください。そうしないと、すべてのコードがごちゃごちゃになります。そのリファクタリングのステップは、オプションでも任意でもありません。それは不可欠です。

于 2010-03-02T18:56:24.193 に答える
0

特定の文字列がスパムであるかどうかを確認することは、実際には単体テストではなく、むしろ顧客テストだと思います。実際には赤/強欲タイプではないため、重要な違いがあります。実際には、おそらく数百のテスト ドキュメントが必要です。最初のうちは、スパムとして分類されるものもありますが、製品を改善するにつれて、分類がより直接的に目的に一致するようになります。そのため、一連のテスト ドキュメントをロードして分類し、全体的なスコアを評価するカスタム アプリを作成する必要があります。その顧客テストが終了すると、アルゴリズムを実装していないため、スコアは非常に悪くなります。しかし、今後の進捗状況を測定する手段が得られました。これは、今後予想される学習/変更/実験の量を考えると、非常に価値があります。

アルゴリズムを実装するとき (および直接の顧客テストでさえも)、実際の単体テストで TDD を実行できます。ベイジアン フィルター コンポーネントの最初のテストでは、特定の文字列がスパムとして評価されるかどうかは測定されませんが、文字列がベイジアン フィルター コンポーネントを適切に通過するかどうかが測定されます。次のテストでは、ベイジアン フィルターの実装方法 (ノードを正しく構造化する、トレーニング データを適用するなど) に焦点を当てます。

製品がどこに向かっているのかについてのビジョンが必要であり、テストと実装はそのビジョンに向けられる必要があります。また、盲目的に顧客テストを追加するだけではなく、製品全体のビジョンを念頭に置いてテストを追加する必要があります。ソフトウェア開発の目標には、作成できる良いテストと悪いテストがあります。

于 2010-03-02T19:14:50.673 に答える