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

一 我们为啥要用gtest呢?

Why use the Google C++ Testing Framework?

There are many good reasons for you to use this framework. This section describes several of them.

1 强在多次测试的可行性:

Some categories of tests have bad memory problems that surface only during certain runs. Google's test framework provides excellent support for handling such situations. You can repeat the same test a thousand times using the Google framework. At the first sign of a failure, the debugger is automatically invoked. In addition, all of this is done with just two switches passed from command line: --gtest_repeat=1000 --gtest_break_on_failure.

Contrary to a lot of other testing frameworks, Google's test framework has built-in assertions that are deployable in software where exception handling is disabled (typically for performance reasons). Thus, the assertions can be used safely in destructors, too.

2 测试结果输出强大,到xml非常方便

Running the tests is simple. Just making a call to the predefined RUN_ALL_TESTS macro does the trick, as opposed to creating or deriving a separate runner class for test execution. This is in sharp contrast to frameworks such as CppUnit.

Generating an Extensible Markup Language (XML) report is as easy as passing a switch: --gtest_output="xml:<file name>". In frameworks such as CppUnit and CppTest, you need to write substantially more code to generate XML output.

二 举例,一个基本的测试构建

Creating a basic test

Consider the prototype for a simple square root function shown in Listing 1.

构建一个简单的开根号的函数如下:

Listing 1. Prototype of the square root function
1
double square-root (const double);

For negative numbers, this routine returns -1. It's useful to have both positive and negative tests here, so you do both. Listing 2shows that test case.

对应负数直接返回-1,下面是这个函数的测试

Listing 2. Unit test for the square root function
1
2
3
4
5
6
7
8
9
10
11
12
#include "gtest/gtest.h"
TEST (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));
}
TEST (SquareRootTest, ZeroAndNegativeNos) {
    ASSERT_EQ (0.0, square-root (0.0));
    ASSERT_EQ (-1, square-root (-22.0));
}

Listing 2 creates a test hierarchy named SquareRootTest and then adds two unit tests, PositiveNos and ZeroAndNegativeNos, to that hierarchy.

这里建立了两个单元测试,一个是测试正数,一个是0和负数

TEST is a predefined macro defined in gtest.h (available with the downloaded sources) that helps define this hierarchy.

测试用宏定义的方式已经在网页上了,

EXPECT_EQ and ASSERT_EQ are also macros—in the former case test execution continues even if there is a failure while in the latter case test execution aborts. Clearly, if the square root of 0 is anything but 0, there isn't much left to test anyway. That's why the ZeroAndNegativeNos test uses only ASSERT_EQ while the PositiveNos test uses EXPECT_EQ to tell you how many cases there are where the square root function fails without aborting the test.

宏定义EXPECT_EQ and ASSERT_EQ 的区别,一个只是告诉通知你有错,一个确实会中断测试的下一步进行。

三,运行测试

Running the first test

Now that you've created your first basic test, it is time to run it. Listing 3 is the code for the main routine that runs the test.

Listing 3. Running the square root test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include "gtest/gtest.h"
TEST(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));
}
TEST (SquareRootTest, ZeroAndNegativeNos) {
    ASSERT_EQ (0.0, square-root (0.0));
    ASSERT_EQ (-1, square-root (-22.0));
}
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

The ::testing::InitGoogleTest method does what the name suggests—it initializes the framework and must be called before RUN_ALL_TESTSRUN_ALL_TESTS must be called only once in the code because multiple calls to it conflict with some of the advanced features of the framework and, therefore, are not supported. Note that RUN_ALL_TESTS automatically detects and runs all the tests defined using the TEST macro. By default, the results are printed to standard output. Listing 4 shows the output.

方法InitGoogleTest 顾名思义就是初始化用的,而RUN_ALL_TESTS这只能自行一次。

Listing 4. Output from running the square root test
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Running main() from user_main.cpp
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from SquareRootTest
[ RUN      ] SquareRootTest.PositiveNos
..\user_sqrt.cpp(6862): error: Value of: sqrt (2533.310224)
  Actual: 50.332
Expected: 50.3321
[  FAILED  ] SquareRootTest.PositiveNos (9 ms)
[ RUN      ] SquareRootTest.ZeroAndNegativeNos
[       OK ] SquareRootTest.ZeroAndNegativeNos (0 ms)
[----------] 2 tests from SquareRootTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran. (10 ms total)
[  PASSED  ] 1 test.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SquareRootTest.PositiveNos
 1 FAILED TEST

四,gtest的一些酷酷的功能。

Options for the Google C++ Testing Framework

In Listing 3 you see that the InitGoogleTest function accepts the arguments to the test infrastructure. This section discusses some of the cool things that you can do with the arguments to the testing framework.

4.1 测试输出格式选择

You can dump the output into XML format by passing --gtest_output="xml:report.xml" on the command line. You can, of course, replace report.xml with whatever file name you prefer.

There are certain tests that fail at times and pass at most other times. This is typical of problems related to memory corruption. There's a higher probability of detecting the fail if the test is run a couple times. If you pass --gtest_repeat=2 --gtest_break_on_failure on the command line, the same test is repeated twice. If the test fails, the debugger is automatically invoked.

4.1 测试过滤,保证你不需要每次都全部做所有的测试,挑那些错误的做就好了

你也可以通过“-”,去挑选那些你不想做的测试。

Not all tests need to be run at all times, particularly if you are making changes in the code that affect only specific modules. To support this, Google provides --gtest_filter=<test string>. The format for the test string is a series of wildcard patterns separated by colons (:). For example, --gtest_filter=* runs all tests while --gtest_filter=SquareRoot* runs only theSquareRootTest tests. If you want to run only the positive unit tests from SquareRootTest, use --gtest_filter=SquareRootTest.*-SquareRootTest.Zero*. Note that SquareRootTest.* means all tests belonging toSquareRootTest, and -SquareRootTest.Zero* means don't run those tests whose names begin with Zero.

Listing 5 provides an example of running SquareRootTest with gtest_outputgtest_repeat, and gtest_filter.

Listing 5. Running SquareRootTest with gtest_outputgtest_repeat, and gtest_filter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
[arpan@tintin] ./test_executable --gtest_output="xml:report.xml" --gtest_repeat=2 --
gtest_filter=SquareRootTest.*-SquareRootTest.Zero*
Repeating all tests (iteration 1) . . .
Note: Google Test filter = SquareRootTest.*-SquareRootTest.Z*
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SquareRootTest
[ RUN      ] SquareRootTest.PositiveNos
..\user_sqrt.cpp (6854): error: Value of: sqrt (2533.310224)
  Actual: 50.332
Expected: 50.3321
[  FAILED  ] SquareRootTest.PositiveNos (2 ms)
[----------] 1 test from SquareRootTest (2 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (20 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SquareRootTest.PositiveNos
 1 FAILED TEST
Repeating all tests (iteration 2) . . .
Note: Google Test filter = SquareRootTest.*-SquareRootTest.Z*
[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from SquareRootTest
[ RUN      ] SquareRootTest.PositiveNos
..\user_sqrt.cpp (6854): error: Value of: sqrt (2533.310224)
  Actual: 50.332
Expected: 50.3321
[  FAILED  ] SquareRootTest.PositiveNos (2 ms)
[----------] 1 test from SquareRootTest (2 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (20 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SquareRootTest.PositiveNos
 1 FAILED TEST

五,屏蔽某些测试

Temporarily disabling tests

Let's say you break the code. Can you disable a test temporarily? Yes, simply add the DISABLE_ prefix to the logical test name or the individual unit test name and it won't execute. Listing 6 demonstrates what you need to do if you want to disable thePositiveNos test from Listing 2.

Listing 6. Disabling a test temporarily
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#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));
}
OR
TEST (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));
}

Note that the Google framework prints a warning at the end of the test execution if there are any disabled tests, as shown inListing 7.

Listing 7. Google warns user of disabled tests in the framework
1
2
1 FAILED TEST
  YOU HAVE 1 DISABLED TEST

If you want to continue running the disabled tests, pass the -gtest_also_run_disabled_tests option on the command line.Listing 8 shows the output when the DISABLE_PositiveNos test is run.

Listing 8. Google lets you run tests that are otherwise disabled
1
2
3
4
5
6
7
8
9
10
[----------] 1 test from DISABLED_SquareRootTest
[ RUN      ] DISABLED_SquareRootTest.PositiveNos
..\user_sqrt.cpp(6854): error: Value of: square-root (2533.310224)
  Actual: 50.332
Expected: 50.3321
[  FAILED  ] DISABLED_SquareRootTest.PositiveNos (2 ms)
[----------] 1 test from DISABLED_SquareRootTest (2 ms total)
[  FAILED  ] 1 tests, listed below:
[  FAILED  ] SquareRootTest. PositiveNos

六 assertion说明

It's all about assertions

The Google test framework comes with a whole host of predefined assertions. There are two kinds of assertions—those with names beginning with ASSERT_ and those beginning with EXPECT_.

The ASSERT_* variants abort the program execution if an assertion fails while EXPECT_* variants continue with the run. In either case, when an assertion fails, it prints the file name, line number, and a message that you can customize. Some of the simpler assertions include ASSERT_TRUE (condition) and ASSERT_NE (val1, val2). The former expects the condition to always be true while the latter expects the two values to be mismatched. These assertions work on user-defined types too, but you must overload the corresponding comparison operator (==, !=, <=, and so on).

ASSERT_TRUE 条件真的判断

ASSERT_NE 判读两个变量是否相等

七 对应更高精度的要求下:

Floating point comparisons

Google provides the macros shown in Listing 9 for floating point comparisons.

Listing 9. Macros for floating point comparisons
1
2
3
4
5
6
7
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)

Why do you need separate macros for floating point comparisons? Wouldn't ASSERT_EQ work? The answer is that ASSERT_EQ and related macros may or may not work, and it's smarter to use the macros specifically meant for floating point comparisons. Typically, different central processing units (CPUs) and operating environments store floating points differently and simple comparisons between expected and actual values don't work. For example, ASSERT_FLOAT_EQ (2.00001, 2.000011) passes—Google does not throw an error if the results tally up to four decimal places. If you want greater precision, use ASSERT_NEAR (2.00001, 2.000011, 0.0000001) and you receive the error shown in Listing 10.

Listing 10. Error message from ASSERT_NEAR
1
2
3
4
5
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.

八 退出消息比较和检查

Death tests

The Google C++ Testing Framework has an interesting category of assertions (ASSERT_DEATHASSERT_EXIT, and so on) that it calls the death assertions. You use this type of assertion to check if a proper error message is emitted in case of bad input to a routine or if the process exits with a proper exit code.

错误的测试结果,我们往往会定义一些错误代码。然而,最好的方式,还是给出错误的消息讯息。谷歌测试会允许你通过比较这些你自己定制话的错误讯息去assert测试的过程。

For example, in Listing 3, it would be good to receive an error message when doing square-root (-22.0) and exiting the program with return status -1 instead of returning -1.0. Listing 11 uses ASSERT_EXIT to verify such a scenario.

Listing 11. Running a death test using Google's framework
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "gtest/gtest.h"
double square-root (double num) {
    if (num < 0.0) {
        std::cerr << "Error: Negative Input\n";
        exit(-1);
    }
    // Code for 0 and +ve numbers follow
}
TEST (SquareRootTest, ZeroAndNegativeNos) {
    ASSERT_EQ (0.0, square-root (0.0));
    ASSERT_EXIT (square-root (-22.0), ::testing::ExitedWithCode(-1), "Error:
Negative Input");
}
int main(int argc, char **argv) {
  ::testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}

ASSERT_EXIT checks if the function is exiting with a proper exit code (that is, the argument to exit or _exit routines) and compares the string within quotes to whatever the function prints to standard error. Note that the error messages must go to

std::cerr and not std::cout. Listing 12 provides the prototypes for ASSERT_DEATH and ASSERT_EXIT.

Listing 12. Prototypes for death assertions
1
2
ASSERT_DEATH(statement, expected_message)
ASSERT_EXIT(statement, predicate, expected_message)

Google provides the predefined predicate ::testing::ExitedWithCode(exit_code). The result of this predicate is true only if the program exits with the same exit_code mentioned in the predicate. ASSERT_DEATH is simpler than ASSERT_EXIT; it just compares the error message in standard error with whatever is the user-expected message.

Understanding test fixtures

这里是整个测试初始化的部分,结束部分。游离于测试实体之外的设计都在这里。

It is typical to do some custom initialization work before executing a unit test. For example, if you are trying to measure the time/memory footprint of a test, you need to put some test-specific code in place to measure those values. This is where fixtures come in—they help you set up such custom testing needs. Listing 13 shows what a fixture class looks like.

Listing 13. A test fixture class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
};

The fixture class is derived from the ::testing::test class declared in gtest.h. Listing 14 is an example that uses the fixture class. Note that it uses the TEST_F macro instead of TEST.

Listing 14. Sample use of a fixture
1
2
3
4
5
6
7
8
9
TEST_F (myTestFixture1, UnitTest1) {
    
.
}
TEST_F (myTestFixture1, UnitTest2) {
    
.
}

There are a few things that you need to understand when using fixtures:

  • You can do initialization or allocation of resources in either the constructor or the SetUp method. The choice is left to you, the user.
  • You can do deallocation of resources in TearDown or the destructor routine. However, if you want exception handling you must do it only in the TearDown code because throwing an exception from the destructor results in undefined behavior.
  • The Google assertion macros may throw exceptions in platforms where they are enabled in future releases. Therefore, it's a good idea to use assertion macros in the TearDown code for better maintenance.
  • The same test fixture is not used across multiple tests. For every new unit test, the framework creates a new test fixture. So inListing 14, the SetUp (please use proper spelling here) routine is called twice because two myFixture1 objects are created.

Conclusion

This article just scratches the surface of the Google C++ Testing Framework. Detailed documentation about the framework is available from the Google site. For advanced developers, I recommend you read some of the other articles about open regression frameworks such as the Boost unit test framework and CppUnit.

Downloadable resources

  • PDF

Related topics

  • Google TestPrimer
  • Google TestAdvancedGuide
  • Google TestFAQ
  • Open source C/C++ unit testing tools, Part 1: Get to know the Boost unit test framework
  • What Every Computer Scientist Should Know About Floating-Point Arithmetic

REF:

http://www.ibm.com/developerworks/aix/library/au-googletestingframework.html

[gtest][001] A quick introduction to the Google C++ Testing Framework相关推荐

  1. Google C++ Testing Framework之断言

    本节将会深入一步,了解 gTest 的断言机制. 开始. 1. 我们先从测试代码第一行开始: TEST(IsPrimeTest, TrueCondition) 宏: TEST 是一个宏,有两个参数,g ...

  2. A quick introduction to Google test

    视频参考:Google C++ Testing GTest GMock Framework 为什么要使用 Google C++ Testing Framework? 使用这个框架有许多好理由.本文讨论 ...

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

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

  4. What Is Google C++ Mocking Framework?

    (Note: If you get compiler errors that you don't understand, be sure to consult Google Mock Doctor.) ...

  5. Google Mock启蒙篇 [1] (Google C++ Mocking Framework for Dummies 翻译)

    Google C++ Mocking Framework for Dummies Google Mock启蒙篇 Version: 0.07< xmlnamespace prefix =" ...

  6. Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)

    Setting Expectations 成功地使用Mock对象的关键是在它上面设置合适的期望.如果你设置的期望太过严格,你的测试可能会因为无关的改变而失败.如果你把期望设置的太过松驰,bugs可能会 ...

  7. [gtest][002] A quick start to build the Google C++ Testing project

    前言:上一篇谷歌的测试的框架,大致介绍了测试的框架的基本情况.这一节,讲述如何构建一个真正的自动化测试项目: 注意,文章最后一部分有一个视频,这个视频是一步一步构建谷歌测试案例,值得仔细研究. Uni ...

  8. 软件工程师必备的技能 | 单元测试

    关注.星标公众号,直达精彩内容 来源:保罗的酒吧 前言 测试是软件开发过程中一个必须的环节,测试确保软件的质量符合预期. 对于工程师自己来说,单元测试也是提升自信心的一种方式. 直接交付没有经过测试的 ...

  9. 如何成为一名合格的自动驾驶工程师

    今天跟大家分享一篇来自 Felix Friedmann 的技术博客,Felix 目前在奥迪的全资自动驾驶公司 AID感知组从事软件开发工作.我自己在锡根读完书找自动驾驶软件开发岗位工作的时候偶然读到了 ...

最新文章

  1. 中文语言能力评测基准「智源指数」问世:覆盖17种主流任务,19个代表性数据集,更全面、更均衡...
  2. Atomikos 中文说明文档【转】
  3. 面试--Linux命令总结
  4. 二刻拍案惊奇之——国人为什么那么轻视技术
  5. u盘iso安装服务器系统怎么安装win7系统安装方法,win7 iso,手把手教你U盘如何安装win7系统...
  6. Flutter使用阿里矢量图库管理项目svg图片
  7. matlab fft时域采样,信号时域采样 谱分析(matlab).doc
  8. UMLChina公众号文章精选(20220807更新精选)
  9. OutMan——C语言中字符串处理函数、内存管理和内存分区
  10. Xcode8快速注释插件无法使用
  11. java线程池——逐步分析
  12. 前端模板标签eq与neq的使用,以及管理系统模块权限控制
  13. win11恢复win10的右击菜单,自测可用
  14. MySQL主外键设置
  15. 二、CString、CStringA 和 CStringW
  16. Lua入门(1) 编译环境、变量类型与三种结构的实现
  17. python实战小项目,多线程百度云盘下载,突破限速,超越迅雷超高速下载
  18. R-studio超强数据恢复工具(含带注册码)
  19. 【HDOJ】1005 Number Sequence_天涯浪子_新浪博客
  20. C++指针使用方法解惑

热门文章

  1. 微信小程序request:fail invalid url
  2. HGsoft-downloader
  3. 【C语言】输入一个正整数,判断其是否为素数
  4. 工作中,我们经常用到哪些SQL语句呢?
  5. 身份证识别开发_成为您的身份永远不会太晚-在36岁时成为一名开发人员
  6. javascript使用_用JavaScript唤醒沉睡的城市
  7. php implode key,PHP Implode关联数组
  8. origin 设置数据显示位数
  9. SpringBoot-视图解析与模板引擎
  10. shell编程之进阶篇五函数