2012-01-23 12 views
6

私は数式を実装するコードをリファクタリングしています。私はテストのスキルを向上させるために、まずテストを行い、コードをカバーしたままにします。複数パラメータの式をテストする方法

この特定のコードは、3つのパラメータを取り、値を返す数式です。理論的には、入力パラメータを変更して対応する期待値に対して結果をチェックするだけで、数多くのテストを行うことができます。

しかし、私はそれを行うためのより良い方法があると思っていました。私はValue Parameterized Testsを見つけました。

これで、さまざまな入力のテストを自動的に作成する方法がわかりました。
しかし、それに対応する期待値を計算結果と比較するにはどうすればよいですか?

私が思い付くことができる唯一のことは、スタティックルックアップテーブルとルックアップテーブルのインデックスであり、実行ごとにインクリメントされるテキストフィクスチャの静的メンバーです。

#include "gtest/gtest.h" 

double MyFormula(double A, double B, double C) 
{ 
    return A*B - C*C; // Example. The real one is much more complex 
} 

class MyTest:public ::testing::TestWithParam<std::tr1::tuple<double, double, double>> 
{ 
protected: 

    MyTest(){ Index++; } 
    virtual void SetUp() 
    { 
     m_C = std::tr1::get<0>(GetParam()); 
     m_A = std::tr1::get<1>(GetParam()); 
     m_B = std::tr1::get<2>(GetParam()); 
    } 

    double m_A; 
    double m_B; 
    double m_C; 

    static double ExpectedRes[]; 
    static int Index; 

}; 

int MyTest::Index = -1; 

double MyTest::ExpectedRes[] = 
{ 
//    C = 1 
//  B: 1  2  3  4  5  6  7  8  9 10 
/*A = 1*/ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 
/*A = 2*/ 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0, 15.0, 17.0, 19.0, 
/*A = 3*/ 2.0, 5.0, 8.0, 11.0, 14.0, 17.0, 20.0, 23.0, 26.0, 29.0, 

//    C = 2 
//  B:  1  2  3  4  5  6  7  8  9 10 
/*A = 1*/ -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 
/*A = 2*/ -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0, 16.0, 
/*A = 3*/ -1.0, 2.0, 5.0, 8.0, 11.0, 14.0, 17.0, 20.0, 23.0, 26.0, 
}; 

TEST_P(MyTest, TestFormula) 
{ 
    double res = MyFormula(m_A, m_B, m_C); 
    ASSERT_EQ(ExpectedRes[Index], res); 
} 

INSTANTIATE_TEST_CASE_P(TestWithParameters, 
         MyTest, 
         testing::Combine(testing::Range(1.0, 3.0), // C 
              testing::Range(1.0, 4.0), // A 
              testing::Range(1.0, 11.0) // B 
             )); 

これは良いアプローチですか、それともそれぞれの実行で正しい予期される結果を得る良い方法がありますか?

答えて

0

私は単体テストの経験はあまりありませんが、数学者としてはあなたができることはそれほど多くないと思います。

数式の不変量を知っていれば、それらをテストできますが、それはほんのわずかなシナリオでのみ意味をなさないと思います。

たとえば、自然指数関数を正しく実装している場合は、テストすることをお奨めします。知識を利用することができます。その微分は関数自体と同じ値を持つ必要があります。その後、百万点の微分値の近似値を計算し、それらが実際の関数値に近いかどうかを調べることができます。

1

ハードコーディングすると、テストケースの数が再び制限されているように見えます。データ駆動型モデルを完成させたい場合は、フラットファイル/ xml/xlsファイルから期待される結果を入力することをお勧めします。

+0

感謝を。この場合、私が従わなければならない仕様は、数式にいくつかの値に期待される結果を加えたテーブルを加えたものです。私の結果がそれらのテーブルと一致すれば、私はそれをOKにしてしまったと確信することができます。実際、テストのおかげで、すでに仕様書に間違った値が見つかっています。 – MikMik

+0

それは素晴らしいです。テストクラス内にテストデータを追加すると、将来別のシナリオをテストする場合に問題が発生し、クラスを再度更新する必要があります。しかし、外部ファイルからテストデータにアクセスすると、テストケースの保守性が低下します。そのフラットファイルを更新して新しいテストデータを追加しようとしているからです。それでおしまい。あなたのクラスを構築し、それを再度展開する必要はありません。 –

+0

@PritamKarmakar、テストケースの保守性が向上することを意味します。それを維持するために必要な努力は軽減されるでしょう。 – Alan

6

入力とともに予想される結果を含めます。 3倍の入力値の代わりに、テストパラメータを4タプルにします。

class MyTest: public ::testing::TestWithParam< 
    std::tr1::tuple<double, double, double, double>> 
{ }; 

TEST_P(MyTest, TestFormula) 
{ 
    double const C = std::tr1::get<0>(GetParam()); 
    double const A = std::tr1::get<1>(GetParam()); 
    double const B = std::tr1::get<2>(GetParam()); 
    double const result = std::tr1::get<3>(GetParam()); 

    ASSERT_EQ(result, MyFormula(A, B, C)); 
} 

欠点は、あなたがtesting::Combineで簡潔なテストパラメータを維持することはできませんということです。代わりに、testing::Valuesを使用して、テストする4タプルを定義することができます。引数の数をValuesに設定すると、すべてのC = 1ケースを1つに、C = 2ケースを別のケースに入れるなど、インスタンス化を分割できます。

INSTANTIATE_TEST_CASE_P(
    TestWithParametersC1, MyTest, testing::Values(
    //   C  A  B 
    make_tuple(1.0, 1.0, 1.0, 0.0), 
    make_tuple(1.0, 1.0, 2.0, 1.0), 
    make_tuple(1.0, 1.0, 3.0, 2.0), 
    // ... 
)); 

INSTANTIATE_TEST_CASE_P(
    TestWithParametersC2, MyTest, testing::Values(
    //   C  A  B 
    make_tuple(2.0, 1.0, 1.0, -3.0), 
    make_tuple(2.0, 1.0, 2.0, -2.0), 
    make_tuple(2.0, 1.0, 3.0, -1.0), 
    // ... 
)); 

それとも、testing::ValuesInを使用し、あなたのインスタンス化から分離し、アレイ内のすべての値を置くことができます。

std::tr1::tuple<double, double, double, double> const FormulaTable[] = { 
    //   C  A  B 
    make_tuple(1.0, 1.0, 1.0, 0.0), 
    make_tuple(1.0, 1.0, 2.0, 1.0), 
    make_tuple(1.0, 1.0, 3.0, 2.0), 
    // ... 
    make_tuple(2.0, 1.0, 1.0, -3.0), 
    make_tuple(2.0, 1.0, 2.0, -2.0), 
    make_tuple(2.0, 1.0, 3.0, -1.0), 
    // ... 
}; 

INSTANTIATE_TEST_CASE_P(
    TestWithParameters, MyTest, ::testing::ValuesIn(FormulaTable)); 
関連する問題