[英]Data-driven unit tests with google test
I am currently writing unit tests for an embedded application using googles unit test framework . 我目前正在使用Googles单元测试框架为嵌入式应用程序编写单元测试。 Now my boss got upset that the data I test with (ie the values with which I call methods of the class under test) is hard wired in the tests. 现在,我的老板很生气,我测试所用的数据(即我用来调用被测类的方法的值)在测试中被硬连线。 He requests to have this data read-in from a file. 他要求从文件中读取此数据。 His argument is that it would thus be easier to add another test for a corner case that was previously forgotten. 他的论点是,为以前被遗忘的极端情况添加另一个测试会更容易。 I am not that experienced with unit tests but so far that was not how I did it. 我没有单元测试的经验,但是到目前为止,这还不是我的经验。 So I tried to figure out what would be the best way to do it - even if it is a good idea to do it at all. 因此,我试图弄清楚什么是最好的方法-即使完全是个好主意。 I quickly came across the DDT (data-driven testing) approach. 我很快想到了DDT(数据驱动测试)方法。
The google unit test framework has a feature they call " Value-Parameterized Tests ". Google单元测试框架具有一个称为“ 值参数化测试 ”的功能。 With that my test fixture becomes a template class and I can pass in parameters. 这样,我的测试装置便成为模板类,并且可以传递参数。 However, I see some problems with this: 但是,我看到了一些问题:
I would have imagined that something as mature as the google test framework to make it easier. 我本来可以想象到,与Google测试框架一样成熟的东西可以使其变得更容易。 However, they write 但是,他们写道
value-parameterized tests come handy [when] you want to test your code over various inputs (aka data-driven testing). 当您想通过各种输入来测试代码(也称为数据驱动的测试)时,可以使用值参数化的测试。 This feature is easy to abuse, so please exercise your good sense when doing it! 此功能易于滥用,因此在使用时请多加注意!
Additionally there exists this blogpost TotT: Data Driven Traps , also warning me of (abusing) data-driven unit tests. 此外,还有一篇博客文章《 TotT:数据驱动的陷阱》 ,也警告我(滥用)数据驱动的单元测试。
So my question comes down to: 所以我的问题归结为:
I am not really bound to googletest and basically free to choose any framework I'd like, though. 不过,我并不是真的要受googletest的束缚,基本上可以自由选择我想要的任何框架。
EDIT 编辑
I found the following statement in an FAQ entry of the googletest FAQs 我在googletest常见问题解答的常见问题解答条目中找到了以下语句
Google Test doesn't yet have good support for [...] data-driven tests in general. 总体而言,Google Test还没有对数据驱动测试的良好支持。 We hope to be able to make improvements in this area soon. 我们希望能够尽快在这方面进行改进。
GTest has support for it - but maybe they do not know... GTest支持它-但也许他们不知道...
Use testing::ValuesIn
- like in this simplified example: 使用testing::ValuesIn
在此简化示例中类似:
class SomeTests : public TestWithParam<int>
{
public:
};
TEST_P(SomeTests, shouldBePositive)
{
ASSERT_GT(GetParam(), 0);
}
And - the way how to get values from input stream: 并且-如何从输入流中获取值的方式:
std::ifstream inputValuesFromFile("input.txt");
INSTANTIATE_TEST_CASE_P(FromFileStream,
SomeTests,
ValuesIn(std::istream_iterator<int>(inputValuesFromFile),
std::istream_iterator<int>()));
To use more complicated types than "int" you need to write an operator >> for it - like: 要使用比“ int”更复杂的类型,您需要为其编写一个运算符>>-例如:
struct A
{
int a;
std::vector<int> b;
}
std::istream& operator >> (std::istream& is, A& out)
{
std::size_t bSize;
if ((is >> A.a) && (is >> bSize))
{
out.b.reserve(bSize);
while (bSize-- > 0)
{
int b;
if (!(is >> b))
break;
out.b.push_back(b);
}
}
return is;
}
Of course - in more complicated cases - consider to use XMl-like (json?) formats and some more specialized iterators than std::istream_iterator<T>
. 当然-在更复杂的情况下-考虑使用类似于XMl的(json?)格式和一些比std::istream_iterator<T>
更专门的迭代器。
For XML - like formats - you might consider such scheme (this is very hypothetical code - I do not have any such library in my mind): 对于XML(如格式),您可以考虑采用这种方案(这是非常假设的代码,我脑海中没有任何此类库):
SomeLib::File xmlData("input.xml");
class S1BasedTests : public TestWithParam<S1>
{};
TEST_P(S1BasedTests , shouldXxxx)
{
const S1& s1 = GetParam();
...
}
auto s1Entities = file.filterBy<S1>("S1");
INSTANTIATE_TEST_CASE_P(S1,
S1BasedTests,
ValuesIn(s1Entities.begin(), s1Entities .end()));
// etc for any types S1 you want //对于您想要的任何类型S1等等
If there is no such C++-type-friendly library on the market (I searched for 2 minutes and did not find) - then maybe something like this: 如果市场上没有这样的C ++类型友好库(我搜索了2分钟却没有找到)-那么可能是这样的:
SomeLib::File xmlFile("input.xml");
struct S1BasedTests : public TestWithParam<SomeLib::Node*>
{
struct S1 // xml=<S1 a="1" b="2"/>
{
int a;
int b;
};
S1 readNode()
{
S1 s1{};
s1.a = GetParam()->getNode("a").getValue<int>();
s1.b = GetParam()->getNode("b").getValue<float>();
return s1;
}
};
TEST_P(S1BasedTests , shouldXxxx)
{
const S1& s1 = readNode();
...
}
INSTANTIATE_TEST_CASE_P(S1,
S1BasedTests ,
ValuesIn(xmlFile.getNode("S1").getChildren()));
// xml=<S1s> <S1.../> <S1.../> </S1>
// etc for any node types like S1 //对于任何节点类型(例如S1)等
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.