使用gtest做单元测试

使用gtest做单元测试


gtest是一个跨平台的(Liunx、Mac OS X、Windows 、Cygwin 、Windows CE and Symbian ) C++单元测试框架,由google公司发布。gtest是为在不同平台上为编写C++测试而生成的。它提供了丰富的断言、致命和非致命判断、参数化、”死亡测试”等等

1.用gtest写测试工程的大致流程

配置gtest头文件及库

下载gtest源码:

Releases · google/googletest (github.com)

一般选择最新版应该就没啥问题

放到本地编译,这里假设下载的是1.8.0版本

tar -zxvf googletest-release-1.8.0.tar.gz 
cd googletest-release-1.8.0/ 
mkdir build 
cd build 
cmake .. 
# 编译 
make 
# 安装 
make install

编译完之后,把googletest/include下的gtest头文件拷贝放到自己测试工程的include目录下。

image-20220529110417505

然后把编译出来的静态库(在build/googlemock/gtest下,分别叫libgtest.a和libgtest_main.a),放到自己测试工程下的lib文件夹下。我本地的lib目录如下,其中gmock是用来打桩的,打桩的意思是测试中一个函数还没有实现,然后在需要调用该函数的地方设置一个返回规则,这个加不加都无所谓。

image-20220529110216051

然后在CMakeLists.txt加入相应的配置信息

# 包含头文件的路径 
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/include")
# 设置库文件的生成路径
set(LIBRARY_PATH "${CMAKE_CURRENT_SOURCE_DIR}/lib")

# 链接依赖的库: gtest库,pthread库 
target_link_libraries(Test目标文件 ${LIBRARY_PATH}/gtest/libgtest.a) 
target_link_libraries(Test目标文件 ${LIBRARY_PATH}/gtest/libgtest_main.a) 
target_link_libraries(Test目标文件 pthread)

然后在测试工程源文件中添加对gtest头文件,就可以使用gtest的一系列宏定义来写单元测试函数了

// Test.cpp 
#include <gtest/gtest.h> 
#include "待测试代码头文件.h" /* 待测试的业务代码头文件 */ 

/* 使用TEST宏定义测试名、用例名 */ 
TEST(Module1, function1) 
{ 
    int res = function1(...); /* 调用待测试函数 */ 
    ... 
    EXPECT_EQ(res, 1); 
    /* 比较返回和期望值 */ 
}

最后写上运行所有测试用例,就可以跑测试了。

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

以上都写得很简单,但大概流程就是,拉取gtest源码进行编译,生成gtest静态库,然后把gtest的头文件和库文件加入测试工程中,这样就可以调用gtest了。在自己测试工程中使用TEST或者TEST_F宏定义结合断言来写单元测试函数,最后运行RUN_ALL_TESTS()来运行所有测试用例。当然,CMakeLists.txt中也是必须添加相关路径引用设置的。

gtest的相关概念

TEST与TEST_F

  • TEST(test_case_name, test_name)

创建一个简单测试,它定义了一个测试函数,在这个函数里可以使用任何C++代码并使用提供的断言来进行检查。

  • TEST_F(test_fixture,test_name)

多个测试场景需要相同数据配置的情况,用 TEST_F 。TEST_F test fixture,测试夹具,测试套,承担了一个注册的功能。

断言

gtest中断言的宏可以分为两类:一类是ASSERT宏,另一类就是EXPECT宏了。

1、ASSERT_系列:如果当前点检测失败则退出当前函数

2、EXPECT_系列:如果当前点检测失败则继续往下执行

如果你对自动输出的错误信息不满意的话,也是可以通过operator<<能够在失败的时候打印日志,将一些自定义的信息输出。

比如:

ASSERT_TRUE(Abs(1) == 1) << "Abs(1)=1";

这样在判断不通过时会有后面打印"Abs(1)=1"。

ASSERT_系列:

bool值检查

1、 ASSERT_TRUE(参数),期待结果是true

2、ASSERT_FALSE(参数),期待结果是false

数值型数据检查

3、ASSERT_EQ(参数1,参数2),传入的是需要比较的两个数 equal

4、ASSERT_NE(参数1,参数2),not equal,不等于才返回true

5、ASSERT_LT(参数1,参数2),less than,小于才返回true

6、ASSERT_GT(参数1,参数2),greater than,大于才返回true

7、ASSERT_LE(参数1,参数2),less equal,小于等于才返回true

8、ASSERT_GE(参数1,参数2),greater equal,大于等于才返回true

字符串检查

9、ASSERT_STREQ(expected_str, actual_str),两个C风格的字符串相等才正确返回

10、ASSERT_STRNE(str1, str2),两个C风格的字符串不相等时才正确返回

11、ASSERT_STRCASEEQ(expected_str, actual_str)

12、ASSERT_STRCASENE(str1, str2)

EXPECT_系列,也是具有类似的宏结构的

事件机制

我理解的事件机制是,每个TestSuite事件是某个TestSuite下的所有测试可能需要有一些相同条件,那么在每个TestSuite前运行一遍的函数或者设置,会在这个TestSuite里的所有TestCase里都是一样的,然后每个TestCase运行前可能也有些需要预先运行的函数或者设置,这个需要在TestCase事件里设置。详细解释如下:

“事件” 本质是框架给你提供了一个机会, 让你能在这样的几个机会来执行你自己定制的代码, 来给测试用例准备/清理数据。gtest提供了多种事件机制,总结一下gtest的事件一共有三种:

1、TestSuite事件

需要写一个类,继承testing::Test,然后实现两个静态方法:SetUpTestCase 方法在第一个TestCase之前执行;TearDownTestCase方法在最后一个TestCase之后执行。

2、TestCase事件

是挂在每个案例执行前后的,需要实现的是SetUp方法和TearDown方法。SetUp方法在每个TestCase之前执行;TearDown方法在每个TestCase之后执行。

3、全局事件

要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。SetUp方法在所有案例执行前执行;TearDown方法在所有案例执行后执行。

例如全局事件可以按照下列方式来使用:

除了要继承testing::Environment类,还要定义一个该全局环境的一个对象并将该对象添加到全局环境测试中去。

TetsSuite事件和TestCase事件如下设置:

class TestMap:public testing::Test
{
public:
//TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后。
static void SetUpTestCase()
{
cout<<"SetUpTestCase"<<endl;
}
static void TearDownTestCase()
{
cout<<"TearDownTestCase"<<endl;
}
/*TestCase级别的,每个TestCase前后*/
virtual void SetUp() //TEST跑之前会执行SetUp
{
cout<<"SetUp"<<endl;
}
virtual void TearDown() //TEST跑完之后会执行TearDown
{
cout<<"TearDown"<<endl;
}
};
TEST_F(TestMap,Find) //此时使用的是TEST_F宏
{
map<int,int>::iterator it=test_map.find(1);
ASSERT_NE(it,test_map.end());
}
TEST_F(TestMap,Size)
{
ASSERT_EQ(test_map.size(),5);
}
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc, argv);//将命令行参数传递给gtest
return RUN_ALL_TESTS(); //RUN_ALL_TESTS()运行所有测试案例
}

即一般在一个头文件里引用gtest和待测试的代码头文件,然后写一个类继承testing::Test,实现里面的SetUp和

TearDown等函数,最后在测试cpp文件里使用TEST_F()来写单元测试,这时TestCase必须是刚才写的类名。

参考

gtest的介绍和使用-测试 (uml.org.cn)

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值