一.gtest简介
是Google的一套用于编写C++测试的框架,可以运行在很多平台上(包括Linux、Mac OS X、Windows、Cygwin等等)。基于xUnit架构。支持很多好用的特性,包括自动识别测试、丰富的断言、断言自定义、死亡测试、非终止的失败、生成XML报告等等。
主要用于单元测试.
二.下载安装
git clone https://github.com/google/googletest.git
cd googletest
cmake ..
make
sudo cp libgtest*.a /usr/lib
sudo cp –a include/gtest /usr/include
然后在build/lib目录下会生成:libgmock.a libgmock_main.a libgtest.a libgtest_main.a
最后我们再 sudo make install
三.gtest之断言 :ASSERT宏 与 EXPECT宏
- ASSERT_系列:如果当前点检测失败则退出当前的函数
- EXPECT_系列:如果当前点检测失败则继续往下执行
- 如果我们对gtest自带的输出不满意的话,可以通过operator<<能够在失败的时候打印日志,将一些自定义的信息输出,如下:
ASSERT_TRUE(Abs(1) == 1);
ASSERT_TRUE(Abs(1) == 1) << "Abs(1)=1";
其中Abs()是自定义的来取绝对值的函数,与<<无关
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_系列,也是具有类似的宏结构的,如EXPECT_TRUE()
不同的是,及时遇到失败,还是会继续的向下执行.
使用实例:
1 #include<iostream>
2 using namespace std;
3 #include"gtest/gtest.h"
4
5 int Abs(int x)
6 {
7 return x > 0 ? x:(x*-1);
8 }
9
10 // TEST宏有两个参数,第一个是TestSuiteName,第二个是TestCaseName
11 TEST(IsAbsTest,HandlerTrueReturn)
12 {
13 ASSERT_EQ(Abs(1), 1); //ASSERT_TRUE期待结果是true,operator<<输出一些自定义的信息
14 ASSERT_TRUE(Abs(-1) == 1) << "Abs(-1)=1";
15 ASSERT_FALSE(Abs(-2) == -2); //期待结果是false
16 ASSERT_EQ(Abs(1),Abs(-1));
17 ASSERT_NE(Abs(-1),0);
18 ASSERT_LT(Abs(-1),2);
19 ASSERT_GT(Abs(-1),0);
20 ASSERT_LE(Abs(-1),2);
21 ASSERT_GE(Abs(-1),0);
22 }
23
24 int main(int argc,char **argv){
25 testing::InitGoogleTest(&argc,argv);
26 return RUN_ALL_TESTS();
27 }
//需要包括这个主函数,而且主函数的内容是固定不变的
编译
g++ main.cc -lpthread -lgtest
//需要链接线程和gtest库
如果我们不在源文件中写main()函数的话,编译的时候需要链接libgtest_main.a库
g++ main.cc -lgtest -lgtest_main -lpthread
结果:
Running main() from /home/txp/mydir/gtest/googletest/googletest/src/gtest_main.cc
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from IsAbsTest
[ RUN ] IsAbsTest.HandlerTrueReturn
[ OK ] IsAbsTest.HandlerTrueReturn (0 ms)
[----------] 1 test from IsAbsTest (0 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[ PASSED ] 1 test.
四.gtest之事件机制
事件:框架给我们提供的一个机会,让我们能在这几个机会来执行自己制定的代码买来给测试用例准备/清理数据.
全局事件
要实现全局事件,必须写一个类,继承testing::Environment类,实现里面的SetUp和TearDown方法。
- SetUp()方法在所有案例执行前执行
- TearDown()方法在所有案例执行后执行
还需要告诉gtest添加这个全局事件,我们需要在main函数中通过testing::AddGlobalTestEnvironment方法将事件挂进来,也就是说,我们可以写很多个这样的类,然后将他们的事件都挂上去。
TestSuite事件
我们需要写一个类,继承testing::Test,然后实现两个静态方法
- SetUpTestCase() 方法在第一个TestCase之前执行
- TearDownTestCase() 方法在最后一个TestCase之后执行
在编写测试案例时,我们需要使用TEST_F这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite。
TestCase事件
TestCase事件是挂在每个案例执行前后的,实现方式和上面的几乎一样,不过需要实现的是SetUp方法和TearDown方法:
- SetUp()方法在每个TestCase之前执行
- TearDown()方法在每个TestCase之后执行
#include<gtest/gtest.h>
#include<map>
#include<iostream>
using namespace std;
class Student{
public:
Student(){
age=0;
}
Student(int a){
age=a;
}
void print(){
cout<<"*********** "<<age<<" **********"<<endl;;
}
private:
int age;
};
class FooEnvironment : public testing::Environment{
public:
virtual void SetUp()
{
std::cout << "Foo FooEnvironment SetUP" << std::endl;
}
virtual void TearDown()
{
std::cout << "Foo FooEnvironment TearDown" << std::endl;
}
};
static Student *s;
//在第一个test之前,最后一个test之后调用SetUpTestCase()和TearDownTestCase()
class TestMap:public testing::Test
{
public:
static void SetUpTestCase()
{
cout<<"SetUpTestCase()"<<endl;
s=new Student(23);
}
static void TearDownTestCase()
{
delete s;
cout<<"TearDownTestCase()"<<endl;
}
void SetUp()
{
cout<<"SetUp() is running"<<endl;
}
void TearDown()
{
cout<<"TearDown()"<<endl;
}
};
TEST_F(TestMap, Test1)
{
// you can refer to s here
s->print();
}
int main(int argc, char** argv)
{
testing::AddGlobalTestEnvironment(new FooEnvironment);
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
五.gtest之死亡测试
”死亡”指的是程序的奔溃。通常在测试的过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序奔溃,这个时候我们就要检查程序是否按照预期的方式挂掉,这也就是所谓的”死亡测试”。
1>、ASSERT_DEATH(参数1,参数2)
程序挂了并且错误信息和参数2匹配,此时认为测试通过。如果参数2为空字符串,则只需要看程序挂没挂即可。
2>、ASSERT_EXIT(参数1,参数2,参数3)
语句停止并且错误信息和被提前给的信息匹配。
#include<gtest/gtest.h>
int func() //访问空指针
{
int *p=NULL;
*ptr = 100;
return 0;
}
TEST (FuncDeathTest,Nullptr)
{
ASSERT_DEATH(func()," ");
}
六.gtest之参数测试
当考虑多次要为被测函数传入不同的值的情况时,可以按下面的方式去测试。必须添加一个类,继承testing::TestWithParam。其中T就是你需要参数化的参数类型,如下面的案例是int型参数。(官方文档上的案例)
#include<gtest/gtest.h>
// Returns true iff n is a prime number.
bool IsPrime(int n)
{
// Trivial case 1: small numbers
if (n <= 1) return false;
// Trivial case 2: even numbers
if (n % 2 == 0) return n == 2;
// Now, we have that n is odd and n >= 3.
// Try to divide n by every odd number i, starting from 3
for (int i = 3; ; i += 2) {
// We only have to try i up to the squre root of n
if (i > n/i) break;
// Now, we have i <= n/i < n.
// If n is divisible by i, n is not prime.
if (n % i == 0) return false;
}
// n has no integer factor in the range (1, n), and thus is prime.
return true;
}
class IsPrimeParamTest : public::testing::TestWithParam<int>{};
TEST_P(IsPrimeParamTest, HandleTrueReturn)
{
int n = GetParam();
EXPECT_TRUE(IsPrime(n));
}
//被测函数须传入多个相关的值
INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));
int main(int argc, char **argv)
{
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
七.一个关于gtest的例子
#include<iostream>
using namespace std;
#include<gtest/gtest.h>
struct LinkNode
{
int _data;
LinkNode *_next;
LinkNode(const int& data)
:_data(data)
,_next(NULL)
{}
};
class Link
{
public:
Link()
:pHead(new LinkNode(0))
{}
void PushBack(const int& data)
{
if(pHead == NULL)
return ;
LinkNode *newNode=new LinkNode(data);
if(pHead->_next == NULL){ //第一次插入结点
pHead->_next=newNode;
}
else{ //找到最后一个结点直接尾插
LinkNode *cur=pHead->_next;
while(cur->_next){
cur=cur->_next;
}
cur->_next=newNode;
}
}
void PopBack()
{
if(pHead == NULL)
return ;
LinkNode *cur=pHead;
LinkNode *prev=NULL;
while(cur->_next)
{
prev=cur;
cur=cur->_next;
}
prev->_next=NULL;
delete cur;
}
LinkNode *FindNode(const int& data)
{
if(pHead == NULL)
return NULL;
LinkNode *cur=pHead->_next;
while(cur)
{
if(cur->_data == data)
return cur;
cur=cur->_next;
}
return NULL;
}
bool Delete(int data)
{
LinkNode *pos=FindNode(data);
if(pos == NULL)
return false;
LinkNode *cur=pHead->_next;
while(cur->_next != pos)
{
cur=cur->_next;
}
cur->_next=pos->_next;
delete pos;
return true;
}
void Destroy()
{
if(pHead == NULL)
return;
LinkNode *cur=pHead->_next;
while(cur)
{
LinkNode *del=cur;
cur=cur->_next;
delete del;
del=NULL;
}
delete pHead; //删除头结点
}
LinkNode *pHead;
};
class TestLink:public testing::Test
{
public:
virtual void SetUp()
{
cout<<"SetUp"<<endl;
for(int i=1;i<=5;i++){
link.PushBack(i);
}
}
virtual void TearDown()
{
cout<<"TearDown"<<endl;
link.Destroy();
}
Link link;
};
TEST_F(TestLink,PushBack)
{
ASSERT_FALSE(link.pHead == NULL);
link.PushBack(9);
LinkNode *res=link.FindNode(9);
ASSERT_FALSE(res == NULL);
}
TEST_F(TestLink,PopBack)
{
for(int i=1;i<=5;i++){
link.PopBack();
}
}
TEST_F(TestLink,FindNode)
{
ASSERT_TRUE(link.FindNode(3));
ASSERT_TRUE(link.FindNode(2));
ASSERT_TRUE(link.FindNode(4));
ASSERT_TRUE(link.FindNode(5));
ASSERT_TRUE(link.FindNode(1));
ASSERT_FALSE(link.FindNode(7));
}
TEST_F(TestLink,Delete)
{
ASSERT_FALSE(link.pHead == NULL);
ASSERT_TRUE(link.Delete(3) == true);
ASSERT_TRUE(link.Delete(9) == false);
}
int main(int argc,char *argv[])
{
testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}