准备工作
GoogleTest官网:https://google.github.io/googletest/
gtest github仓库:https://github.com/google/googletest
目前最新稳定版本:https://github.com/google/googletest/releases/tag/v1.13.0
下载源码,到目录下创建build文件夹进入后运行 cmake …
测试宏
gtest有两套测试宏:ASSERT_* 和 EXPECT_*:
- ASSERT_* 会生成fatal错误并终止当前函数,断言失败后立即返回,很有可能跳过清理代码,所以有可能发生资源泄露,看使用场景是否允许这种情况发生
- EXPECT_* 生成非fatal错误,不会终止当前函数。
在使用中优先选择EXPECT_* 。如果发生错误继续测试下去没有意义可以使用ASSERT_*
两个概念
- test suites:测试函数
- test fixtures:测试类
test suites
创建一个test suite:
- 使用TEST*()宏定义一个test函数,不需要返回值。test suite的第一个参数为test suite名,第二个参数名为test suite内的test名称。名称中不能包含下划线"_"。一个测试的全名称包含test suite名+test 名。不同的test suite可以有相同的test名。
- 函数体中除了自定义内容外,使用各种gtest测试断言检查值
- 测试结果由gtest测试断言决定,如果断言失败,或crash,整个测试失败。
Google test按照测试套test suite对测试结果进行分组,所以逻辑上有相关联的都应该在同一个测试套中。
Test Fixtures
使用test fixture的场景:有两个或更多的test使用相同的数据
创建一个fixture:
- 继承自::testing::Test,使用protected(因为TEST_F中可以直接访问到继承类中定义的数据成员)
- 在类中声明定义任何想要使用的对象
- 如果需要可以实现默认构造或者SetUp()去执行开始测试程序之前的操作;注意不要写成Setup(),使用override关键字可以防止拼写错误
- 如果需要可以实现析构或者TearDown()释放SetUp中申请的资源。在哪些地方使用构造/析构,在哪些地方使用SetUp()/TearDown(),一般情况下优先使用构造/析构,因为参考这里:
- 可以初始化定义的常量,常量的定义可以避免被修改
- 继承了test fixture的子类后如果使用SetUp/TearDown可能会忘记调用,构造和析构不会出现这种情况(什么情况下需要继承test fixture类?)
有以下情况可以优先使用SetUp()/TearDown():
- 构造和析构中不能使用ASSERT_xx宏,但可以在SetUp中调用
- 如果tear-down操作抛出异常,就必须使用TearDown()而不是析构
当使用test fixture时,使用TEST_F()代替TEST(),TEST_F()(_F代表Fixture)允许你在test fixture中访问对象和子程序。TEST_F()的第一个参数必须是 test fixture 的类名,所以必须在使用TEST_F之前定义一个test fixture类。TEST_F中不需要test suite。
对于每一个TEST_F(),gtest会创建一个新的test fixture对象,并立即调用SetUp()后运行测试,然后在调用TearDown()后删除test fixture。
注意,在同一个test suite中不同的tests有不同的test fixture对象,gtest会在创建新的test fixture之前先删除以前的。gtest不会在多个tests中复用test fixture。任何一个对test fixture改变的test的改变不会影响其他test
(TEST和TEST_F要写在cpp中,h和hpp中没法调用)
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(q0_.size(), 1);
}
TEST_F(QueueTest, DequeueWorks) {
int *n = q0_.Dequeue();
EXPECT_EQ(n, nullptr);
delete n;
}
处理流程如下:
- 开始第一个测试(IsEmptyInitially)gtest构造QueueTest对象(我们称之为t1)
- 自动调用 t1.SetUp() 初始化t1
- 执行第一个test的test body
- t1.TearDown()执行清理工作
- t1析构
- 重复第二个test(DequeueWorks)
测试运行流程
TEST和TEST_F会隐式的注册到GoogleTest中,所以不需要额外操作。定义完tests之后,可以运行 RUN_ALL_TESTS(),它会让所有的tests运行(即使在不同的文件中)。成功返回0,否则返回1。
RUN_ALL_TESTS()运行之后:
- 保存gtest flags的状态
- 为第一个test创建test fixture
- 通过SetUp()初始化
- 在fixture对象上运行test
- 通过TearDown() 清理fixture
- 删除fixture
- 保存gtest flags的状态
- 重复开始下一个test,直到所有的tests都运行完
main函数
对于不需要做额外操作的用户来说应该使用gtest_main代替main。如果需要在测试运行前要做一些其他操作,可以使用main。使用main时需要返回RUN_ALL_TESTS()
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
::testing::InitGoogleTest() 解析命令行参数,必须要在RUN_ALL_TESTS()前调用,详细信息参考https://google.github.io/googletest/advanced.html
- gtest_main的用法示例 TODO
关于线程安全
gtest在pthreads库中被设计为是线程安全的,在其他情况下多线程下是不安全的,大多数情况下断言只在main线程中执行,所以不会有问题,如果要支持多线程安全需要使用gtest-port.h中的同步机制