gtest 介绍
GTest是⼀个跨平台的 C++单元测试框架,由google公司发布。gtest是为了在不同平台上为编写C++单元测试⽽⽣成的。它提供了丰富的断⾔、致命和⾮致命判断、参数化等等测试所需的宏,以及全局测试,单元测试组件。
一、gtest 安装
bash
sudo apt-get install libgtest-dev
二、gtest 使用
2.1 包含头文件
cpp
#include <gtest/gtest.h>
2.2 程序编译时的链接
makefile
g++ main.cc -o main -lgtest
2.3 TEST 宏
cpp
TEST(测试名称, 测试样例名称)
TEST_F(test_fixture,test_name)
-
TEST:主要用来创建一个简单测试,定义了一个测试函数,在这个函数中可以使用任何的 C++ 代码并使用框架提供的断言进行检查。 TEST 主要用于定义不需要复杂初始化或数据共享的测试用例,每个 TEST 都是独立的,互不干扰。 -
TEST_F:主要用来进行多样测试,TEST_F 用于需要共享初始化逻辑、清理逻辑或测试数据的场景,在多个测试用例中复用相同的测试环境。
⚠️ 测试用例和测试样例名称无需使用双引号,且同测试下多个测试样例不能同名。
2.4 断言宏
GTest中的断⾔的宏可以分为两类:
-
ASSERT_系列:如果当前点检测失败则退出当前函数。
-
EXPECT_系列:如果当前点检测失败则继续往下执⾏。
| 类别 | 断言宏 | 说明 |
|---|---|---|
| 布尔检查 | EXPECT_TRUE(condition) |
检查条件是否为真 |
EXPECT_FALSE(condition) |
检查条件是否为假 | |
| 数值比较 | EXPECT_EQ(val1, val2) |
检查 val1 == val2 |
EXPECT_NE(val1, val2) |
检查 val1 != val2 |
|
EXPECT_LT(val1, val2) |
检查 val1 < val2 |
|
EXPECT_GT(val1, val2) |
检查 val1 > val2 |
|
EXPECT_LE(val1, val2) |
检查 val1 <= val2 |
|
EXPECT_GE(val1, val2) |
检查 val1 >= val2 |
|
| 字符串比较 | EXPECT_STREQ(str1, str2) |
检查两个 C 字符串内容相同 |
EXPECT_STRNE(str1, str2) |
检查两个 C 字符串内容不同 | |
| 异常检查 | EXPECT_THROW(statement, exception_type) |
检查语句是否抛出了指定类型的异常 |
2.5 初始化和调用
cpp
#include <gtest/gtest.h>
int main(int argc , char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
2.6 简单案例
gtest.cc:
cpp
#include <iostream>
#include <unordered_map>
#include <gtest/gtest.h>
TEST(unordered_map_test , insert) {
std::unordered_map<int,int> hash;
hash.insert({1, 1});
hash.insert({2, 2});
hash.insert({3, 3});
ASSERT_EQ(hash.size() , 3);
}
int main(int argc , char* argv[]) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
Makefile:
makefile
main: gtest.cc
g++ -o $@ $^ -std=c++17 -lgtest
输出结果:
bash
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from unordered_map_test
[ RUN ] unordered_map_test.insert
[ OK ] unordered_map_test.insert (0 ms)
[----------] 1 test from unordered_map_test (1 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (1 ms total)
[ PASSED ] 1 test.
三、gtest 事件机制
GTest 中的事件机制是指在测试前和测试后提供给⽤⼾⾃⾏添加操作的机制,⽽且该机制也可以让同⼀测试套件下的测试⽤例共享数据。GTest框架中事件的结构层次:
-
测试程序 :测试程序是整个测试的可执行文件,包含所有测试套件和测试用例。一个测试程序通常对应一个可执行文件。对应
main函数。该级别的事件机制是在程序的开始和结束执⾏。 -
测试套件(TestSuite) :测试套件是一组相关的测试用例的集合,通常用于测试同一个类或同一个功能模块。测试套件通过
TEST()宏的第一个参数来标识。该级别的事件机制是在整体的测试案例开始和结束执⾏。 -
测试用例(TestCase) :测试用例是最小的测试单元,代表一个具体的测试点。测试用例通过
TEST()宏的第二个参数来标识。该级别的事件机制是在每个测试⽤例开始和结束都执⾏。
3.1 全局事件
全局事件是 Google Test 事件机制中级别最高的事件,通过继承 testing::Environment 类实现,然后实现两个虚函数 SetUp 与 TearDown,同时,在 main 函数中调用 testing::AddGlobalTestEnvironment(new MyGlobalEnvironment),允许你在整个测试程序运行前后执行自定义的初始化和清理代码。
Setup() 和 TearDown() 的执行时机:在所有测试运行之前/之后执行。
cpp
#include <iostream>
#include <unordered_map>
#include <gtest/gtest.h>
std::unordered_map<int,int> hash;
class GlobalEnvironment : public testing::Environment {
public:
virtual void SetUp() override {
std::cout << "在所有的测试之前执行" << std::endl;
hash.insert({1, 1});
hash.insert({2, 2});
hash.insert({3, 3});
};
virtual void TearDown() override {
std::cout << "在所有的测试之后执行" << std::endl;
hash.clear();
}
};
TEST(unordered_map_test , size) {
EXPECT_EQ(hash.size() , 3); // true
}
TEST(unordered_map_test , erase) {
hash.erase(1);
EXPECT_EQ(hash.size() , 3); // false
EXPECT_EQ(hash.size() , 2); // true
}
TEST(unordered_map_test , find) {
EXPECT_EQ(hash.find(1) , hash.end()); // true
}
int main(int argc , char* argv[]) {
testing::InitGoogleTest(&argc , argv);
testing::AddGlobalTestEnvironment(new GlobalEnvironment);
return RUN_ALL_TESTS();
}
输出结果:
bash
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
在所有的测试之前执行
[----------] 3 tests from unordered_map_test
[ RUN ] unordered_map_test.size
[ OK ] unordered_map_test.size (0 ms)
[ RUN ] unordered_map_test.erase
gtest.cc:27: Failure
Expected equality of these values:
hash.size()
Which is: 2
3
[ FAILED ] unordered_map_test.erase (0 ms)
[ RUN ] unordered_map_test.find
[ OK ] unordered_map_test.find (0 ms)
[----------] 3 tests from unordered_map_test (0 ms total)
[----------] Global test environment tear-down
在所有的测试之后执行
[==========] 3 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 2 tests.
[ FAILED ] 1 test, listed below:
[ FAILED ] unordered_map_test.erase
1 FAILED TEST
3.2 TestSuite 事件
测试套件事件是在每个测试套件(Test Suite)开始和结束时触发的事件 ,允许你在测试套件级别执行初始化和清理操作。通过继承 testing::Test 类实现 ,然后实现 两个静态函数 SetUpTestCase 与 TearDownTestCase。
⚠️:测试套件的事件机制不需要像全局事件机制一样在 main 函数中注册。
⚠️:TEST 宏需要改为 TEST_F 宏。
⚠️:TEST_F 的第一个参数必须要与创建类的名称完全一致。
SetUpTestCase() 和 TearDownTestCase() 的执行时机:在该测试套件第一个测试用例开始前/最后一个测试用例结束后执行。
cpp
#include <iostream>
#include <unordered_map>
#include <gtest/gtest.h>
class UnorderedMapEnvironmentTest : public testing::Test {
public:
static void SetUpTestCase() {
std::cout << "在该测试套件第一个测试用例开始前执行" << std::endl;
}
static void TearDownTestCase() {
std::cout << "在该测试套件最后一个测试用例结束后执行" << std::endl;
}
public:
std::unordered_map<int,int> hash;
};
TEST_F(UnorderedMapEnvironmentTest , size) {
hash.insert({1, 1});
hash.insert({2, 2});
EXPECT_EQ(hash.size() , 2);
}
TEST_F(UnorderedMapEnvironmentTest , find) {
// 这里是一个全新的 map
// EXPECT_EQ(hash.find(2)->second , 2); // 段错误
hash.insert({2, 2});
EXPECT_EQ(hash.find(2)->second , 2);
}
int main(int argc , char* argv[]) {
testing::InitGoogleTest(&argc , argv);
return RUN_ALL_TESTS();
}
输出结果:
bash
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from UnorderedMapEnvironmentTest
在该测试套件第一个测试用例开始前执行
[ RUN ] UnorderedMapEnvironmentTest.size
[ OK ] UnorderedMapEnvironmentTest.size (0 ms)
[ RUN ] UnorderedMapEnvironmentTest.find
[ OK ] UnorderedMapEnvironmentTest.find (0 ms)
在该测试套件最后一个测试用例结束后执行
[----------] 2 tests from UnorderedMapEnvironmentTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 2 tests.
3.3 TestCase 事件
测试用例事件是在每个测试用例(Test Case)运行前后触发的事件,通过继承 Testing::Test 类,然后实现两个虚函数 SetUp() 和 TearDown() 方法实现 ,确保每个测试用例都有独立的运行环境。
Setup() 和 TearDown() 的执行时机:在该测试套件的每一个测试用例开始前/每一个测试用例结束后执行。
cpp
#include <iostream>
#include <unordered_map>
#include <gtest/gtest.h>
class UnorderedMapEnvironmentTest : public testing::Test {
public:
static void SetUpTestCase() {
std::cout << "在该测试套件第一个测试用例开始前执行" << std::endl;
}
static void TearDownTestCase() {
std::cout << "在该测试套件最后一个测试用例结束后执行" << std::endl;
}
virtual void SetUp() override {
std::cout << "在该测试套件的每一个测试用例开始前执行" << std::endl;
hash.insert({1, 1});
hash.insert({2, 2});
hash.insert({3, 3});
};
virtual void TearDown() override {
std::cout << "在该测试套件的每一个测试用例结束后执行" << std::endl;
hash.clear();
}
public:
std::unordered_map<int,int> hash;
};
TEST_F(UnorderedMapEnvironmentTest , size) {
EXPECT_EQ(hash.size() , 3);
}
TEST_F(UnorderedMapEnvironmentTest , find) {
EXPECT_EQ(hash.find(2)->second , 2);
}
int main(int argc , char* argv[]) {
testing::InitGoogleTest(&argc , argv);
return RUN_ALL_TESTS();
}
输出结果:
bash
[==========] Running 2 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 2 tests from UnorderedMapEnvironmentTest
在该测试套件第一个测试用例开始前执行
[ RUN ] UnorderedMapEnvironmentTest.size
在该测试套件的每一个测试用例开始前执行
在该测试套件的每一个测试用例结束后执行
[ OK ] UnorderedMapEnvironmentTest.size (0 ms)
[ RUN ] UnorderedMapEnvironmentTest.find
在该测试套件的每一个测试用例开始前执行
在该测试套件的每一个测试用例结束后执行
[ OK ] UnorderedMapEnvironmentTest.find (0 ms)
在该测试套件最后一个测试用例结束后执行
[----------] 2 tests from UnorderedMapEnvironmentTest (0 ms total)
[----------] Global test environment tear-down
[==========] 2 tests from 1 test suite ran. (0 ms total)
[ PASSED ] 2 tests.