遇见gtest--函数参数化测试

来源:互联网 发布:055级驱逐舰 知乎 编辑:程序博客网 时间:2024/05/16 08:15
1、前言
      有时为了完整的测试一个函数的正确性,我们需要测试给定各种不同输入的情况下,函数的输出是否正确。最直接的方法就是我们手动去给不同输入,然后测试输出是否正确。但是这种方式工作量大,并且都是重复性,无意义的操作。为此,gtest中提供了参数化的测试。

2、参数化测试使用方法
    要使用参数化测试,我们需要创建一个子类继承testing::TestWithParam<T>,此处T为我们的参数类型。首先我们看一下这个类的声明:
template <typename T>class TestWithParam : public Test, public WithParamInterface<T> {};

    它是一个继承自testing::Test类和testing::WithParamInterface<T>的类,接下来我们再看看testing::WithParamInterface<T>这个接口的声明:
template <typename T>class WithParamInterface { public:  typedef T ParamType;  virtual ~WithParamInterface() {}  // The current parameter value. Is also available in the test fixture's  // constructor. This member function is non-static, even though it only  // references static data, to reduce the opportunity for incorrect uses  // like writing 'WithParamInterface<bool>::GetParam()' for a test that  // uses a fixture whose parameter type is int.  const ParamType& GetParam() const {    GTEST_CHECK_(parameter_ != NULL)        << "GetParam() can only be called inside a value-parameterized test "        << "-- did you intend to write TEST_P instead of TEST_F?";    return *parameter_;  } private:  // Sets parameter value. The caller is responsible for making sure the value  // remains alive and unchanged throughout the current test.  static void SetParam(const ParamType* parameter) {    parameter_ = parameter;  }  // Static value used for accessing parameter during a test lifetime.  static const ParamType* parameter_;  // TestClass must be a subclass of WithParamInterface<T> and Test.  template <class TestClass> friend class internal::ParameterizedTestFactory;};

    这个类它提供了GetParam方法来获取下一个参数用于输入。除此以外,它还有一个私有的SetParam方法,这个函数用于设置下一个参数值,它是在这个类的friend类internal::ParameterizedTestFactory中类调用的。这个类的定义如下:
    
template <class TestClass>class ParameterizedTestFactory : public TestFactoryBase { public:  typedef typename TestClass::ParamType ParamType;  explicit ParameterizedTestFactory(ParamType parameter) :      parameter_(parameter) {}  virtual Test* CreateTest() {    TestClass::SetParam(¶meter_);    return new TestClass();  } private:  const ParamType parameter_;  GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);};

    这个类实现了TestFactoryBase接口,用来生成TestClass类的对象,其中TestClass为TestWithParam的子类。对于TestWithParam类我们暂时了解至此,接下来我们看一下如何使用它。
    1)为了在我们的单元测试中使用这个参数,我们需要实现一个TestWithParam的子类。
   
class IsEvenTest: public testing::TestWithParam<int> {};

    2)告诉gtest我们的测试内容,我们此处需要用到新的宏TEST_P.
   
TEST_P(IsEvenTest, allEvenTest)        {        int n = GetParam();        EXPECT_TRUE(n);    }

    3)告诉gtest你想要测试的参数范围是什么

 使用INSTANTIATE_TEST_CASE_P这宏来告诉gtest你要测试的参数范围,它的定义如下:

# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \  ::testing::internal::ParamGenerator<test_case_name::ParamType> \      gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \  int gtest_##prefix##test_case_name##_dummy_ = \      ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \          GetTestCasePatternHolder<test_case_name>(\              #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\                  #prefix, \                  >est_##prefix##test_case_name##_EvalGenerator_, \                  __FILE__, __LINE__)

    这个宏需要三个参数,其中prefix为测试用例的前缀;test_case_name为测试用例,它是我们自定义的继承自testing::TestWithParam的类;generator是是testing::internal::ParamGenerator类的示例。对于我们的测试,我们可以如下使用:

   
INSTANTIATE_TEST_CASE_P(TrueReturn, IsEvenTest, testing::Values(2,4,6,8));

 gtest为我们提供了如下generator:

Range(begin, end[, step])范围在begin~end之间,步长为step,不包括endValues(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)作为一个参数。

说明:这个功能只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1

 3、总结

本章我们只介绍了函数的参数化测试,gtest中还提供了类型参数化的测试,在后续的章节中我们会进行介绍。

0 0