Googletest 测试

C++进阶 专栏收录该内容
70 篇文章 25 订阅

一、介绍

 

详情参考github:https://github.com/google/googletest/

Future Plans:

  • 1.8.x Release - the 1.8.x is the last release that works with pre-C++11 compilers. The 1.8.x will not accept any requests for any new features and any bugfix requests will only be accepted if proven "critical"
  • Post 1.8.x - work to improve/cleanup/pay technical debt. When this work is completed there will be a 1.9.x tagged release
  • Post 1.9.x googletest will follow Abseil Live at Head philosophy

Welcome to Google Test, Google's C++ test framework!

This repository is a merger of the formerly separate GoogleTest and GoogleMock projects. These were so closely related that it makes sense to maintain and release them together.

Please subscribe to the mailing list at googletestframework@googlegroups.com for questions, discussions, and development.
There is also an IRC channel on OFTC (irc.oftc.net) #gtest available.

Getting started information for Google Test is available in the Google Test Primer documentation.

Google Mock is an extension to Google Test for writing and using C++ mock classes. See the separate Google Mock documentation.

More detailed documentation for googletest (including build instructions) are in its interior googletest/README.md file.

Features

  • An xUnit test framework.
  • Test discovery.
  • A rich set of assertions.
  • User-defined assertions.
  • Death tests.
  • Fatal and non-fatal failures.
  • Value-parameterized tests.
  • Type-parameterized tests.
  • Various options for running the tests.
  • XML test report generation.

Platforms

Google test has been used on a variety of platforms:

  • Linux
  • Mac OS X
  • Windows
  • Cygwin
  • MinGW
  • Windows Mobile
  • Symbian
  • PlatformIO

Who Is Using Google Test?

In addition to many internal projects at Google, Google Test is also used by the following notable projects:

Related Open Source Projects

GTest Runner is a Qt5 based automated test-runner and Graphical User Interface with powerful features for Windows and Linux platforms.

Google Test UI is test runner that runs your test binary, allows you to track its progress via a progress bar, and displays a list of test failures. Clicking on one shows failure text. Google Test UI is written in C#.

GTest TAP Listener is an event listener for Google Test that implements the TAP protocol for test result output. If your test runner understands TAP, you may find it useful.

gtest-parallel is a test runner that runs tests from your binary in parallel to provide significant speed-up.

GoogleTest Adapter is a VS Code extension allowing to view Google Tests in a tree view, and run/debug your tests.

Requirements

Google Test is designed to have fairly minimal requirements to build and use with your projects, but there are some. Currently, we support Linux, Windows, Mac OS X, and Cygwin. We will also make our best effort to support other platforms (e.g. Solaris, AIX, and z/OS). However, since core members of the Google Test project have no access to these platforms, Google Test may have outstanding issues there. If you notice any problems on your platform, please notifygoogletestframework@googlegroups.com. Patches for fixing them are even more welcome!

Linux Requirements

These are the base requirements to build and use Google Test from a source package (as described below):

  • GNU-compatible Make or gmake
  • POSIX-standard shell
  • POSIX(-2) Regular Expressions (regex.h)
  • A C++11-standard-compliant compiler

Windows Requirements

  • Microsoft Visual C++ 2015 or newer

Cygwin Requirements

  • Cygwin v1.5.25-14 or newer

Mac OS X Requirements

  • Mac OS X v10.4 Tiger or newer
  • Xcode Developer Tools

Contributing change

Please read the CONTRIBUTING.md for details on how to contribute to this project.

Happy testing!

二、编译googletest


googletest以开源源码的形式提供,需要自己在项目所在平台中进行编译,这一小节介绍如何编译googletest库

下载源码
googletest的源码在github上托管,托管的地址是https://github.com/google/googletest 
下载源码的方式很简单,配置好你的git后,使用如下命令获取源码

# clone source
git clone https://github.com/google/googletest.git
# checkout newest tag
git checkout release-1.7.0

注意到,在上面的命令中 checkout 出了最新的 tag, 这是因为master分支上的代码不一定能够编译的过

安装CMAKE
googletest使用cmake来生成makefile,所以我们需要下载并安装 cmake 工具。有关 cmake 的介绍可以参考这篇文章 
安装cmake的方法很简单,从这里下载最新的 cmake zip压缩包。 

配置cmake, 在source code和'where to build the binaries'里选择你的实际目录, 点击configure, generate按钮, 我用的是免费的Mingw,请按实际情况选择
配置好的话,会生成makefile, 接下来去执行make:

用VisualStudio打开gtest-1.7.0\msvc目录下的gtest.sln工程。

  1) 分别在Debug与Release模式下编译gtest.sln工程,在对应编译结果文件夹中可以找到gtestd.lib(Debug模式)和gtestd.lib(Release模式)。将编译得到的lib文件拷贝到一个文件夹中,如lib文件夹。由于单元测试环境需要使用gtest-1.7.0.zip压缩包中include文件夹中的头文件,故本文实践中将lib文件夹新建在解压后的gtest-1.7.0中,其路径为C:\gtest-1.7.0\lib。

  2) 在Tools→Options→Projectsand Solutions→VC++Directories中选择“Includefiles”,添加新路径C:\gtest-1.7.0\include。该设置对所有VS工程均生效。

  3) 在Tools→Options→Projectsand Solutions→VC++Directories中选择“Libraryfiles”,添加新库C:\gtest-1.7.0\lib。该设置对所有VS工程均生效。

  4)在Project→Properties→ConfigurationProperties→C/C++→Code Generation中设置RuntimeLibrary。工程为Debug模式设置为Multi-threaded Debug (/MTd),工程为Release模式设置为Multi-threaded (/MT)。该设置仅对当前VS工程生效。

三、简单的测试实例


创建一个test:

使用TEST()宏定义和命名一个特是函数,这是一个普通的无返回值的C++函数。
在函数内部,可以包含任何我们想要添加的C++条件,使用GoogleTest断言去检查相关的值。
测试的结果取决于内部的断言机制。如果有任何的测试失败(不管是fatally还是non-fatally),或者测试中断,那么整个测试失败;否则测试成功。
TEST(testCaseName, testName) {
 ... test body ...
}
testCaseName是 test case的名字,testName是test case内部测试的名称。两者的名称必须是合法的C++标识符,不允许有下划线( _ ) 。不同的test case的内部测试可以有相同的独立的名字。

int Factorial(int n); // Returns the factorial of n

// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
  EXPECT_EQ(1, Factorial(0));
}

// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
  EXPECT_EQ(1, Factorial(1));
  EXPECT_EQ(2, Factorial(2));
  EXPECT_EQ(6, Factorial(3));
  EXPECT_EQ(40320, Factorial(8));
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}


GoogleTest通过test case组织测试结果,因此逻辑相关的测试必须在一个test case中;换句话说,TEST()的第一个参数必须相同。上面例子的HandlesZeroInput和HandlesPositiveInput都属于FactorialTest这个测试实例。
 

四、相关知识


4.1 Test、Test Case 和 Test Suite
此处介绍三个概念:Test、Test Case 和 Test Suite。

这三者在某些场景下容易混淆。

由于某些历史原因,googletest 使用 Test Case 来将相关的 Test 归为一组,然而,当前 ISTQB(International Software Testing Qualifications Board) 和很多关于软件质量书籍都使用 Test Suite 替换 Test Case;而 googletest 中的 Test 则对应 ISTQB 的 Test Case。总结后,即下表内容:

Meaning    googletest Term    ISTQB Term
Exercise a particular program path with specific input values and verify the results    TEST()    Test Case
A set of several tests related to one component    Test Case    Test Suite
4.2 基本概念
使用 googletest,最先写的就是断言(assertion)。断言是一种检查某个条件是否为真的描述。断言的结果可以是成功、非致命失败、致命失败。当致命失败发生时,当前函数将会终止;而断言的其他结果则不会有此效果。

Test 使用断言来判断测试代码的行为:如果一个 Test 崩溃了或者出现了一个失败的断言,则该 Test 就失败了;反之,它就是成功的。

Test case 包括一个或多个 Test。我们应当把 Test 打包、分组,放入 Test Case 中,以便测试代码的结构更加清晰。当一个 Test Case 中的多个 Test 需要共享对象和子程序时,我们可以把这些共享内容放入一个(test fixture)类中。

一个测试程序可以包含多个 Test Case。

4.3 断言(assertion)
googletest 的断言是类似函数调用的宏。

我们可以通过编写相关的断言,来测试类或函数的行为。如果断言失败了,googletest 将打印该断言的源文件及行号信息,以及该失败信息。我们也可以定制 googletest 的失败信息。

当前,有两种断言可供我们使用:

ASSERT_* :当断言失败时,产生致命错误,并终止当前函数;
EXPECT_* :当断言失败时,产生非致命错误,并且不会终止当前函数。
通常,我们都会选择 EXPECT_*,因为它能让我们在一次测试中测试出更多的失败情况。不过,如果我们想要在出现失败的测试时立即终止程序,则要选择 ASSERT_*。

注意:因为 ASSERT_* 会在失败时立即终止函数,那么就可能跳过后面程序中进行清理工作的代码,由此可能会产生内存泄露。所以我们在使用 ASSERT_* 时,要留心检查堆内存,防止内存泄露。

一些常见的断言语句如下:

test() 示例

TEST() 宏的第一个参数是 Test Case 的名称,第二个参数是(隶属于第一个Test Case参数的)Test 的名称。一个测试的完整名称包括 Test Case 名称及 Test 的名称,不同 Test Case 的 Test 名称可以相同。

#include "gtest/gtest.h"
 
// 此函数用于判断入参是否为正整数:如果是,则返回0;否则,返回-1
int Positive(int nNum)
{
    if (nNum > 0)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}
 
// 测试入参2是否为正整数
TEST(PositiveTest, HandlesPositiveInput)
{
    EXPECT_EQ(Positive(2), 0);
}
 
// 测试入参0是否为正整数
TEST(PositiveTest, HandlesZeroInput)
{
    EXPECT_EQ(Positive(0), -1);
}
 
// 测试入参-2是否为正整数
TEST(PositiveTest, HandlesNegativeInput)
{
    EXPECT_EQ(Positive(-2), -1);
}
 
int main(int argc, char **argv)
{
    // 分析gtest程序的命令行参数
    testing::InitGoogleTest(&argc, argv);
 
    // 调用RUN_ALL_TESTS()运行所有测试用例
    // main函数返回RUN_ALL_TESTS()的运行结果
    return RUN_ALL_TESTS();
}
 

在上述代码中,我们编写了三个 test,分别为:HandlesPositiveInput、HandlesZeroInput 和 HandlesNegativeInput,这三个 test 都属于同一个 test case(PositiveTest)。

TEST_F()宏


当我们想让多个 test 使用同一套数据配置时,就需要用到 Test Fixtures 了。

test fixtures 的用法相对复杂一些,创建 fixture 的具体方法如下:

派生一个继承 ::testing::Test 的类,并将该类中的一些内容声明为 protected 类型,以便在子类中进行访问;
根据实际情况,编写默认的构造函数或SetUp()函数,来为每个 test 准备所需内容;
根据实际情况,编写默认的析构函数或TearDown()函数,来释放SetUp()中分配的资源;
根据实际情况,定义 test 共享的子程序。
当使用 fixture 时,我们使用 TEST_F() 宏代替 TEST() 宏,TEST_F() 允许我们在 test fixture 中访问对象和子程序。

注意:TEST_F() 的第一个参数(即 test case 的名称)必须是 test fixture 类的名字。

对于 TEST_F() 定义的每个 test,googletest 将会在运行时创建一个新的 test fixture,并立即通过 SetUp() 对其进行初始化,然后运行 test,之后通过调用 TearDown() 进行数据清理,最后删除 test fixture。需要注意的是,同一个 test case 中不同的 test 具有不同的 test fixture 对象,并且 googletest 每次创建新的 test fixture 前都会先删除之前的 test fixture。多个 test 不会重用相同的 test fixture,某个 test 对 fixture 进行的修改对其他 test 无影响。
 

#include "gtest/gtest.h"
 
// 定义测试类FooTest
class FooTest: public testing::Test {
protected:
    // Code here will be called immediately after the constructor (right before each test)
    void SetUp()
    {
        m_nTarget = 5;
    }
 
    // Code here will be called immediately after each test (right before the destructor)
    void TearDown()
    {
    }
 
public:
    int IsLargeThan5(const int & nNum);
    int m_nTarget;
};
 
// 判断入参是否大于5:如果是,则返回0;否则返回-1
int FooTest::IsLargeThan5(const int & nNum)
{
    if (nNum > m_nTarget)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}
 
TEST_F(FooTest, HandlesInput6)
{
    EXPECT_EQ(IsLargeThan5(6), 0);
}
 
TEST_F(FooTest, HandlesInput5)
{
    EXPECT_EQ(IsLargeThan5(5), 0);
}
 
TEST_F(FooTest, HandlesInput4)
{
    EXPECT_EQ(IsLargeThan5(4), -1);
}
 
int main(int argc, char **argv)
{
    // 分析gtest程序的命令行参数
    ::testing::InitGoogleTest(&argc, argv);
 
    // 调用RUN_ALL_TESTS()运行所有测试用例
    // main函数返回RUN_ALL_TESTS()的运行结果
    return RUN_ALL_TESTS();
}

在上述代码中,我们编写了三个 test,分别为:HandlesInput6、HandlesInput5 和 HandlesInput4,这三个 test 都属于同一个 test case(即 FooTest)。注意,这里的 test case(即 FooTest) 一定要是 test fixture 类。

上述代码中的 test 运行时,主要会进行如下操作:

googletest 构造一个 FooTest 类的对象(我们称之为 f1);
f1.SetUp() 函数对 f1 进行初始化;
使用对象 f1,运行第一个 test(HandlesInput6);
f1.TearDown() 在 test 完成后,进行清理工作;
对象 f1 被析构。
上述5个步骤在另一个 FooTest 类的对象(如 f2)中重复,此次会运行 HandlesInput5。
 


在上面的代码示例中我们能够看到,调用 Test 的操作是通过 RUN_ALL_TESTS() 宏完成的。

RUN_ALL_TESTS() 宏在所有 test 都成功时,返回0;否则返回1。需要注意的是,RUN_ALL_TESTS() 会运行所有关联的 test,这些 test 可以来自不同的 test case,甚至不同的源文件。

当我们调用 RUN_ALL_TESTS() 宏的时候,会进行以下操作:

保存所有 googletest flag 的状态;
为第一个 test 创建一个 test fixture 对象;
通过 SetUp() 对上一步创建的 test fixture 对象进行初始化;
使用 test fixture 对象运行 test;
通过 TearDown() 清理 fixture;
删除 fixture;
还原所有 googletest flag 的状态;
为下一个 test 重复上述操作,直到所有的 test 执行完成。
注意:main() 函数必须要返回 RUN_ALL_TESTS() 宏的结果。同时,RUN_ALL_TESTS() 只能运行一次,多次调用会与 googletest 的一些功能(如 thread-safe death tests)发生冲突。


编写 main() 函数时,要返回 RUN_ALL_TESTS() 宏的值。

main() 函数中的 ::testing::InitGoogleTest() 函数将会解析命令行中的 googletest 参数,它允许用户通过多样的命令行参数来控制测试程序的行为(即定制命令行参数的功能)。需要注意的是,::testing::InitGoogleTest() 函数必须要在 RUN_ALL_TESTS() 之前调用,否则对应的 flag 可能不会被正常地初始化。


Google Test 是线程安全的,其线程安全特性要依赖 pthreads 库。
 

  • 0
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值