可以用Googletest值参数化多个,不同类型的参数匹配mbUnit的灵活性
Can Googletest value-parameterized with multiple, different types of parameters match mbUnit flexibility?
我想编写C++Google测试,它可以使用具有不同数据类型的多个参数的值参数化测试,与以下用C++/CLI编写的mbUnit测试的复杂性完美匹配。
有关mbUnit的解释,请参阅Hanselman 2006年的文章。截至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#的这种更奇特的测试(将.Net属性中可以定义的内容的边界推到C++/CLI中可能定义的范围之外):
[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)
{
...
}
帮助中说,值参数化测试只允许您编写一次测试,然后使用任意数量的参数值轻松地实例化和运行它但我相当确定这是指测试用例的数量。
即使不改变数据类型,在我看来,参数化测试也只能接受一个参数?
2019更新
添加是因为我收到了关于这个问题的ping。显示的Row
属性是mbUnit的一部分。
有关mbUnit的解释,请参阅Hanselman 2006年的文章。截至2019年的编辑,他包含的其他链接都已失效。
在C#世界中,NUnit以一种更强大、更灵活的方式添加了参数化测试,包括将泛型处理为参数化固定装置。
以下测试将执行十五次,每个x值执行三次,每次结合从-1.0到+1.0的5次随机加倍。
[Test]
public void MyTest(
[Values(1, 2, 3)] int x,
[Random(-1.0, 1.0, 5)] double d)
{
...
}
下面的测试夹具将由NUnit实例化三次,将每组参数传递给相应的构造函数。请注意,有三种不同的构造函数,它们与作为参数提供的数据类型相匹配。
[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());
}
}
是的,只有一个参数。不过,您可以使该参数任意复杂。您可以调整文档中的代码以使用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日访问)
- 我收到同义重复编译器错误。我应该如何修复"类型"X"的参数与类型"X"的参数不兼容?
- 在模板中显示参数的类型
- 列表参数的类型定义
- 视觉工作室 2017;启用 /permissive 时,类型 "const wchar_t *" 的参数与类型 "PWSTR" 的参数不兼容
- 是否可以在C++中有一个"generic"模板参数,该参数可以是非类型模板参数或类型?
- 如果可推导类型上有替换,可变参数模板类型推导会使编译器崩溃
- 通过引用传递参数时C++类型转换
- 推断指针非类型模板参数的类型
- 可变参数模板参数扩展 类型为 std::function 的类成员
- 类具有相同的接口,但参数的类型不同
- 将强制转换简化为取决于参数的类型
- 具有可变参数非类型参数的模板专用化
- 使模板函数按函数参数选择类型
- 为表示一个或多个操作的C++函数的int参数寻找类型安全的替换
- 编译器给出错误:format 指定类型 'float *',但参数的类型'double' [-Wformat]
- 参数数据类型未知的可变参数函数
- 将可变参数模板类型转换为 void,预期')'之前
- 有没有办法根据 lambda 参数返回类型部分专用化我的模板化函数?
- 将参数列表未知的可变参数模板类型定义为 std::map 值类型
- C++ 类型 "char" 的参数与类型 "const char" 的参数不兼容