视频参考:Google C++ Testing GTest GMock Framework

为什么要使用 Google C++ Testing Framework?

使用这个框架有许多好理由。本文讨论其中几个。

某些类型的测试有糟糕的内存问题,这些问题只在某几次运行期间出现。Google 的测试框架为处理这种情况提供了出色的支持。可以使用 Google 框架重复运行相同的测试一千次。当出现故障的迹象时,自动地调用调试器。另外,这只需要在命令行上传递两个开关即可实现:--gtest_repeat=1000 --gtest_break_on_failure

与其他许多测试框架相反,可以把 Google 测试框架内置的断言部署在禁用了异常处理(通常由于性能原因)的软件中。因此,也可以在析构函数中安全地使用断言。

运行测试很简单。只需调用预定义的 RUN_ALL_TESTS 宏,而不需要通过创建或驱动单独的运行器类来执行测试。这比 CppUnit 等框架方便多了。

只需传递一个开关即可生成 Extensible Markup Language (XML) 报告: --gtest_output="xml:<file name>"。在 CppUnit 和 CppTest 等框架中,需要编写很多代码才能生成 XML 输出。

创建基本测试

以下代码均在Linux下运行。也可以利用VS2017 cross platform feature 在Windows本地进行Gtest测试。

sample.h

#ifndef _SAMPLE_H_
#define _SAMPLE_H_// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n);// Returns true iff n is a prime number.
bool IsPrime(int n);#endif

View Code

sample.c

#include "sample.h"// Returns n! (the factorial of n).  For negative n, n! is defined to be 1.
int Factorial(int n) {int result = 1;for (int i = 1; i <= n; i++) {result *= i;}return result;
}// Returns true iff n is a prime number.
bool IsPrime(int n) {// Trivial case 1: small numbersif (n <= 1) return false;// Trivial case 2: even numbersif (n % 2 == 0) return n == 2;// Now, we have that n is odd and n >= 3.// Try to divide n by every odd number i, starting from 3for (int i = 3; ; i += 2) {// We only have to try i up to the square root of nif (i > n/i) break;// Now, we have i <= n/i < n.// If n is divisible by i, n is not prime.if (n % i == 0) return false;}// n has no integer factor in the range (1, n), and thus is prime.return true;
}

View Code

sample_unittest.c

#include <limits.h>
#include "sample.h"
#include "gtest/gtest.h"
namespace {TEST(FactorialTest, Negative) {// This test is named "Negative", and belongs to the "FactorialTest"// test case.EXPECT_EQ(1, Factorial(-5));EXPECT_EQ(1, Factorial(-1));EXPECT_GT(Factorial(-10), 0);
}TEST(FactorialTest, Zero) {EXPECT_EQ(1, Factorial(0));
}TEST(FactorialTest, Positive) {EXPECT_EQ(1, Factorial(1));EXPECT_EQ(2, Factorial(2));EXPECT_EQ(6, Factorial(3));EXPECT_EQ(40320, Factorial(8));
}// Tests IsPrime()
TEST(IsPrimeTest, Negative) {EXPECT_FALSE(IsPrime(-1));EXPECT_FALSE(IsPrime(-2));EXPECT_FALSE(IsPrime(INT_MIN));
}TEST(IsPrimeTest, Trivial) {EXPECT_FALSE(IsPrime(0));EXPECT_FALSE(IsPrime(1));EXPECT_TRUE(IsPrime(2));EXPECT_TRUE(IsPrime(3));
}TEST(IsPrimeTest, Positive) {EXPECT_FALSE(IsPrime(4));EXPECT_TRUE(IsPrime(5));EXPECT_FALSE(IsPrime(6));EXPECT_TRUE(IsPrime(23));
}
}  // namespace

View Code

g++ sample.c sample_unittest.c  -lgtest -std=c++11 -lgtest_main -lpthread -o test

没有main函数

使用Gtest你可以不提供main函数,libgtest_main.a会为你提供一个。如果没有特殊理由还是建议自己提供main函数

main.c

#include <gtest/gtest.h>
int main(int argc, char** argv){::testing::InitGoogleTest(&argc, argv);return RUN_ALL_TESTS();
}

View Code

g++ sample.c sample_unittest.c  main.c -lgtest -std=c++11 -lpthread -o test

::testing::InitGoogleTest 方法的作用就是对框架进行初始化,必须在调用 RUN_ALL_TESTS 之前调用它。在代码中只能调用 RUN_ALL_TESTS 一次,因为多次调用会与框架的一些高级特性冲突,不支持这种做法。注意,RUN_ALL_TESTS自动地探测并运行用 TEST 宏定义的所有测试。在默认情况下,结果输出到标准输出。

编译、运行结果和上面一样。

Gtest选项

InitGoogleTest 函数接收传递给test infrastructure的参数,下面介绍常用参数

通过在命令行上传递 --gtest_output="xml:report.xml",可以把输出转储为 XML 格式。当然,可以把 report.xml 替换为您喜欢的任何文件名。

某些测试有时候会失败,但是在大多数时候会顺利通过。这是与memory corruption相关的问题的典型特点。如果多次运行测试,就能够提高发现失败的可能性。如果在命令行上传递 --gtest_repeat=2 --gtest_break_on_failure,就重复运行相同的测试两次。如果测试失败,会自动调用调试器。

并不需要每次都运行所有测试,尤其是在修改的代码只影响某几个模块的情况下。为了支持运行一部分测试,Google 提供 --gtest_filter=<test string>。test string 的格式是由冒号 (:) 分隔的一系列通配符模式。例如,--gtest_filter=* 运行所有测试,而 --gtest_filter=SquareRoot* 只运行 SquareRootTest 测试。如果希望只运行 SquareRootTest 中的正数单元测试,应该使用 --gtest_filter=SquareRootTest.*-SquareRootTest.Zero*。注意,SquareRootTest.* 表示属于 SquareRootTest 的所有测试,而 -SquareRootTest.Zero* 表示不运行名称以 Zero 开头的测试。

禁用临时测试

可以临时禁用测试吗?可以,只需在逻辑测试名或单元测试名前面加上 DISABLE_ 前缀,它就不会执行了。

禁用临时测试

#include "gtest/gtest.h"TEST (DISABLE_SquareRootTest, PositiveNos) { EXPECT_EQ (18.0, square-root (324.0));EXPECT_EQ (25.4, square-root (645.16));EXPECT_EQ (50.3321, square-root (2533.310224));
}ORTEST (SquareRootTest, DISABLE_PositiveNos) { EXPECT_EQ (18.0, square-root (324.0));EXPECT_EQ (25.4, square-root (645.16));EXPECT_EQ (50.3321, square-root (2533.310224));
}

View Code

注意,如果禁用了任何测试,Google 框架会在测试执行结束时输出警告消息,Google 警告用户在框架中有禁用的测试

1 FAILED TESTYOU HAVE 1 DISABLED TEST

View Code

如果希望继续运行禁用的测试,那么在命令行上传递 -gtest_also_run_disabled_tests 选项。

Assertions(断言)

演示用于浮点数比较的宏

ASSERT_FLOAT_EQ (expected, actual)
ASSERT_DOUBLE_EQ (expected, actual)
ASSERT_NEAR (expected, actual, absolute_range)EXPECT_FLOAT_EQ (expected, actual)
EXPECT_DOUBLE_EQ (expected, actual)
EXPECT_NEAR (expected, actual, absolute_range)

View Code

为什么需要用单独的宏进行浮点数比较?使用 ASSERT_EQ 不行吗?使用 ASSERT_EQ 和相关的宏可能可以,也可能不行,但是使用专门用于浮点数比较的宏更好。通常,不同的中央处理单元 (CPU) 和操作环境以不同的方式存储浮点数,简单地比较期望值和实际值是无效的。例如,ASSERT_FLOAT_EQ (2.00001, 2.000011) 会顺利通过 — 如果直到小数点后四位都匹配,Google 就不会抛出错误。如果需要更精确的比较,应该使用 ASSERT_NEAR (2.00001, 2.000011, 0.0000001),就会得到 下面所示的错误。

Math.cc(68): error: The difference between 2.00001 and 2.000011 is 1e-006, which exceeds
0.0000001, where
2.00001 evaluates to 2.00001,
2.000011 evaluates to 2.00001, and
0.0000001 evaluates to 1e-007.

View Code

断言引发的三种结果

Assertions会引发3种结果:success、Non-Fatal Failure、Fatal Failure

Non-Fatal Failure 和 Fatal Failure啥区别?

前者失败后还会继续执行,后者失败后停止执行。ASSERT_XX属于fatal assertion,EXPECT_XX属于nonfatal assertion。

不建议才一个测试单元里面写多个assertion

当有多个Non-Fatal Assertion时,不管有多少个assertion通过,只要有一个不通过,该测试用例就不通过。

如果把第一个EXPECT_EQ换成ASSERT_EQ,那么断言失败时停止执行,后面代码不会被执行。虽然你可以通过日志去翻那个文件、哪个函数、哪段代码第几行执行错误。这种情况适合于测试用例少的情况,上百个测试用例的时候,这种排查发简直是噩梦。一个建议原则是one region one assertion

理解test fixtures

在执行单元测试之前,通常要执行一些定制的初始化。例如,如果希望度量测试的时间/内存占用量,就需要放置一些测试专用代码以度量这些值。这就是fixtures的用途 — 它们帮助完成这种定制的测试初始化。代码如下

A test fixture class

class myTestFixture1: public ::testing::test {
public: myTestFixture1( ) { // initialization code here
   } void SetUp( ) { // code here will execute just before the test ensues
   }void TearDown( ) { // code here will be called just after the test completes// ok to through exceptions from here if need be
   }~myTestFixture1( )  { // cleanup any pending stuff, but no exceptions allowed
   }// put in any custom data members that you need
};

View Code

这个fixtures class派生自 gtest.h 中声明的 ::testing::test 类。下面是使用这个装备类的示例。注意,它使用 TEST_F 宏而不是 TEST

TEST_F (myTestFixture1, UnitTest1) { .
}TEST_F (myTestFixture1, UnitTest2) { .
}

View Code

在使用装备时,要注意以下几点:

  • 可以在构造函数或 SetUp 方法中执行初始化或分配资源。由用户选择具体方式。
  • 可以在 TearDown 或析构函数例程中释放资源。但是,如果需要异常处理,那么只能在 TearDown 代码中进行,因为从析构函数中抛出异常会导致不确定的结果。
  • 在以后的版本中,Google 断言宏可能会在平台上抛出异常。因此,为了便于维护,最好在 TearDown 代码中使用断言宏(assertion macros)。
  • 不存在多个测试使用同一个test fixture。对于每个新的测试单元,框架创建一个新的test fixture。在上面代码中,由于要创建两个 myFixture1 对象,所以两次调用 SetUp 例程(请注意使用正确的拼写)。

转载于:https://www.cnblogs.com/kelamoyujuzhen/p/10161362.html

A quick introduction to Google test相关推荐

  1. Variance Reduction Methods: a Quick Introduction to Quasi Monte Carlo——完结

    https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/monte-carlo-methods- ...

  2. [gtest][001] A quick introduction to the Google C++ Testing Framework

    前言:这是一篇非常好的介绍谷歌测试框架基本知识的文章.我们知道谷歌在提供开源的模块的时候,往往都附带提供了相应的测试案例.例如浏览器的移植工作,理解这些测试案例,比如unit test案例是很重要的事 ...

  3. 使用Google Maps API和google-maps-react进行React Apps

    This tutorial aims at integrating the google maps API to your React components and enabling you to d ...

  4. 谷歌ai人工智能叫什么_谷歌正在通过AI策展和内置订阅全面革新Google新闻

    谷歌ai人工智能叫什么 Google is overhauling Google News with an AI-driven home screen and a quick way to subsc ...

  5. 谷歌搜索引擎_在搜索引擎上击败Google的4种方法

    谷歌搜索引擎 Today a new search engine launched called Cuil. Because of the resumes of the company's found ...

  6. Google Sites 简介

    Google Sites 简介 本文地址: http://blog.csdn.net/caroline_wendy Google Sites is the easiest way to make in ...

  7. Google 地图 API for Android

    原文:Introduction to Google Maps API for Android 作者: Eunice Obugyei 译者:kmyhy 从健康类 app Runkeeper 到游戏 ap ...

  8. 深度学习 免费课程_深入学习深度学习,提供15项免费在线课程

    深度学习 免费课程 by David Venturi 大卫·文图里(David Venturi) 深入学习深度学习,提供15项免费在线课程 (Dive into Deep Learning with ...

  9. 机器学习|最简单易懂的机器学习

    https://www.toutiao.com/a6670113185682424324/ 本文用浅显易懂的语言精准概括了机器学习的相关知识,内容全面,总结到位,剖析了机器学习的what,who,wh ...

最新文章

  1. python函数进阶小结_Python-进阶-functools模块小结
  2. 挨踢部落直播课堂第一期:起航2017——拥抱大数据
  3. PHP带头大哥谈程序语言的学习体会!
  4. 开启Linux下Telnet服务
  5. 上海的房租有多高?我用Python爬虫为你揭晓
  6. 在网页中插入百度地图(实例)
  7. oracle 12.2 启用分片,关于Oracle Sharding,你想知道的都在这里
  8. windows10怎样关闭,开机启动项中不需要的应用?
  9. grub的说明与配置方法
  10. 新的android包格式,在Android中注册新文件类型
  11. linuxYUM源配置问题
  12. 在MAC上安装mysql
  13. 英语单词记忆(词缀 / 词根)
  14. 【iOS】【最新】2022苹果开发者账号注册流程
  15. Nanopore测序技术
  16. 挖掘视频网站【优酷】上被截断的视频的地址--001
  17. 配置Apache服务
  18. invoker 祈求者 c++ 题解
  19. 谁是您眼里的好?您是谁眼里的草?
  20. 20:django中的安全问题

热门文章

  1. asp.net 图片 上传 打水印 高质量缩略图
  2. Chapter 1 First Sight——33
  3. UVA 11038 How Many O's?
  4. 如此智能的Windows Embedded Standard 7
  5. 查看、关闭被占用的端口
  6. java 导出word换行_Java 导出数据库表信息生成Word文档
  7. MySQL分组函数和distinct搭配使用
  8. 将本地镜像发布到阿里云
  9. 索引使用原则-联合索引最左匹配
  10. Dubbo对于REST协议的支持