9

私のほとんどの C++ プロジェクトでは、次のように ASSERTION ステートメントを多用しました。

int doWonderfulThings(const int* fantasticData)
{
    ASSERT(fantasticData);
    if(!fantasticData)
        return -1;
    // ,,,
    return WOW_VALUE;
}

しかし、TDD コミュニティは次のようなことを楽しんでいるようです。

int doMoreWonderfulThings(const int* fantasticData)
{
    if(!fantasticData)
        return ERROR_VALUE;
    // ...
    return AHA_VALUE;
}

TEST(TDD_Enjoy)
{
    ASSERT_EQ(ERROR_VALUE, doMoreWonderfulThings(0L));
    ASSERT_EQ(AHA_VALUE, doMoreWonderfulThings("Foo"));
}

私の経験では、最初のアプローチで非常に多くの微妙なバグを取り除くことができました。しかし、TDD アプローチは、レガシー コードを処理するための非常に賢明なアイデアです。

「Google」 - 彼らは「FIRST METHOD」を「救命胴衣を着て海岸を歩き、安全ガードなしで海を泳ぐ」と比較します。

どちらの方がよいですか?ソフトウェアを堅牢にするのはどれですか?

4

5 に答える 5

4

私の(限られた)経験では、最初のオプションはかなり安全です。テストケースでは、定義済みの入力のみをテストし、結果を比較します。これは、考えられるすべてのエッジケースがチェックされている限り、うまく機能します。最初のオプションは、すべての入力をチェックして「ライブ」値をテストするだけで、バグを非常に迅速に除外しますが、パフォーマンスが低下します。

Code Completeで、 Steve McConnell は、最初の方法を使用してデバッグビルドのバグをうまく除外できることを学びました。リリース ビルドでは、すべてのアサーションを除外して (たとえば、コンパイラ フラグを使用して)、追加のパフォーマンスを得ることができます。

私の意見では、最良の方法は両方の方法を使用することです。

不正な値をキャッチする方法 1

int doWonderfulThings(const int* fantasticData)
{
    ASSERT(fantasticData);
    ASSERTNOTEQUAL(0, fantasticData)

    return WOW_VALUE / fantasticData;
}

方法 2 は、アルゴリズムのエッジ ケースをテストします。

int doMoreWonderfulThings(const int fantasticNumber)
{
    int count = 100;
    for(int i = 0; i < fantasticNumber; ++i) {
        count += 10 * fantasticNumber;
    }
    return count;
}

TEST(TDD_Enjoy)
{
    // Test lower edge
    ASSERT_EQ(0, doMoreWonderfulThings(-1));
    ASSERT_EQ(0, doMoreWonderfulThings(0));
    ASSERT_EQ(110, doMoreWonderfulThings(1));

    //Test some random values
    ASSERT_EQ(350, doMoreWonderfulThings(5));
    ASSERT_EQ(2350, doMoreWonderfulThings(15));
    ASSERT_EQ(225100, doMoreWonderfulThings(150));
}
于 2008-08-19T23:49:54.450 に答える
2

どちらのメカニズムにも価値があります。適切なテストフレームワークはとにかく標準のassert()をキャッチするため、アサートを失敗させるテストを実行すると、テストが失敗します。

私は通常、各c++メソッドの先頭にコメント'//preconditions'を含む一連のアサートを持っています。これは、メソッドが呼び出されたときにオブジェクトが持つと予想される状態の健全性チェックにすぎません。これらは、機能をテストするときに実行時に機能するだけでなく、テスト時にも機能するため、どのTDDフレームワークにもうまく適合します。

于 2008-08-22T22:24:14.350 に答える
1

テスト パッケージが doMoreWonderfulThings のようなアサートをキャッチできない理由はありません。これは、ASSERT ハンドラーでコールバック メカニズムをサポートするか、テスト アサートに try/catch ブロックを含めることで実行できます。

于 2008-08-19T23:31:17.367 に答える
0

あなたが言及している特定の TDD サブコミュニティはわかりませんが、私が遭遇した TDD パターンは、肯定的な結果を得るために Assert.AreEqual() を使用するか、それ以外の場合は ExpectedException メカニズム (.NET の属性など) を使用して宣言します。観察すべきエラー。

于 2008-08-19T23:23:51.487 に答える
0

C++ では、ほとんどのテスト フレームワークを使用する場合、方法 2 を好みます。これにより、通常、障害レポートが理解しやすくなります。これは、テストが作成されてから数か月から数年後のテストでは非常に貴重です。

私の理由は、ほとんどの C++ テスト フレームワークは、スタック トレース情報なしで、アサートが発生した場所のファイルと行番号を出力するからです。そのため、ほとんどの場合、テスト ケース内ではなく、関数またはメソッド内でレポート行番号を取得します。

アサートがキャッチされ、呼び出し元から再アサートされた場合でも、レポート行は catch ステートメントと共にあり、アサートしたメソッドまたは関数を呼び出したテスト ケース行の近くにない場合があります。これは、アサートされた関数がテスト ケースで複数回使用された可能性がある場合に、非常に厄介です。

ただし、例外もあります。たとえば、Google のテスト フレームワークには、例外が発生した場合にトレースの一部として出力される範囲指定されたトレース ステートメントがあります。そのため、一般化されたテスト関数の呼び出しをトレース スコープでラップし、正確なテスト ケースのどの行が失敗したかを 1 ~ 2 行で簡単に知ることができます。

于 2013-08-27T21:01:59.080 に答える