1.下载与安装
gtest是google编写的一个c++测试框架,具有轻便、灵活、跨平台等特点。其下载地址:http://code.google.com/p/googletest/downloads/list,现在最新的版本为gtest-1.6.0.zip。
下载完成后,在终端对gtest进行解压安装:
unzip gtest-1.6.0.zip
cd gtest-1.6.0
g++ -I./include -I./ -c ./src/gtest-all.cc
ar -rv libgtest.a gtest-all.o
运行上述命令后,确认生成了库文件libgtest.a,这个库是后续测试程序需要链接的库。
2. 测试实例
2.1 配置项目环境
首先把/gtest-1.6.0/include/gtest下的头文件引入eclipse工程中,其次把
安装过程中生成的库文件引入,同时把pthread库也引入到工程中。
2.2 测试代码
头文件CMax.h:
#ifndefCMAX_H_
#defineCMAX_H_
intmax(int a, int b)
{
returna > b ? a : b;
}
#endif
测试文件CMax_test.cpp:
#include"gtest/gtest.h"
#include"CMax.h"
TEST(CMAX,max)
{
EXPECT_EQ(2,max(2,-1));
EXPECT_EQ(3,max(2,3));
}
intmain(int argc, char** argv)
{
::testing::InitGoogleTest(&argc,argv);
returnRUN_ALL_TESTS();
}
编译CMax_test.cpp,其运行结果如下:
[==========] Running 1 test from 1 testcase.
[----------]Global test environment set-up.
[----------]1 test from CMAX
[RUN ] CMAX.max
[ OK ] CMAX.max (0 ms)
[----------]1 test from CMAX (0 ms total)
[----------]Global test environment tear-down
[==========]1 test from 1 test case ran. (0 ms total)
[ PASSED ] 1 test.
::testing::InitGoogleTest(&argc,argv): gtest的测试案例允许接收一系列的命令行参数,因此,我们将命令行参数传递给gtest,进行一些初始化操作。
RUN_ALL_TESTS(): 运行所有测试。
在测试用例中我们使用了TEST这个宏,它有两个参数,官方的对这两个参数的解释为:[TestCaseName,TestName]。
对检查点的检查,我们上面使用到了EXPECT_EQ这个宏,这个宏用来比较两个数字是否相等。Google还包装了一系列EXPECT_*和ASSERT_*的宏,下文将对gtest的断言等进行详细的概括。
3.gtest断言
3.1 断言简介
gtest中,断言的宏可以理解为分为两类,一类是ASSERT系列,一类是EXPECT系列。一个直观的解释就是:
(1) ASSERT_* 系列的断言,当检查点失败时,退出当前函数。
(2) EXPECT_* 系列的断言,当检查点失败时,继续往下执行。
3.2 示例
//int型比较,预期值:3,实际值:Add(1,2)
EXPECT_EQ(3 , Add (1,2) )
如果把预期值改成4,则会出现如下测试结果:
../src/CMax_Test.cpp:12:Failure
Valueof: add(1,2)
Actual: 3
Expected: 4
如果对自动输出的出错信息不满意的话,还可以通过操作符 << 将一些自定义的信息输出,通常,这对于调试或是对一些检查点的补充说明来说是很有用的,例子如下:
如果不使用 << 操作符自定义输出的话:
for(int i = 0 ; i < x.size() ; i++)
{
EXPECT_EQ(x[i],y[i]);
}
测试人员不会知道是何时出错的,出错时 i 的值是多少。
而如果使用 << 操作符将一些重要信息输出的话:
for (int i = 0; i < x.size(); ++i)
{
EXPECT_EQ(x[i],y[i])<<"Vectors x and y differ at index "<< i;
}
从输出结果中就可以定位到在 i = 多少时出现了错误。这样的输出结果看起来更加容易理解。
3.3 布尔值检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_TRUE(condition) | EXPECT_TRUE(condition) | condition is true |
ASSERT_FALSE(condition) | EXPECT_FALSE(condition) | condition is false |
3.4 数值类型的检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_EQ(expected,actual) | EXPECT_EQ(expected,actual) | expected==actual |
ASSERT_NE(val1,val2) | EXPECT_NE(val1, val2) | val1!= val2 |
ASSERT_LT(val1,val2) | EXPECT_LT(val1, val2) | val1 < val2 |
ASSERT_LE(val1,val2) | EXPECT_LE(val1, val2) | val1 <= val2 |
ASSERT_GT(val1,val2) | EXPECT_GT(val1, val2) | val1 >val2 |
ASSERT_GE(val1,val2) | EXPECT_GE(val1, val2) | val1 >=val2 |
3.5字符串类型的检查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_STREQ(expected,actual) | EXPECT_STREQ(expected,actual) | the two C strings have the same content |
ASSERT_STRNE(str1, str2) | EXPECT_STRNE(str1, str2) | the two C strings have different content |
ASSERT_STRCASEEQ(expected,actual) | EXPECT_STRCASEEQ(expected,actual) | the two C strings have the same content, ignoring case |
ASSERT_STRCASENE(str1, str2) | EXPECT_STRCASENE(str1, str2) | the two C strings have different content, ignoring case |
4.gtest参数化
4.1值参数化测试
在设计测试案例时,经常需要考虑给被测函数传入不同的值的情况。我们之前的做法通常是写一个通用方法,然后编写在测试案例调用它。即使使用了通用方法,这样的工作也是有很多重复性的。Google考虑到了这个问题,并且提供了一个灵活的参数化测试的方案。
被测试的函数:
boolIsPrime(int n)
{
if (n <= 1) return false;
if (n % 2 == 0) return n == 2;
for (int i = 3; ; i += 2) {
if (i > n/i) break;
if (n % i == 0) return false;
}
return true;
}
假如要编写判断结果为true的测试案例,需要传入一系列数值让函数IsPrime()去判断是否为true(其实即使传入再多值也无法确保函数正确),可以这样编写如下的测试案例:
TEST(IsPrimeTest,HandleTrueReturn)
{
EXPECT_TRUE(IsPrime(3));
EXPECT_TRUE(IsPrime(5));
EXPECT_TRUE(IsPrime(11));
EXPECT_TRUE(IsPrime(23));
EXPECT_TRUE(IsPrime(17));
}
我们注意到,在这个测试案例中,我至少复制粘贴了4次,随着测试次数的增多无疑会变得很繁琐。而事实上,gtest可以是这样解决问题的。
(1)告诉gtest你的参数类型是什么。可以添加一个类:testing::TestWithParam<T>,其中T就是你需要参数化的参数类型,比如上面的例子,我们需要参数化一个int型的参数。
classIsPrimeParamTest :public::testing::TestWithParam<int>
{
};
(2)告诉gtest你拿到参数的值后,具体做些什么样的测试。这里,我们使用一个新的:TEST_P,关于这个"P"的含义,可以理解为"parameterized"。在TEST_P宏里,使GetParam()获取当前的参数的具体值。
TEST_P(IsPrimeParamTest,HandleTrueReturn)
{
int n = GetParam();
EXPECT_TRUE(IsPrime(n));
}
(3)告诉gtest你想要测试的参数范围是什么。可以使用INSTANTIATE_TEST_CASE_P这宏来告诉gtest你要测试的参数范围: INSTANTIATE_TEST_CASE_P(TrueReturn,IsPrimeParamTest,testing::Values(3,5,11,23,17));
第一个参数是测试案例的前缀,可以任意取。
第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同:IsPrimeParamTest
第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:
Range(begin, end[, step]) | 范围在begin--end之间,步长为step,不包括end |
Values(v1, v2, ..., Vn) | v1,v2到Vn的值 |
ValuesIn(container) and ValuesIn(begin,end) | 从一个C类型的数组或是STL容器,或是迭代器中取值 |
Bool() | 取false 和 true 两个值 |
Combine(g1, g2, ..., Gn) | 它将g1,g2,...Gn进行排列组合,g1,g2,...Gn本身是一个参数生成器,每次分别从g1,g2,...Gn中各取出一个值,组合成一个元组(Tuple)作为一个参数 |
gtest值参数化完整案例:
parameter.h:
bool IsPrime(int n)
{
if(n <= 1)
returnfalse;
if(n % 2 == 0)
returnn == 2;
for(int i = 3;; i += 2)
{
if(i > n / i)
break;
if(n % i == 0)
returnfalse;
}
returntrue;
}
class IsPrimeParamTest : public::testing::TestWithParam<int>
{
};
MainTest.cpp:
TEST_P(IsPrimeParamTest, TrueReturn)
{
int n = GetParam();
EXPECT_TRUE(IsPrime(n));
}
INSTANTIATE_TEST_CASE_P(TrueReturn,IsPrimeParamTest, testing::Values(3,5,11,13));
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc,argv);
returnRUN_ALL_TESTS();
}
4.2 gest类型参数化测试
除了值参数化测试外,gtest还提供了类型参数化测试,以应付各种不同类型数据时的方案。
类型参数化测试步骤:
(1)首先定义一个模版类,继承testing::Test。
template<typename T> class FooTest : public testing::Test
{
public:
typedef std::list<T>List;
T value_;
};
(2)接着定义需要测试的具体数据类型,比如下面定义了char,int和unsigned int:
typedef testing::Types<char,int, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);
(3) 使用宏TYPED_TEST来完成测试案例。在声明模版的数据类型时,使用TypeParam 。
TYPED_TEST(FooTest,DoesBlah)
{
TypeParamn = this->value_;
typenameTestFixture::List values;
values.push_back(n);
}
5.gtest死亡测试
这里的死亡指的的是程序的崩溃。通常在测试过程中,我们需要考虑各种各样的输入,有的输入可能直接导致程序崩溃,这时我们就需要检查程序是否按照预期的方式挂掉,这也就是所谓的死亡测试。gtest的死亡测试能做到在一个安全的环境下执行崩溃的测试案例,同时又对崩溃结果进行验证。
gtest的死亡测试所用的宏如下表所示:
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_DEATH(statement, regex`) | EXPECT_DEATH(statement, regex`) | statement crashes with the given error |
ASSERT_EXIT(statement, predicate, regex`) | EXPECT_EXIT(statement, predicate, regex`) | statement exits with the given error and its exit code matchespredicate |
5.1_DEATH(statement, regex`)
(1) statement是被测试的代码语句。
(2) regex是一个正则表达式,用来匹配异常时在stderr中输出的内容。
例子:
void Foo()
{
int *pInt = 0;
*pInt = 42 ;
}
TEST(FooDeathTest, Demo)
{
EXPECT_DEATH(Foo(), "");
}
注意:编写死亡测试案例时,TEST的第一个参数,即testcase_name,请使用DeathTest后缀。原因是gtest会优先运行死亡测试案例,应该是为线程安全考虑。
5.2 *_EXIT(statement, predicate,regex`)
(1)statement是被测试的代码语句。
(2)predicate 在这里必须是一个委托,接收int型参数,并返回bool。只有当返回值为true时,死亡测试案例才算通过。
(3)regex是一个正则表达式,用来匹配异常时在stderr中输出的内容。
要说明的是,*_DEATH其实是对*_EXIT进行的一次包装。