问题描述
我目前正在使用 google google google google google单元测试框架.现在,我的老板对我测试的数据(即我称之为测试的类方法的值)感到不安,这是在测试中很难连接的.他要求从文件中读取此数据.他的论点是,因此为以前被遗忘的角案添加另一个测试会更容易.我对单位测试并不是那么经验,但到目前为止,这不是我的做法.因此,我试图弄清楚什么是最好的方法 - 即使是一个好主意.我很快遇到了DDT(数据驱动的测试)方法.
Google单元测试框架具有他们称为" 价值参数测试.有了我的测试固定装置即可成为模板类,我可以传递参数.但是,我看到了一些问题:
- 我目前每个课程都有一个固定装置.但是我需要每个方法测试的固定装置,因为每种方法都需要一组不同的参数.这将是很多额外的工作.
- 正如我所看到的,我只能传递一个参数.由于我的测试需要几个(我的方法的所有参数加上预期的结果),因此需要我传递诸如向量或地图之类的东西.再次,这种结构和检索听起来像是很多工作.
我会想象,像Google测试框架一样成熟,以使其更容易.但是,他们写
价值参数测试(当您想通过各种输入(又称数据驱动测试)测试代码时).此功能易于滥用,因此请在执行此功能时锻炼身体!
此外,还有此博客pobl tott:tott:数据驱动陷阱,也警告我(滥用)数据驱动的单元测试.
所以我的问题归结为:
- 进行数据驱动的单元测试是一个好主意吗?
- 如何使用Google测试框架进行数据驱动的单元测试
我并不是真正属于Googletest,基本上可以自由选择我想要的任何框架.
编辑
我在googletest常见问题的常见问题解答中找到了以下语句
Google测试尚未对[...]数据驱动的测试提供良好的支持.我们希望能够尽快在这一领域进行改进.
推荐答案
gtest对此有所支持 - 但也许他们不知道...
使用testing::ValuesIn - 在这个简化的示例中喜欢:
class SomeTests : public TestWithParam<int> { public: }; TEST_P(SomeTests, shouldBePositive) { ASSERT_GT(GetParam(), 0); }
和 - 从输入流获取值的方式:
std::ifstream inputValuesFromFile("input.txt"); INSTANTIATE_TEST_CASE_P(FromFileStream, SomeTests, ValuesIn(std::istream_iterator<int>(inputValuesFromFile), std::istream_iterator<int>()));
要使用比" 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; }
当然 - 在更复杂的情况下 - 考虑使用类似XML的(JSON?)格式和一些专业的迭代器,而不是std::istream_iterator<T>.
.对于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()));
//等任何类型的S1
如果市场上没有这样的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>
//等任何节点类型,例如S1