gtest 提供了类型参数化测试方案,可以测试不同类型的数据接口,比如模板测试。可以定义参数类型列表,按照列表定义的类型,每个测试case都执行一遍。

本例中,定义了2种计算素数的类,一个是实时计算,一个是提前计算好存放到一个大数组了。既空间和时间实现方式的对比。两种实现类都继承于抽象类PrimeTable。

  1. // The prime table interface.
  2. class PrimeTable {
  3. public:
  4. virtual ~PrimeTable() {}

  5. // Returns true if and only if n is a prime number.
  6. virtual bool IsPrime(int n) const = 0;

  7. // Returns the smallest prime number greater than p; or returns -1
  8. // if the next prime is beyond the capacity of the table.
  9. virtual int GetNextPrime(int p) const = 0;
  10. };

为了测试,定义了一个测试类,使用了两种特例化的CreatePrimeTable模板函数。

  1. template <class T>
  2. PrimeTable* CreatePrimeTable();
  3.  
  4. template <>
  5. PrimeTable* CreatePrimeTable<OnTheFlyPrimeTable>() {
  6. return new OnTheFlyPrimeTable;
  7. }
  8.  
  9. template <>
  10. PrimeTable* CreatePrimeTable<PreCalculatedPrimeTable>() {
  11. return new PreCalculatedPrimeTable(10000);
  12. }
  13.  
  14. // Then we define a test fixture class template.
  15. template <class T>
  16. class PrimeTableTest : public testing::Test {
  17. protected:
  18. // The ctor calls the factory function to create a prime table
  19. // implemented by T.
  20. PrimeTableTest() : table_(CreatePrimeTable<T>()) {}

  21. ~PrimeTableTest() override { delete table_; }

  22. // Note that we test an implementation via the base interface
  23. // instead of the actual implementation class. This is important
  24. // for keeping the tests close to the real world scenario, where the
  25. // implementation is invoked via the base interface. It avoids
  26. // got-yas where the implementation class has a method that shadows
  27. // a method with the same name (but slightly different argument
  28. // types) in the base interface, for example.
  29. PrimeTable* const table_;
  30. };

具体测试,有3个测试用例.

  1. TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes)
  2. TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes)
  3. TYPED_TEST(PrimeTableTest, CanGetNextPrime)

sample 6也演示了两种模式,第一种模式是已知所有的类型,先定义为一个Types结构。

  1. typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;
  2. #define TYPED_TEST_SUITE TYPED_TEST_CASE

  3. TYPED_TEST_SUITE(PrimeTableTest, Implementations);

第二种模式,不知道具体的类型,在运行测试时候,动态的绑定新的类型到测试fixture。

  1. TYPED_TEST_SUITE_P(PrimeTableTest2);

  2. REGISTER_TYPED_TEST_SUITE_P(
  3. PrimeTableTest2, // The first argument is the test case name.
  4. // The rest of the arguments are the test names.
  5. ReturnsFalseForNonPrimes, ReturnsTrueForPrimes, CanGetNextPrime);


  6. typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable>
  7. PrimeTableImplementations;

  8. INSTANTIATE_TYPED_TEST_SUITE_P(OnTheFlyAndPreCalculated, // Instance name
  9. PrimeTableTest2, // Test case name
  10. PrimeTableImplementations); // Type list

测试结果如下图,PrimeTableTest有2个类型,3个案例。PrimeTableTest2也有2个类型,3个案例。合计运行了12个tests。

代码分析


这个例子非常复杂,分析下主要的函数的调用。

第一步:定义Types

typedef Types<OnTheFlyPrimeTable, PreCalculatedPrimeTable> Implementations;

  1. // Types 的定义为:
  2. template <typename T1, typename T2>
  3. struct Types<T1, T2, internal::None, internal::None, internal::None,
  4. internal::None, internal::None, internal::None, internal::None,
  5. internal::None, internal::None, internal::None, internal::None,
  6. internal::None, internal::None, internal::None, internal::None,
  7. internal::None, internal::None, internal::None, internal::None,
  8. internal::None, internal::None, internal::None, internal::None,
  9. internal::None, internal::None, internal::None, internal::None,
  10. internal::None, internal::None, internal::None, internal::None,
  11. internal::None, internal::None, internal::None, internal::None,
  12. internal::None, internal::None, internal::None, internal::None,
  13. internal::None, internal::None, internal::None, internal::None,
  14. internal::None, internal::None, internal::None, internal::None,
  15. internal::None> {
  16. typedef internal::Types2<T1, T2> type;
  17. };

第二步:定义测试套件(Test suite)

TYPED_TEST_SUITE(PrimeTableTest, Implementations);

  1. // TYPED_TEST_SUITE 在老版本里叫做TYPED_TEST_CASE, 定义为
  2. # define TYPED_TEST_CASE(CaseName, Types, ...) \
  3. typedef ::testing::internal::TypeList< Types >::type GTEST_TYPE_PARAMS_( \
  4. CaseName); \
  5. typedef ::testing::internal::NameGeneratorSelector<__VA_ARGS__>::type \
  6. GTEST_NAME_GENERATOR_(CaseName)

GTEST_TYPE_PARAMS、GTEST_NAME_GENERATOR_、NameGeneratorSelector依赖于:

  1. // GTEST_TYPE_PARAMS
  2. # define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
  3. // GTEST_NAME_GENERATOR_
  4. #define GTEST_NAME_GENERATOR_(TestCaseName) \
  5. gtest_type_params_##TestCaseName##_NameGenerator

  6. struct DefaultNameGenerator {
  7. template <typename T>
  8. static std::string GetName(int i) {
  9. return StreamableToString(i);
  10. }
  11. };
  12. // NameGeneratorSelector
  13. template <typename Provided = DefaultNameGenerator>
  14. struct NameGeneratorSelector {
  15. typedef Provided type;
  16. };

TYPED_TEST_SUITE(PrimeTableTest, Implementations) 用上面的宏替换后:

  1. typedef::testing::internal::TypeList<Implementations>::type gtest_type_params_PrimeTableTest_;
  2. typedef ::testing::internal::__VA_ARGS__ gtest_type_params_PrimeTableTest_NameGenerator
  3.  
  4. //TypeList 扩展
  5. template <typename T1, typename T2, typename T3, typename T4, typename T5,
  6. typename T6, typename T7, typename T8, typename T9, typename T10,
  7. typename T11, typename T12, typename T13, typename T14, typename T15,
  8. typename T16, typename T17, typename T18, typename T19, typename T20,
  9. typename T21, typename T22, typename T23, typename T24, typename T25,
  10. typename T26, typename T27, typename T28, typename T29, typename T30,
  11. typename T31, typename T32, typename T33, typename T34, typename T35,
  12. typename T36, typename T37, typename T38, typename T39, typename T40,
  13. typename T41, typename T42, typename T43, typename T44, typename T45,
  14. typename T46, typename T47, typename T48, typename T49, typename T50>
  15. struct TypeList<Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13,
  16. T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26, T27, T28,
  17. T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43,
  18. T44, T45, T46, T47, T48, T49, T50> > {
  19. typedef typename Types<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12,
  20. T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25, T26,
  21. T27, T28, T29, T30, T31, T32, T33, T34, T35, T36, T37, T38, T39, T40,
  22. T41, T42, T43, T44, T45, T46, T47, T48, T49, T50>::type type;
  23. };

  24. // TypeList的type是 Types::type的别名,2个模板参数的Types::type是Types2类型,所以进一步扩展为:
  25. struct testing::internal::Types2<class OnTheFlyPrimeTable,class PreCalculatedPrimeTable> gtest_type_params_PrimeTableTest_;
  26. // NameGeneratorSelector<__VA_ARGS__>::type 类型返回Provided类型参数,默认为DefaultNameGenerator类型
  27. struct testing::internal::DefaultNameGenerator gtest_type_params_PrimeTableTest_NameGenerator

第三步:定义测试case,case名字要和test fixture名字相同。

  1. // Then use TYPED_TEST(TestCaseName, TestName) to define a typed test,
  2. // similar to TEST_F.
  3. TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) {
  4. // Inside the test body, you can refer to the type parameter by
  5. // TypeParam, and refer to the fixture class by TestFixture. We
  6. // don't need them in this example.

  7. // Since we are in the template world, C++ requires explicitly
  8. // writing 'this->' when referring to members of the fixture class.
  9. // This is something you have to learn to live with.
  10. EXPECT_FALSE(this->table_->IsPrime(-5));
  11. EXPECT_FALSE(this->table_->IsPrime(0));
  12. EXPECT_FALSE(this->table_->IsPrime(1));
  13. EXPECT_FALSE(this->table_->IsPrime(4));
  14. EXPECT_FALSE(this->table_->IsPrime(6));
  15. EXPECT_FALSE(this->table_->IsPrime(100));
  16. }

  17. TYPED_TEST(PrimeTableTest, ReturnsTrueForPrimes) {
  18. EXPECT_TRUE(this->table_->IsPrime(2));
  19. EXPECT_TRUE(this->table_->IsPrime(3));
  20. EXPECT_TRUE(this->table_->IsPrime(5));
  21. EXPECT_TRUE(this->table_->IsPrime(7));
  22. EXPECT_TRUE(this->table_->IsPrime(11));
  23. EXPECT_TRUE(this->table_->IsPrime(131));
  24. }

  25. TYPED_TEST(PrimeTableTest, CanGetNextPrime) {
  26. EXPECT_EQ(2, this->table_->GetNextPrime(0));
  27. EXPECT_EQ(3, this->table_->GetNextPrime(2));
  28. EXPECT_EQ(5, this->table_->GetNextPrime(3));
  29. EXPECT_EQ(7, this->table_->GetNextPrime(5));
  30. EXPECT_EQ(11, this->table_->GetNextPrime(7));
  31. EXPECT_EQ(131, this->table_->GetNextPrime(128));
  32. }

TYPED_TEST是个宏定义,展开为:

  1. # define TYPED_TEST(CaseName, TestName) \
  2. template <typename gtest_TypeParam_> \
  3. class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
  4. : public CaseName<gtest_TypeParam_> { \
  5. private: \
  6. typedef CaseName<gtest_TypeParam_> TestFixture; \
  7. typedef gtest_TypeParam_ TypeParam; \
  8. virtual void TestBody(); \
  9. };

  10. #define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
  11. test_case_name##_##test_name##_Test

TYPED_TEST(PrimeTableTest, ReturnsFalseForNonPrimes) 替换掉宏后为:

  1. template <typename gtest_TypeParam_> \
  2. class PrimeTableTest_ReturnsFalseForNonPrimes_Test \
  3. : public PrimeTableTest<gtest_TypeParam_> { \
  4. private: \
  5. typedef PrimeTableTest<gtest_TypeParam_> TestFixture; \
  6. typedef gtest_TypeParam_ TypeParam; \
  7. virtual void TestBody(); \
  8. };

EXPECT_FALSE(this->table_->IsPrime(-5)) 展开如下,使用AssertionResult函数判断是否为true。

  1. // 定义
  2. #define EXPECT_FALSE(condition) \
  3. GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \
  4. GTEST_NONFATAL_FAILURE_)

  5. #define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \
  6. GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
  7. if (const ::testing::AssertionResult gtest_ar_ = \
  8. ::testing::AssertionResult(expression)) \
  9. ; \
  10. else \
  11. fail(::testing::internal::GetBoolAssertionFailureMessage(\
  12. gtest_ar_, text, #actual, #expected).c_str())
  13. // 展开为
  14. #define EXPECT_FALSE(condition) \
  15. if (const ::testing::AssertionResult gtest_ar_ = ::testing::AssertionResult(condition)) ; \
  16. else fail(::testing::internal::GetBoolAssertionFailureMessage(gtest_ar_, #condition, "true", "false").c_str())

具体的函数执行,启动test用例,TestBody()虚函数是入口。

尊重技术文章,转载请注明!

Google单元测试框架gtest之官方sample笔记2--类型参数测试

https://www.cnblogs.com/pingwen/p/14455354.html

Google单元测试框架gtest之官方sample笔记2--类型参数测试的更多相关文章

  1. Google单元测试框架gtest之官方sample笔记3--值参数化测试

    1.7 sample7--接口测试 值参数不限定类型,也可以是类的引用,这就可以实现对类接口的测试,一个基类可以有多个继承类,那么可以测试不同的子类功能,但是只需要写一个测试用例,然后使用参数列表实现 ...

  2. Google单元测试框架gtest之官方sample笔记4--事件监控之内存泄漏测试

    sample 10 使用event listener监控Water类的创建和销毁.在Water类中,有一个静态变量allocated,创建一次值加一,销毁一次值减一.为了实现这个功能,重载了new和d ...

  3. Google单元测试框架gtest之官方sample笔记1--简单用例

    1.0 通用部分 和常见的测试工具一样,gtest提供了单体测试常见的工具和组件.比如判断各种类型的值相等,大于,小于等,管理多个测试的测试组如testsuit下辖testcase,为了方便处理初始化 ...

  4. Google单元测试框架gtest--值参数测试

    测试一个方法,需要较多个参数进行测试,比如最大值.最小值.异常值和正常值.这中间会有较多重复代码工作,而值参数测试就是避免这种重复性工作,并且不会损失测试的便利性和准确性. 如果测试一个函数,需要些各 ...

  5. C++单元测试框架gtest使用

    作用 作为代码编码人员,写完代码,不仅要保证编译通过和运行,还要保证逻辑尽量正确.单元测试是对软件可测试最小单元的检查和校验.单元测试与其他测试不同,单元测试可看作是编码工作的一部分,应该由程序员完成 ...

  6. 简单易懂的单元测试框架-gtest(一)

    简介     gtest是google开源的一个单元测试框架,以其简单易学的特点被广泛使用.该框架以第三方库的方式插入被测代码中.同其他单元测试框架相似,gtest也通过制作测试样例来进行代码测试.同 ...

  7. Google C++单元测试框架---Gtest框架简介(译文)

    一.设置一个新的测试项目 在用google test写测试项目之前,需要先编译gtest到library库并将测试与其链接.我们为一些流行的构建系统提供了构建文件: msvc/ for Visual ...

  8. 简单易懂的单元测试框架-gtest(二)

    简介     事件机制用于在案例运行前后添加一些操作(相当于挂钩函数).目前,gtest提供了三种等级的事件,分别: 全局级,所有案例执行的前后 TestSuite级,某一个案例集的前后 TestCa ...

  9. Google C++单元测试框架GoogleTest---GTest的Sample1和编写单元测试的步骤

    如果你还没有搭建gtest框架,可以参考我之前的博客:http://www.cnblogs.com/jycboy/p/6001153.html.. 1.The first sample: sample ...

随机推荐

  1. Think in Java 第四 五 章

    Think in Java 第四章 控制执行流程 测试while public class whileTest { static boolean condition(){ boolean result ...

  2. 2019牛客暑期多校训练营(第九场)J Symmetrical Painting (思维)

    传送门 大体思路就是:枚举所有可能的水平对称线,计算面积更新答案. 所有可能的水平对称线:\(L_i,R_i,{L_i+R_i\over 2}\) 计算面积:将所有可能的水平对称线从小到大排序,然后依 ...

  3. HDOJ1232 畅通工程 DFS

    很早之前就做过的题以前用并查集做的 现在用DFS重做算是熟悉DFS吧 #include<stdio.h>#include<string.h>const int size=100 ...

  4. cf-1230C Anadi and Domino

    题目链接:http://codeforces.com/contest/1230/problem/C 题意: 有21 个多米诺骨牌,给定一个无向图(无自环,无重边),一条边上可以放一个多米诺骨牌.如果两 ...

  5. Codeforces Round #672 (Div. 2) C1. Pokémon Army (easy version) (DP)

    题意:给你一组数\(a\),构造一个它的子序列\(b\),然后再求\(b_1-b2+b3-b4...\),问构造后的结果最大是多少. 题解:线性DP.我们用\(dp1[i]\)来表示在\(i\)位置, ...

  6. Docker文件挂载总结

    Docker容器启动的时候,如果要挂载宿主机的一个目录,可以用-v参数指定. 譬如我要启动一个centos容器,宿主机的/test目录挂载到容器的/soft目录,可通过以下方式指定: # docker ...

  7. HDU 4049 Tourism Planning(状压DP)题解

    题意:m个城市,n个人,让这n个人按固定顺序走遍m个城市.每个城市有一个单人票价pi.每个人在每个城市能获得vij的价值.如果多个人在同一城市,那么会额外获得价值,给出一张n * n价值表,额外价值为 ...

  8. Google coding Style Guide : Google 编码风格/代码风格 手册/指南

    1 1 1 https://github.com/google/styleguide Google 编码风格/代码风格 手册/指南 Style guides for Google-originated ...

  9. CSS 定位 relative && absolute 问题?

    1 1 1 CSS 定位 relative && absolute 问题? 谁能解释一下,为什么div使用 relative是设置right,bottom 后,看不到div 呀,哪里多 ...

  10. javascript change array length methods

    javascript change array length methods Array 改变数组长度的方法 push, pop shift, unshift, splice, fill, 不改变数组 ...