gtest参数化

1、简介

  在设计测试案例时,经常需要考虑给被测函数传入不同的值的情况。按照之前的通用方法,需要多次调用同一个函数,这种做法很不方便,效率也不好。
如:
TEST(IsPrimeTest, HandleTrueReturn)
{
  EXPECT_TRUE(IsPrime(3));
  EXPECT_TRUE(IsPrime(5));
  EXPECT_TRUE(IsPrime(11));
  EXPECT_TRUE(IsPrime(23));
  EXPECT_TRUE(IsPrime(17));

  ......
}
这种方法就是1个测试案例,有5个检查点。而且传入再多的值也无法保证函数正确。IsPrime函数在gtest的example1.cc中。因此Google使用参数化的方法解决这种问题。

2、参数化

2.1 告知gtest需要使用的参数类型

  必须添加一个类,继承testing::TestWithParam<T>,其中T就是你需要参数化的参数类型。如:参数化int型的参数(放在头文件中)
class myTest : public testing::TestWithParam<int>
{

};

2.2 告知gtest拿到参数后执行的操作当前的参数的具体值

如:
TEST_P(myTest, test0)
{
  int num = GetParam();
  EXPECT_EQ(num,num)<<"GetParam:"<<GetParam()<<",num:"<<num;
}
此处TEST_P宏中的第一个参数和头文件中定义的参数化的类名相同。

2.3 告知gtest要测试的参数范围

使用INSTANTIATE_TEST_CASE_P宏,如:
  INSTANTIATE_TEST_CASE_P(isParamTestInt, myTest, testing::Values(1, 2, 3, 4));
该宏的参数解析:
  isParamTestInt:测试案例的前缀,随意取即可
  myTest:测试案例名称,要和定义的参数化的类的名称相同
  testing::Values(1, 2, 3, 4):参数生成器

该宏放在与TEST_P宏(2.2)相同的文件。

2.4 参数生成函数

  Range(begin, end[, step])                 范围在begin~end之间,步长为step,不包括end
  Values(v1, v2, ..., vN)                  v1,v2到vN的值
  ValuesIn(container) and ValuesIn(begin, end)      从一个C类型的数组或是STL容器,或是迭代器中取值
  Bool()                            取false 和 true 两个值
  Combine(g1, g2, ..., gN)                 将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。
  注意:Combine只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1。


2.5 参数化后的输出

  4 tests from isParamTestInt/myTest
  [ RUN ] isParamTestInt/myTest.test0/0
  [ OK ] isParamTestInt/myTest.test0/0 (0 ms)
  [ RUN ] isParamTestInt/myTest.test0/1
  [ OK ] isParamTestInt/myTest.test0/1 (0 ms)
  [ RUN ] isParamTestInt/myTest.test0/2
  [ OK ] isParamTestInt/myTest.test0/2 (0 ms)
  [ RUN ] isParamTestInt/myTest.test0/3
  [ OK ] isParamTestInt/myTest.test0/3 (0 ms)
  [----------] 4 tests from isParamTestInt/myTest (4 ms total)

格式:INSTANTIATE_TEST_CASE_P的第一个参数 / TEST_P第一个参数 . TEST_P第二个参数 / testing::Values中参数的序号,从0开始

3、类型参数化

  gtest还提供了应付各种不同类型的数据时的方案,以及参数化类型的方案。

3.1 定义1个模板类,继承testing::Test

template <typename T> class FooTest : public testing::Test {
  public:
    ...
    typedef std::list<T> List;
    static T shared_;
    T value_;
};

3.2 定义需要测试到的具体数据类型

定义需要测试char,int和unsigned int :
  typedef testing::Types<char, int, unsigned int> MyTypes;
  TYPED_TEST_CASE(FooTest, MyTypes);

3.3 使用TYPED_TEST宏完成测试案例,在声明模版的数据类型时,使用TypeParam

TYPED_TEST(FooTest, DoesBlah) {
  // 在测试中,引用特殊名称TypeParam以获取类型参数。
  // 由于我们在一个派生类模板中,所以C++要求我们通过“this”访问FooTest的成员
  TypeParam n = this->value_;

  // 访问fixture的静态成员, 添加'TestFixture::'前缀
  n += TestFixture::shared_;

  // 需要引用fixture中的typedefs, 添加'typename TestFixture::'前缀
  typename TestFixture::List values;
  values.push_back(n);

}
该示例需要事先知道类型的列表
  gtest还提供一种更加灵活的类型参数化的方式,允许你在完成测试的逻辑代码之后再去考虑需要参数化的类型列表,并且还可以重复的使用这个类型列表。

3.4 官方的另一种方案

3.4.1 定义模板类

template <typename T>
class FooTest : public testing::Test {

};

TYPED_TEST_CASE_P(FooTest);
与3.1 一致,先定义模板类。

3.4.2 使用TYPED_TEST_P宏完成测试案例

TYPED_TEST_P(FooTest, DoesBlah) {
  // 测试中,参考TypeParam以获取类型参数
  TypeParam n = 0;
}

TYPED_TEST_P(FooTest, HasPropertyA) { }

3.4.3 使用REGISTER_TYPED_TEST_CASE_P宏

  REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA);
第一个参数是testcase的名称,后面的参数是test的名称

3.4.4 指定需要的类型列表

  typedef testing::Types<char, int, unsigned int> MyTypes;
  INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

这种方案相比之前的方案提供更加好的灵活度,当然,框架越灵活,复杂度也会随之增加。

猜你喜欢

转载自www.cnblogs.com/Sheenagh/p/12215339.html
今日推荐