简介

Google Testgtest),也称为Google C++ Testing Framework,是一个由Google开发的开源C++测试框架,提供了多种工具来支持C++代码的单元测试。主要功能包括:

  • 提供了多种断言方法,可以用于测试函数、代码片段的预期行为。
  • 支持自动化测试,可以方便编写测试用例,并自动运行和输出结果。
  • 支持死亡测试(Death Test),测试代码在极端或异常条件下的行为表现。
  • 提供测试夹具(Test Fixture,一种用于编写可重复执行的测试用例的机制),使得测试用例便于重用。
  • 易于组织测试用例,通过测试套件集中管理。
  • 提供参数化测试、类型参数化测试等功能。
  • 与其他Google测试框架集成,如Google Mock(gmock,用于测试的模拟对象),可以用来测试代码依赖。
  • 支持多平台使用,包括Linux、Windows、Mac等。

一、安装

官方源码:GitHub - google/googletest: GoogleTest - Google Testing and Mocking Framework

我安装在linux上,版本是v1.13.0,官方已明确要求使用的C++标准至少是C14版本。详细的安装过程已在googletest-main/googletest/README.md中说明,如果嫌阅读英文麻烦可以执行以下命令:

git clone https://github.com/google/googletest.git -b v1.13.0
cd googletest        # Main directory of the cloned repository.
cmake .. -DBUILD_GMOCK=OFF
make
sudo make install    # Install in /usr/local/ by default

为找到自己需要的帮助文档,可以先看看googletest-main/docs/index.md

# GoogleTest User's Guide

## Welcome to GoogleTest!

GoogleTest is Google's C++ testing and mocking framework. This user's guide has
the following contents:

*   [GoogleTest Primer](primer.md) - Teaches you how to write simple tests using
    GoogleTest. Read this first if you are new to GoogleTest.
*   [GoogleTest Advanced](advanced.md) - Read this when you've finished the
    Primer and want to utilize GoogleTest to its full potential.
*   [GoogleTest Samples](samples.md) - Describes some GoogleTest samples.
*   [GoogleTest FAQ](faq.md) - Have a question? Want some tips? Check here
    first.
*   [Mocking for Dummies](gmock_for_dummies.md) - Teaches you how to create mock
    objects and use them in tests.
*   [Mocking Cookbook](gmock_cook_book.md) - Includes tips and approaches to
    common mocking use cases.
*   [Mocking Cheat Sheet](gmock_cheat_sheet.md) - A handy reference for
    matchers, actions, invariants, and more.
*   [Mocking FAQ](gmock_faq.md) - Contains answers to some mocking-specific
    questions.

新手入门可阅读primer.md,高级功能可阅读advanced.md

二、基本概念

1、怎样才算是好的测试程序?

  • 测试应是独立的和可重复的。
  • 测试应易于组织,并反映被测试代码的结构。gtest会将共享数据的测试分组到同一测试套件中。
  • 测试应该是可移植的和可重用的。
  • 当测试失败时,应该提供尽可能多的关于这个问题的信息。gtest不会在第一次测试失败时停止。相反,它只停止当前的测试,并继续执行下一个测试。这样就能在一个运行周期中检测并修复多个错误。
  • 测试框架应该将测试编写者从繁复工作中解放出来,并让他们专注于测试内容。gtest会自动检测所有的测试套件,而不需要用户枚举所有的测试来运行它们。
  • 测试应该很快。对于共享的数据,只需要构造、销毁一次就跨测试复用共享资源,无需使测试相互依赖。

2、命名规则

gtest中,一个测试用例用宏TEST()表示,简称为测试。接下来的解释中,请不要混淆。

3、断言

gtest中的测试用例都是通过使用断言来验证被测代码的行为。断言是检查条件是否为真的语句。断言的结果可以是成功、非致命失败或致命失败。如果发生致命失败,则中止当前函数;否则程序将正常继续运行。

TEST(TestSuiteName, TestName) {
    //... test body ...
}

使用TEST()宏来定义一个测试,TEST()是一个没有返回值的宏函数。函数体中除了C++语句外,还需要添加断言。测试的结果就由断言的结果来决定。TEST()包含两个参数,第一个参数是测试套件的名称,第二个参数是测试套件中的测试的名称。这两个名称都必须是有效的C++标识符,并且它们不应该包含任何下划线(_)。

gtest按测试套件将测试结果进行分组,因此逻辑相关的测试应该在同一个测试套件中;也就是说,它们TEST()定义中,第一个参数应该是相同的。

int Factorial(int n); // 返回n的阶乘

// 测试0的阶乘,属于FactorialTest测试套件
TEST(FactorialTest, HandlesZeroInput) {
	EXPECT_EQ(Factorial(0), 1);
}

// 测试正数的阶乘,属于FactorialTest测试套件
TEST(FactorialTest, HandlesPositiveInput) {
    EXPECT_EQ(Factorial(1), 1);
    EXPECT_EQ(Factorial(2), 2);
    EXPECT_EQ(Factorial(3), 6);
    EXPECT_EQ(Factorial(8), 40320);
}

断言类似于宏函数。当断言失败时,gtest将打印断言的源文件和行号位置,以及一条失败消息。你还可以提供一个自定义的失败消息,将它附加到gtest的输出信息中。如下:

// 一切能通过ostream输出的内容都能通过这两个宏输出
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;

ASSERT_*这类断言会在失败时产生致命错误,并中止当前函数。EXPECT_*断言则生成非致命错误,它不会中止当前函数。通常首选EXPECT_*,因为它们允许在一个测试中报告多个错误信息。但是,如果出现失败后继续运行没有意义时,你应该使用ASSERT_*

关于断言更详细的说明可以参考googletest-main/docs/reference/assertions.md

4、测试夹具

测试是最小的组成单位。一个测试套件包含一个或多个测试,用来划分单独的功能。一个测试程序中包含多个测试套件。当一个测试套件中的多个测试需要共享公共对象和子例程时,可以将它们放到一个测试夹具(Test Fixture)中。

测试夹具(Test Fixture)是一种用于编写可重复执行的测试用例的机制。它可以在多个测试用例中重复使用,主要有以下特点:

  1. 测试夹具类中包含多个测试用例。
  2. 提供预置条件(SetUp)和收尾清理(TearDown)代码,为多个测试用例初始化环境和清理环境。
  3. 每个测试用例可以关注不同的功能点或输入,并验证输出。
  4. 测试夹具封装了准备工作,使测试用例更简洁。
  5. 同一个测试夹具可以重复用于不同的测试用例集。

可以这样创建一个夹具:

  1. 继承::testing::Test,并将其成员声明为protected,方便它的子类访问。
  2. 在类中声明你需要使用的对象。
  3. 有必要的话,创建SetUp()函数用于初始化对象,相当于类的构造函数。
  4. 有必要的话,创建TearDown()函数用于回收对象,相当于类的析构函数。
  5. 使用TEST_F()宏函数来声明夹具,与TEST()类似,只不过第一个参数必须为夹具类名,第二个参数则为测试名。

如,创建一个队列的测试夹具:

template <typename E> // E is the element type.
class Queue {
public:
	Queue();
	void Enqueue(const E& element);
	E* Dequeue(); // Returns NULL if the queue is empty.
	size_t size() const;
	...
};

class QueueTest : public ::testing::Test {
protected:
    void SetUp() override {
    // q0_ remains empty
    q1_.Enqueue(1);
    q2_.Enqueue(2);
    q2_.Enqueue(3);
	}

    // void TearDown() override {}
    Queue<int> q0_;
    Queue<int> q1_;
    Queue<int> q2_;
}

TEST_F(QueueTest, IsEmptyInitially) {
	EXPECT_EQ(q0_.size(), 0);
}

TEST_F(QueueTest, DequeueWorks) {
    int* n = q0_.Dequeue();
    EXPECT_EQ(n, nullptr);

    n = q1_.Dequeue();
    ASSERT_NE(n, nullptr);
    EXPECT_EQ(*n, 1);
    EXPECT_EQ(q1_.size(), 0);
    delete n;

    n = q2_.Dequeue();
    ASSERT_NE(n, nullptr);
    EXPECT_EQ(*n, 2);
    EXPECT_EQ(q2_.size(), 1);
    delete n;
}

三、运行样例

1、示例路径

有哪些示例,示例演示的功能,已经在googletest-main/docs/samples.md中进行了说明。代码存放在googletest-main/googletest/samples下。但是示例不能直接运行,需要建立cmake工程进行编译。

2、创建cmake工程

sample目录下新建case1目录,将sample1_unittest.ccsample1.ccsample1.h拷贝至该目录。其中sample1.hsample1.c是用户功能模块,sample1_unittest.cc是单元测试模块。main函数则可以引用现有的src/gtest_main.c文件。添加CMakeLists.txt后就创建了sample1的cmake工程。

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)

# 工程名
project(gtest_sample)

# 配置编译选项
set(CMAKE_CXX_COMPILE_FLAGS "std=c++14")

# 头文件路径
include_directories(
    /usr/local/include/gtest
    ${CMAKE_CURRENT_SOURCE_DIR}/../../include/gtest
)

# 生成可执行程序的文件,使用通配符指定
file(GLOB CPP_FILES
    ${CMAKE_CURRENT_SOURCE_DIR}/*.c*
    ${CMAKE_CURRENT_SOURCE_DIR}/../../src/gtest_main.c*
)
add_executable(${PROJECT_NAME} ${CPP_FILES})

# 依赖库列表
target_link_libraries(${PROJECT_NAME} 
    gtest
    gtest_main
    pthread
)
Note
file()支持引用通配符,能包含所有需要的.cc文件;
按说明文档指示,编译标准至少支持c14;
依赖的库中需要添加pthread
如果不想重写main函数,可以链接gtest_main,使用官方的main函数;

3、运行结果

cd case1
cmake .
make
./gtest_sample

在这里插入图片描述

运行结果会展示运行了几个测试套件、耗时、以及结果。

四、高级功能

这里仅介绍部分高级功能概念,至于如何使用,还是得参考googletest-main/docs/advanced.md

  • 更丰富的断言
    使用谓词形式的断言、使用带返回值的断言、浮点断言、字符串断言、gmock使用。
  • 死亡测试(Death Test)
    一种特殊的单元测试技术,用于检测代码在极端或异常条件下的行为表现。通过故意传入非法或极端输入,使被测代码产生崩溃或异常。验证代码在这种情况下是否如预期般崩溃。 如果没有崩溃,则测试失败。
  • 记录额外信息
    能生成xml、json等格式的报告。
  • 类型测试
    可以先定义测试逻辑,然后再用不同的类型列表来实例化…
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐