基于gtest进行单元测试
技术岗
测试(QA):保证代码没有bug
开发(RD):搬砖
运维(OP):
非技术岗
产品经理
注意公司和部门和岗位和工资
测试时需要先搞清楚需求和功能点
姓名_学校专业_岗位.pdf
1、 软件开发生命周期

2、 单元测试:
# include<cstdio> //实现一个求绝对值的函数 int Abs(int x){ return x>0?x:-x; } //针对Abs函数进行测试:单元测试必须为一个独立的函数 void TestAbs() { int result=Abs(10); if(result==10){ printf("ok\n"); } else { printf("NO\n"); } int result=Abs(-10); if(result==10){ if(result==10){ printf("ok 1\n"); } else { printf("NO 2\n"); } int result=Abs(0); if(result==0){ printf("ok 2\n"); } else { printf("NO 2\n"); } } int main(){ TestAbs(); return 0; }
3、 gtest:谷歌业界广泛使用的单元测试框架:gtest只能用于C++
gtest框架提供了gtest方式的单元测试
gtest中有一个默认的main函数,成功会编程原亮色
4、 步骤:
安装gtest
main.cc # include<gtest/gtest.h> # include<iostream> //TestCase相当于目录,Test相当于目录中的文件 //把一组有关联的Test组织到一个TestCase //TestCaseName和TestName都要结合实际的测试场景决定 //写一个test宏,进行单元测试的基本单位 Test(HelloTestCase,HelloTest) { //TEST宏里面可以写任何合法的C++代码 std::cout<<"hello"<<std::endl; }
Makefile:
hello:hello.cc g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib -lgtest -lgtest_main -lpthread .PHONY:clean clean: rm hello
5、学会使用第三方库
如何将第三方库引入项目中:
gtest中自定义main函数(添加初始化即可):
# include<gtest/gtest.h> # include<iostream> //TestCase相当于目录,Test相当于目录中的文件 //把一组有关联的Test组织到一个TestCase //TestCaseName和TestName都要结合实际的测试场景决定 //写一个test宏,进行单元测试的基本单位 Test(HelloTestCase,HelloTest) { //TEST宏里面可以写任何合法的C++代码 std::cout<<"hello"<<std::endl; } int main(int argc,char* argv[]) { return RUN_ALL_TESTS();//把返回值作为进程的终止码 }
此时makefile中去掉main
hello:hello.cc g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib -lgtest -lpthread .PHONY:clean clean: rm hello
例题二、对求绝对值进行简单的单元测试:
.cc
# include<cstdio> //实现一个求绝对值的函数 int Abs(int x){ return x>0?x:-x; } //以下代码为测试代码 TEST(TestAbs,Positive) { //用法类似于assert宏:断言失败会(1)使程序崩溃,(2)进程异常终止: //(3)会调用abort函数,导致进程异常终止。assert的使用方式比较单一 //ASSERT_TRUE宏的使用方法类似,但是更加灵活,失败时会导致:由原亮色变为红色 //通过框架会展示是否通过,通过的有哪些。 ASSERT_TRUE(Abs(10)==10); } TEST(TestAbs,Positive) { ASSERT_TRUE(Abs(-10)==10); } TEST(TestAbs,Positive) { ASSERT_TRUE(Abs(0)==0); }
Makefile:
main:main.cc g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib -lgtest -lgtest_main -lpthread .PHONY:clean clean: rm main
增加日志打印失败的值:ASSERT_TRUE(Abs(10)==10)<<”Abs(10)= “<<Abs(10);使用的运算符为移位运算符;断言失败会打印值。
ASSERT_TRUE:判断是否为真
ASSERT_EQ(值1,值2);判断两个值是否相等
ASSERT这样的致命断言,一旦失败,该TEST宏中的代码就不继续执行;EXPECT前缀的是非致命的断言,一旦失败,该TEST宏中的代码还能继续执行。ASSERT应用于:需求是实现一个测试文件的格式,用ASSERT来校验打开文件失败(文件打开失败,不能完成文件内容的验证);打开成功用EXPECT校验当前行格式是否正确。
哪个项目中应用到了这个知识点?
C_string :C语言风格的字符串以\0结尾的字符串
3、gtest中的事件机制:gtest在执行之前会有一个回调函数的时间,结束时又会有一定的时间用来销毁数据。
(1)库和框架的区别:
库:C++的标准库包含了标准模板库,STL是标准模板库。许多内容属于标准库而不是STL中的内容。库都是由程序员决定什么时机进行调用的。
框架:对于一些函数的调用时机不是由程序员自己来决定,而是由框架来决定。有些规则需要自己来定制,但是什么时候被调用不受程序员控制。
(2)事件:让事件得到进一步精简,使代码得到进一步重用。
例子:
# include<iostream> # include<gtest/gtest.h> # include<map> void MakeMap(std::map<int,int>& test_map){ test_map.insert(std::make_pair(1,1)); test_map.insert(std::make_pair(2,1)); test_map.insert(std::make_pair(3,1)); test_map.insert(std::make_pair(4,1)); test_map.insert(std::make_pair(5,1)); } //需求是,针对std::map一些典型接口进行单元测试 TEST(TestMap,size){ std::map<int,int>test_map; //插入数据:不允许插入key相同的数据 MakeMap(test_map); //进行测试 ASSERT_EQ(test_map.size(),5); } TEST(TestMap,find){ std::map<int,int>test_map; auto it=test_map.find(2); MakeMap(test_map); ASSERT_NE(it,test_map.end()); } TEST(TestMap,operator){ std::map<int,int>test_map; test_map[2]=100; MakeMap(test_map); ASSERT_EQ(test_map[2],100); }
太繁琐,我们把共用的代码放入宏中,要使用时,自动调用:TEST_F搭配事件机制使用,测试函数的第一个参数名字必须相同,才能构成事件机制自动调用。
# include<iostream> # include<gtest/gtest.h> # include<map> //通过虚函数的方式,将这样的自定制逻辑注册到框架中,框架自动决定什么时候执行。 class TestMap:public testing::Test{ public: void setup(){ test_map.insert(std::make_pair(1,1)); test_map.insert(std::make_pair(2,1)); test_map.insert(std::make_pair(3,1)); test_map.insert(std::make_pair(4,1)); test_map.insert(std::make_pair(5,1)); } void TearDown(){ test_map.clear(); } std::map<int,int> test_map; }; //需求是,针对std::map一些典型接口进行单元测试 TEST_F(TestMap,size){ std::map<int,int>test_map; //进行测试 ASSERT_EQ(test_map.size(),5); } TEST_F(TestMap,find){ std::map<int,int>test_map; auto it=test_map.find(2); ASSERT_NE(it,test_map.end()); } TEST_F(TestMap,operator){ std::map<int,int>test_map; test_map[2]=100; ASSERT_EQ(test_map[2],100); }
makefile:
main:main.cc g++ $^ -o $@ -I ~/third_part/include -L ~/third_part/lib\ -lgtest -lgtest_main -lpthread -std=c++11 .PHONY:clean clean: rm main
通过多态完成一个框架,向框架中插入数据:
浙公网安备 33010602011771号