value-parameterized tests を異なるデータ型の複数のパラメーターで使用できるC++ Googleテストを作成したいと思います。これは、C++/CLIで作成された次のmbUnitテストの複雑さに理想的に一致します。
MbUnitの説明については、 Hanselman2006の記事 を参照してください。この2019年の編集の時点で、彼が含む他のリンクは無効になっています。
これがどれほどコンパクトであるかに注意してください。_[Test]
_属性はこれがテストメソッドであることを示し、[Row(...)]
属性はインスタンス化の値を定義します。
_[Test]
[Row("Empty.mdb", "select count(*) from collar", 0)]
[Row("SomeCollars.mdb", "select count(*) from collar", 17)]
[Row("SomeCollars.mdb", "select count(*) from collar where max_depth=100", 4)]
void CountViaDirectSQLCommand(String^ dbname, String^ command, int numRecs)
{
String^ dbFilePath = testDBFullPath(dbname);
{
StAnsi fpath(dbFilePath);
StGdbConnection db( fpath );
db->Connect(fpath);
int result = db->ExecuteSQLReturningScalar(StAnsi(command));
Assert::AreEqual(numRecs, result);
}
}
_
またはさらに良いことに、C#からのこのよりエキゾチックなテスト(C++/CLIで可能なものを超えて.Net属性で定義できるものの境界を押し広げます):
_[Test]
[Row("SomeCollars.mdb", "update collar set x=0.003 where hole_id='WD004'", "WD004",
new string[] { "x", "y" },
new double[] { 0.003, 7362.082 })] // y value unchanged
[Row("SomeCollars.mdb", "update collar set x=1724.8, y=6000 where hole_id='WD004'", "WD004",
new string[] { "x", "y" },
new double[] { 1724.8, 6000.0 })]
public void UpdateSingleRowByKey(string dbname, string command, string idValue, string[] fields, double[] values)
{
...
}
_
help によると値パラメーター化されたテストでは、テストを1回だけ記述してから、任意の数のパラメーター値で簡単にインスタンス化して実行できます。しかしそれはテストケースの数を指していると私はかなり確信しています。
データ型を変更しなくても、パラメーター化されたテストは1つのパラメーターしか取得できないようです。
2019更新
この質問についてpingを送信したため、追加しました。示されているRow
属性は、mbUnitの一部です。
MbUnitの説明については、 Hanselman2006の記事 を参照してください。この2019年の編集の時点で、彼が含む他のリンクは無効になっています。
C#の世界では、NUnitは パラメーター化されたテスト を、ジェネリックスを パラメーター化されたフィクスチャ として処理する方法を含むより強力で柔軟な方法で追加しました。
次のテストは15回実行され、xの値ごとに3回実行され、それぞれが-1.0から+1.0までの5つのランダムなdoubleと組み合わされます。
_[Test]
public void MyTest(
[Values(1, 2, 3)] int x,
[Random(-1.0, 1.0, 5)] double d)
{
...
}
_
次のテストフィクスチャは、NUnitによって3回インスタンス化され、引数の各セットを適切なコンストラクタに渡します。引数として提供されたデータ型に一致する3つの異なるコンストラクターがあることに注意してください。
_[TestFixture("hello", "hello", "goodbye")]
[TestFixture("Zip", "Zip")]
[TestFixture(42, 42, 99)]
public class ParameterizedTestFixture
{
private string eq1;
private string eq2;
private string neq;
public ParameterizedTestFixture(string eq1, string eq2, string neq)
{
this.eq1 = eq1;
this.eq2 = eq2;
this.neq = neq;
}
public ParameterizedTestFixture(string eq1, string eq2)
: this(eq1, eq2, null) { }
public ParameterizedTestFixture(int eq1, int eq2, int neq)
{
this.eq1 = eq1.ToString();
this.eq2 = eq2.ToString();
this.neq = neq.ToString();
}
[Test]
public void TestEquality()
{
Assert.AreEqual(eq1, eq2);
if (eq1 != null && eq2 != null)
Assert.AreEqual(eq1.GetHashCode(), eq2.GetHashCode());
}
[Test]
public void TestInequality()
{
Assert.AreNotEqual(eq1, neq);
if (eq1 != null && neq != null)
Assert.AreNotEqual(eq1.GetHashCode(), neq.GetHashCode());
}
}
_
はい、1つのパラメータがあります。ただし、そのパラメータを任意に複雑にすることができます。ドキュメントのコードを適応させて、Row
タイプを使用できます。次に例を示します。
class AndyTest : public ::testing::TestWithParam<Row> {
// You can implement all the usual fixture class members here.
// To access the test parameter, call GetParam() from class
// TestWithParam<T>.
};
次に、パラメーター化されたテストを定義します。
TEST_P(AndyTest, CountViaDirectSQLCommand)
{
// Call GetParam() here to get the Row values
Row const& p = GetParam();
std::string dbFilePath = testDBFullPath(p.dbname);
{
StAnsi fpath(dbFilePath);
StGdbConnection db(p.fpath);
db.Connect(p.fpath);
int result = db.ExecuteSQLReturningScalar(StAnsi(p.command));
EXPECT_EQ(p.numRecs, result);
}
}
最後に、それをインスタンス化します。
INSTANTIATE_TEST_CASE_P(InstantiationName, AndyTest, ::testing::Values(
Row("Empty.mdb", "select count(*) from collar", 0),
Row("SomeCollars.mdb", "select count(*) from collar", 17),
Row("SomeCollars.mdb", "select count(*) from collar where max_depth=100", 4)
));
パラメータとしてカスタム構造を使用する代わりに、パラメータジェネレータ::testing::Combine(g1, g2, ..., gn)
を使用することもできます。このジェネレーターを使用すると、他のパラメータージェネレーターを、提供された値のタイプと一致するテンプレートタイプを持つタイプ_std::Tuple
_のパラメーターのセットに組み合わせることができます。
このジェネレーターは、提供された値の デカルト積 を生成することに注意してください。つまり、すべての可能な順序付きタプルが作成されます。元の質問は、提供された値を持つパラメーターの厳密な配列を要求していると思いますが、これはサポートされていません。厳密なパラメーターの配列が必要な場合は、パラメータージェネレーター::testing::Values(v1, v2, ..., vN)
でタプルを使用できます。各値は個別のタプルです。
例:
_#include <string>
#include <Tuple>
class MyTestSuite :
public testing::TestWithParam<std::Tuple<std::string, std::string, int>>
{
};
TEST_P(MyTestSuite, TestThatThing)
{
functionUnderTest(std::get<0>(GetParam()),
std::get<1>(GetParam()),
std::get<2>(GetParam()));
. . .
}
INSTANTIATE_TEST_SUITE_P(
MyTestGroup,
MyTestSuite,
::testing::Combine(
::testing::Values("FirstString1", "FirstString2"),
::testing::Values("SecondString1", "SecondString2"),
::testing::Range(10, 13)));
INSTANTIATE_TEST_SUITE_P(
MyOtherTestGroupThatUsesStrictParameters,
MyTestSuite,
::testing::Values(
{"FirstString1", "SecondString1", 10},
{"FirstString2", "SecondString2", 32},
{"FirstString3", "SecondString3", 75}));
_
上記の例では、MyTestGroup
用に作成されたパラメーターは次のようになります。
_[
{"FirstString1", "SecondString1", 10},
{"FirstString1", "SecondString1", 11},
{"FirstString1", "SecondString1", 12},
{"FirstString1", "SecondString2", 10},
{"FirstString1", "SecondString2", 11},
{"FirstString1", "SecondString2", 12},
{"FirstString2", "SecondString1", 10},
{"FirstString2", "SecondString1", 11},
{"FirstString2", "SecondString1", 12},
{"FirstString2", "SecondString2", 10},
{"FirstString2", "SecondString2", 11},
{"FirstString2", "SecondString2", 12}
]
_
詳細については、GoogleTestのドキュメントを参照してください。 (2019年12月17日にアクセス)