11

私は googletest を使用してテストを実装し始め、値パラメーター化されたテストに関するドキュメントでこの引用に出くわしました

  • さまざまな入力に対してコードをテストしたい (別名データ駆動型テスト)。この機能は悪用されやすいので、良識を持って実行してください。

次のことを行うとき、私は実際にシステムを「悪用」していると思います。この問題についての意見や意見を聞きたいです。

次のコードがあるとします。

template<typename T>
struct SumMethod {
     T op(T x, T y) { return x + y; }   
};

// optimized function to handle different input array sizes 
// in the most efficient way
template<typename T, class Method> 
T f(T input[], int size) {
    Method m;
    T result = (T) 0;
    if(size <= 128) {
        // use m.op() to compute result etc.
        return result;
    }
    if(size <= 256) {
        // use m.op() to compute result etc.
        return result;
    }
    // ...
}

// naive and correct, but slow alternative implementation of f()
template<typename T, class Method>
T f_alt(T input[], int size);

わかりました。したがって、このコードでは、ランダムに生成されたデータのさまざまな入力配列サイズをf()( と比較して) テストして、分岐の正確性をテストすることは確かに理にかなっています。その上、 、 などのようなものf_alt()がいくつかあるので、さまざまなタイプに対してもかなりの数のテストを実行しています。structsSumMethodMultiplyMethod

typedef MultiplyMethod<int> MultInt;
typedef SumMethod<int> SumInt;
typedef MultiplyMethod<float> MultFlt;
// ...
ASSERT(f<int, MultInt>(int_in, 128), f_alt<int, MultInt>(int_in, 128));
ASSERT(f<int, MultInt>(int_in, 256), f_alt<int, MultInt>(int_in, 256));
// ...
ASSERT(f<int, SumInt>(int_in, 128), f_alt<int, SumInt>(int_in, 128));
ASSERT(f<int, SumInt>(int_in, 256), f_alt<int, SumInt>(int_in, 256));
// ...
const float ep = 1e-6;
ASSERT_NEAR(f<float, MultFlt>(flt_in, 128), f_alt<float, MultFlt>(flt_in, 128), ep);
ASSERT_NEAR(f<float, MultFlt>(flt_in, 256), f_alt<float, MultFlt>(flt_in, 256), ep);
// ...

もちろん、私の質問は次のとおりです。これは意味がありますか?なぜこれが悪いのでしょうか?

float実際、 s wheref()f_alt()を使用してテストを実行すると、丸めのために異なる値が返される「バグ」が見つかりましたSumMethod。これは、入力配列を事前に並べ替えることなどで改善できます。

4

3 に答える 3

11

主な問題は、「ランダムに生成されたデータ」でのテストだと思います。テスト ハーネスが実行されるたびにこのデータが再生成されるかどうかは、あなたの質問からは明らかではありません。そうである場合、テスト結果は再現できません。いくつかのテストが失敗した場合、奇妙なランダムなテストデータの組み合わせで、ブルームーンで一度ではなく、実行するたびに失敗するはずです。

したがって、私の意見では、テスト データを事前に生成し、テスト スイートの一部として保持する必要があります。また、データセットが、十分なコード カバレッジを提供するのに十分な大きさと多様性を備えていることを確認する必要があります。

さらに、Ben Voigt が以下でコメントしたように、ランダムなデータのみでテストするだけでは十分ではありません。アルゴリズムのコーナー ケースを特定し、これらのケース専用に調整されたデータを使用して個別にテストする必要があります。ただし、私の意見では、ランダム データを使用した追加のテストは、コーナー ケースをすべて知っているかどうか確信が持てない場合にも有益です。ランダムデータを使用して偶然ヒットする可能性があります。

于 2011-10-08T18:08:21.387 に答える
6

問題は、int と同じ方法で float の正しさを主張できないことです。

計算値と期待値のわずかな差である特定のイプシロン内で正確性をチェックします。それがあなたにできる最善のことです。これは、すべての浮動小数点数に当てはまります。

次のことを行うとき、私は実際にシステムを「悪用」していると思います

その記事を読む前に、これは悪いことだと思いましたか? 何が悪いのか明確にできますか?

いつかこの機能をテストする必要があります。そのためにはデータが必要です。虐待はどこに?

于 2011-10-06T15:30:45.247 に答える
0

それが悪い理由の 1 つは、データ駆動型テストは保守が難しく、長期間にわたってテスト自体にバグが入りやすくなることです。詳細については、こちらをご覧ください: http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

また、私の観点からすると、ユニットテストは、深刻なリファクタリングを行っていて、ロジックを間違った方法で変更していないかどうかわからない場合に最も役立ちます。そのような変更を行った後にランダム データ テストが失敗する場合、次のように推測できます。データが原因なのか、変更が原因なのか?

ただし、これは役立つと思います (100% 再現できないストレス テストと同じです)。しかし、継続的インテグレーション システムを使用している場合、ランダムに生成された大量のデータを使用したデータ駆動型テストをシステムに含める必要があるかどうかはわかりません。一度に多くのランダムなテストを定期的に行う個別の展開を作成したいと思います (したがって、実行するたびに何か悪いものを発見する可能性が非常に高いはずです)。しかし、通常のテスト スイートの一部としてはリソースが多すぎます。

于 2011-10-13T23:28:40.210 に答える