gtest 是一个google开源的C++单元测试的框架,它是跨平台的,可应用在windows、linux、Mac等OS平台。https://github.com/google/googletest
编译gtest
下载gtest源码
[heql@ubuntu gtest]$ git clone https://github.com/google/googletest.git
编译
[heql@ubuntu gtest]$ cd googletest/googletest
[heql@ubuntu googletest]$ g++ -isystem $(pwd)/include -I$(pwd) -lpthread -c $(pwd)/src/gtest-all.cc
编译成功后,会在当前目录下生成一个gtest-all.o文件。
生成静态库
[heql@ubuntu googletest]$ ar -rv libgtest.a gtest-all.o
执行成功后,会在当前目录下生成一个libgtest.a的静态库,以后编译测试程序链接的时候,指定这个静态库和包含本目录下的include头文件。或者可以将这个静态库和头文件拷贝到环境变量中,如下,将libgtest.a拷贝到/usr/local/lib/,将include下的gtest目录拷贝到/usr/local/include/。
[heql@ubuntu googletest]$ cp libgtest.a /usr/local/lib/ 
[heql@ubuntu googletest]$ sudo cp include/gtest/ /usr/local/include/ -rf
简单测试
Factorial函数
在factorial.cc文件中,创建一个求阶乘的函数Factorial,代码如下:
1  | int Factorial(int n) {  | 
Factorial函数的测试用例
在factorial_unittest.cc文件中,创建测试Factorial函数的测试用例,代码如下:
1  | 
  | 
- TEST() 宏用来定义和命名测试函数,这些是不返回值的普通C++函数。
 - 在此函数中,可以使用任何有效的C++语句,使用各种Google Test断言来检查值。
 - 测试的结果由断言确定,如果测试中的任何断言失败(致命或非致命),或者如果测试崩溃,则整个测试失败。 否则,它成功。
 
TEST() 的第一个参数是测试用例的名称,第二个参数是测试用例中的测试名称。 这两个名称必须是有效的C ++标识符,并且它们不应包含下划线(_)。一个测试的全称包括了包含它的测试用例名称,及其独立的测试名称。不同测试用例中的独立测试可以有相同的测试名称。
gtest 通过测试用例对测试结果进行分组,因此逻辑相关的测试应该在同一测试用例中; 换句话说,它们的 TEST() 的第一个参数应该是相同的。 在上面的例子中,有两个测试,Zero和Positive,属于同一个测试用例FactorialTest。
EXPECT_EQ宏用来比较两个数字是否相等。
::testing::InitGoogleTest(&argc, argv),将命令行参数传递给gtest,进行一些初始化操作。如:--gtest_list_tests会列出所有的测试用例和测试名称。
[heql@ubuntu gtest]$ ./factorial_unittest --gtest_list_tests
FactorialTest.
  Zero
  Positive
可以执行./factorial_unittest --help查看命令行支持的参数。
RUN_ALL_TESTS()表示运行所有测试案例。
编译程序
[heql@ubuntu gtest]$ g++ factorial_unittest.cc factorial.cc -o factorial_unittest -lgtest -lpthread
运行上面的单元测试程序,输出如下:

FactorialTest测试用例,运行了两次测试,分别是Zero和Positive,测试的结果是正确的。注意: Zero和Positive的测试,执行的顺序是不确定的。
断言
gtest 断言是类似于函数调用的宏。您可以通过对其行为进行断言来测试类或函数。当断言失败时,gtest 会打印断言的源文件和行号位置以及失败消息。也可以提供自定义失败消息,该消息将附加到测试的信息中。
断言失败
把上面的FactorialTest测试用例的Positive测试改为:
1  | TEST(FactorialTest, Positive) {  | 
编译、运行程序,输出如下:

FactorialTest测试用例,运行了两次测试,分别是Zero和Positive,Zero测试成功,Positive测试失败:在factorial_unittest.cc文件的15行,Factorial(3)执行的结果应该是6,但是EXPECT_EQ的断言是7。
自定义断言失败消息
要提供自定义失败消息,只需使用<<运算符或一系列此类运算符将其流式传输到宏中即可。把上面的FactorialTest测试用例的Positive测试改为:
1  | TEST(FactorialTest, Positive) {  | 
编译、运行程序,输出如下:

可以看到输出的失败消息中,有自定义的消息Factorial(3) unequal to 7.。
布尔值检查
这些断言做基本的真/假条件测试。

gtest 中,断言的宏可以理解为分为两类,一类是ASSERT系列,一类是EXPECT系列。
- ASSERT_* 系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前用例)。
 - EXPECT_* 系列的断言,当检查点失败时,继续往下执行。
 
把上面的FactorialTest测试用例的Positive测试改为:
1  | TEST(FactorialTest, Positive) {  | 
编译、运行程序,输出如下:
    
FactorialTest测试用例,运行了两次测试,分别是Zero和Positive,Zero测试成功,Positive的Factorial(3)和Factorial(8)测试失败。
把上面的FactorialTest测试用例的Positive测试改为:
1  | TEST(FactorialTest, Positive) {  | 
编译、运行程序,输出如下:

FactorialTest测试用例,运行了两次测试,分别是Zero和Positive,Zero照常测试,测试成功,Positive的Factorial(3)测试失败后,Factorial(8)不在进行测试。
数值型数据检查
比较两个值的断言。

字符串检查
该组中的断言比较两个C字符串的值。 如果要比较两个字符串对象,请改用EXPECT_EQ,EXPECT_NE等。

ASSERT_EQ 在两个C字符串上使用,它会测试它们是否在同一个内存位置,而不是它们具有相同的值。因此,如果想比较C字符串(例如const char *)的值,请使用 ASSERT_STREQ 。要比较两个字符串对象,应该使用 ASSERT_EQ 。
要断言C字符串为NULL,请使用 ASSERT_STREQ(NULL,c_string),NULL指针和空字符串被认为是不同的。
如下代码,测试成功:
1  | 
  | 
浮点数检查

Test Fixtures(测试装饰类) 对多个测试使用相同的数据配置
如果你发现自己写了两个或更多的测试来操作类似的数据,你可以使用测试装饰类。它允许您为几个不同的测试重复使用相同的对象配置。
要创建测试装饰类,只需:
- 从
::testing::Test派生一个类。 使用protected:或public:开始它的主体,因为我们想从子类访问fixture成员。 - 在类中,声明你打算使用的任何对象。
 - 如果需要,可以编写默认构造函数或
SetUp函数来为每个测试准备对象。 - 如果需要,写一个析构函数或
TearDown函数来释放你在SetUp中分配的任何资源。 
当使用夹具时,使用 TEST_F() 而不是 TEST()
Foo类
在foo.h文件中,创建一个类Foo,代码如下:
1  | 
  | 
Foo类的测试用例
在foo_unittest.cc文件中,创建测试Foo类的测试用例,使用TEST() 宏进行测试,代码如下:
1  | 
  | 
在FooTest测试用例的测试DefaultConstructor和SetValue分别创建一个Foo的实例。可以使用TEST_F()来共享这个实例,指向创建一个实例即可,代码如下:
1  | 
  | 
在这里SetUp和TearDown函数并没有使用,如果需要可以使用SetUp函数对foo实例进行一些初始化,TearDown函数来释放foo的资源。
参数化测试
在设计测试用例时,经常需要考虑给被测函数传入不同的值的情况。我们之前的做法通常是写一个通用方法,然后编写在测试案例调用它。即使使用了通用方法,这样的工作也是有很多重复性的。
IsPrime函数
IsPrime函数是用来判断一个整数是否为素数,代码如下:
1  | bool IsPrime(int n) {  | 
IsPrime函数的测试用例
使用TEST()宏进行测试
1  | 
  | 
使用值参数化进行测试
- 添加一个类,继承
testing::TestWithParam<T>,其中T就是你需要参数化的参数类型,比如上面的例子,需要参数化一个int型的参数。 
1  | class IsPrimeTest : public ::testing::TestWithParam<int> {  | 
- 使用一个新的宏TEST_P,在 TEST_P 宏里,使用GetParam()获取当前的参数的具体值。
 
1  | TEST_P(IsPrimeTest, TestReturnTrue) {  | 
- 使用 INSTANTIATE_TEST_CASE_P 这宏来告诉gtest要测试的参数范围。
 
1  | INSTANTIATE_TEST_CASE_P(PrimeParamTest,  | 
第一个参数是测试用例的前缀,可以任意取。
第二个参数是测试案例的名称,需要和之前定义的参数化的类的名称相同,如:IsPrimeTest。
第三个参数是可以理解为参数生成器,上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数:  

编译、运行程序,输出如下:

可以看到参数-1,0的返回值不是true,而是false。其余的参数测试是正确的。
其他
gtest 还提供了一些高级的用法,可以参考:
https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md