Gtest
一、初始Gtest和框架搭建
1.4 Demo
intFoo(inta,intb){if(a==0||b==0){throw"don't do that";}intc=a%b;if(c==0)returnb;returnFoo(b,c);}#include<gtest/gtest.h>TEST(FooTest,HandleNoneZeroInput){EXPECT_EQ(2,Foo(4,10));EXPECT_EQ(6,Foo(30,18));}二、断言
2.1 前言
GTest中,断言的宏可以理解为分为两类,一类是ASSERT系列,一类是EXPECT系列。一个直观的解释就是:
ASSERT_*系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前testcase)EXPECT_*系列的断言,当检查点失败时,继续往下执行
2.2 自定义提示信息实例
未使用自定义提示
for(inti=0;i<x.size();++i){EXPECT_EQ(x[i],y[i]);}#结果:无法看出出错时到底是循环到哪里了/* g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i] Actual: 4 Expected: x[i] Which is: 3 */使用<<操作符自定义提示输出
for(inti=0;i<x.size();++i){EXPECT_EQ(x[i],y[i])<<"Vectors x and y differ at index "<<i;}/* g:\myproject\c++\gtestdemo\gtestdemo\gtestdemo.cpp(25): error: Value of: y[i] Actual: 4 Expected: x[i] Which is: 3 Vectors x and y differ at index 2 */2.3 bool值类型检查
| ASSERT | EXPECT |
|---|---|
| 检查失败退出函数 | 检查失败继续往下执行 |
| ASSERT_TRUE(condition); | EXPECT_TRUE(condition); |
| ASSERT_FALSE(condition); | EXPECT_FALSE(condition); |
2.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 |
2.5 字符串检查
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_STREQ(expected_str,actual_str); | EXPECT_STREQ(expected_str,actual_str); | same content |
| ASSERT_STRNE(str1, str2); | EXPECT_STRNE(str1, str2); | the two C strings have different content |
| ASSERT_STRCASEEQ(expected_str, actual_str); | EXPECT_STRCASEEQ(expected_str, actual_str); | same content, ignoring case |
| ASSERT_STRCASENE(str1,str2); | EXPECT_STRCASENE(str1,str2); | different content, ignoring case |
2.6 显示返回成功或失败
- 直接返回成功
SUCCEED() - 返回失败
| Fatal assertion | Nonfatal assertion |
|---|---|
| FAIL(); | ADD_FAILURE(); |
TEST(ExplicitTest,Demo){ADD_FAILURE()<<"Sorry";// None Fatal Asserton,继续往下执行。//FAIL() << "Sorry!"; // Fatal Assertion,不继续往下执行该案例。SUCCEED();}2.7 异常检查
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_THROW(statement,exception_type); | EXPECT_THROW(statement,exception_type); | statement throws an exception of the given type |
| ASSERT_ANY_THROW(statement); | EXPECT_ANY_THROW(statement); | statement throws an exception of any type |
| ASSERT_NO_THROW(statement); | EXPECT_NO_THROW(statement); | statement doesn’t throw any exception |
intFoo(inta,intb){if(a==0||b==0){throw"don't do that";}intc=a%b;if(c==0)returnb;returnFoo(b,c);}TEST(FooTest,HandleZeroInput){EXPECT_ANY_THROW(Foo(10,0));EXPECT_THROW(Foo(0,5),char*);}2.8 Predicate Assertions
是对ASSERT_TRUE和EXPECT_TRUE的改进,使其不仅判断TRUE和FALSE,而且能显示其他信息,比如输入的参数内容。
如下分别是一个输入参数和两个输入参数的使用。
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_PRED1(pred1, val1); | EXPECT_PRED1(pred1, val1); | pred1(val1) returns true |
| ASSERT_PRED2(pred2, val1, val2); | EXPECT_PRED2(pred2, val1, val2); | pred2(val1, val2) returns true |
boolMutuallyPrime(intm,intn){returnFoo(m,n)>1;}TEST(PredicateAssertionTest,Demo){intm=5,n=6;EXPECT_PRED2(MutuallyPrime,m,n);}/* 当失败时,返回错误信息: error: MutuallyPrime(m, n) evaluates to false, where m evaluates to 5 n evaluates to 6 */2.9 浮点型检查
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_FLOAT_EQ(expected, actual); | EXPECT_FLOAT_EQ(expected, actual); | the two float values are almost equal |
| ASSERT_DOUBLE_EQ(expected, actual); | EXPECT_DOUBLE_EQ(expected, actual); | the two double values are almost equal |
2.9.1 相近数比较
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_NEAR(val1, val2, abs_error); | EXPECT_NEAR(val1, val2, abs_error); | the difference between val1 and val2 doesn’t exceed the given absolute error |
2.10 Windows HRESULT 检查
| Fatal assertion | Nonfatal assertion | Verifies |
|---|---|---|
| ASSERT_HRESULT_SUCCEEDED(expression); | EXPECT_HRESULT_SUCCEEDED(expression); | expression is a success HRESULT |
| ASSERT_HRESULT_FAILED(expression); | EXPECT_HRESULT_FAILED(expression); | expression is a failure HRESULT |
CComPtr shell;ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application"));CComVariant empty;ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url),empty,empty,empty,empty));2.11 类型检查
template<typenameT>classFooType{public:voidBar(){testing::StaticAssertTypeEq<int,T>();}};TEST(TypeAssertionTest,Demo){FooType<bool>fooType;fooType.Bar();}三、事件机制
3.1 前言
事件:在案例执行之前或之后做的一些操作。
共有三个粒度:
- 全局级别的。在所有案例的第一个执行前,和所有案例最后一个执行后。
- TestSuite级别的。在某一批案例中的第一个案例前,最后一个案例执行后。
- TsetCase级别的。每个TestCase前后。
特别需要注意区分粒度。
| 粒度 | 解释 |
|---|---|
| 全局 | 有50个testcase,SetUp在第1个testcase前执行,TearDown在第50个testcase后执行。 |
| TestSuite | 有50个testcase,其中针对这一个TestSuite的testcase是第20-30个,则此SetUpTestCase在第20个testcase前执行,TearDownTestCase在第30个testcase后执行。 |
| TestCase | SetUp使用此事件的每一个testcase前执行一次,TearDown在 使用此事件的每一个testcase后执行一次 |
3.2 全局级别
要实现全局级别的事件:
- 写一个类,继承
testing::Environment类,实现SetUp和TearDown - 在main函数中通过
testing::AddGlobalTestEnvironment把事件挂进来。
我们有50个testcase,SetUp在第1个testcase前执行,TearDown在第50个testcase后执行。
3.2.1 实现SetUP和TearDown
classFooEnvironment:publictesting::Environment{public:virtualvoidSetUp(){std::cout<<"Foo FooEnvironment SetUP"<<std::endl;}virtualvoidTearDown(){std::cout<<"Foo FooEnvironment TearDown"<<std::endl;}public:intdwRet;};3.2.2 挂载事件
int_tmain(intargc,_TCHAR*argv[]){testing::AddGlobalTestEnvironment(newFooEnvironment);testing::InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();}3.3 TestSuite事件
要实现TestSuite级别(某一批)的事件:
- 写一个类,继承
testing::Test类,实现静态方法SetUpTestCase和TearDownTestCase
我们有50个testcase,其中针对这一个TestSuite的testcase是第20-30个,则此SetUpTestCase在第20个testcase前执行,TearDownTestCase在第30个testcase后执行。
classFooTest:publictesting::Test{protected:staticvoidSetUpTestCase(){shared_resource_=new;}staticvoidTearDownTestCase(){deleteshared_resource_;shared_resource_=NULL;}staticT*shared_resource_;};在编写测试案例时,我们需要使用TEST_F这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite
TEST_F(FooTest,Given_When_Then){// you can refer to shared_resource here}TEST_F(FooTest,Given_When_Then){// you can refer to shared_resource here}3.4 TestCase事件
TestCase是在每个testcase执行前执行,也在每个testcase执行后执行。
classTEST_Command_Parse:publictesting::Test{public:CoreInfo*coreInfo;2.在main函数中通过t`esting::AddGlobalTestEnvironment`把事件挂进来。public:virtualvoidSetUp(){coreInfo=InitCoreNetwork();}virtualvoidTearDown(){CloseCoreNetwork(coreInfo);}};#include"gtest/gtest.h"GTEST_API_intmain(intargc,char**argv){testing::InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();}四、死亡测试
//暂缺
五、运行参数
5.1 命令行参数
gtest同样能够处理命令行参数,因为在main函数中我们把命令行参数交给了gtest。
int_tmain(intargc,_TCHAR*argv[]){testing::InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();}由gtest来搞定命令行问题,这样就可以使用命令行参数来使得gtest达到我们想要的效果,比如:
| 参数 | 作用 |
|---|---|
| –gtest_list_tests | 使用这个参数时,将不会执行里面的测试案例,而是输出一个案例的列表。 |
5.2 代码中指定FLAG
gtest提供了不止一种设置运行参数的方法:
- 命令行参数
- 代码中指定FLAG
- 系统环境变量
- 优先级为:
命令行参数 > 代码中指定FLAG > 系统环境变量 - 代码指定FLAG:
testing::GTEST_FLAG(output) = "xml:"
代码中指定FLAG,可以使用testing::GTEST_FLAG这个宏来设置,推荐将这句放在InitGoogleTest之前,这样就可以使得对于同样的参数,命令行参数优先级高于代码指定。
int_tmain(intargc,_TCHAR*argv[]){testing::GTEST_FLAG(output)="xml:";testing::InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();}5.3 列表
| 命令行参数 | 说明 |
|---|---|
| –gtest_list_tests | |
| –gtest_filter | |
| –gtest_also_run_disabled_tests | |
| –gtest_repeat=[COUNT] | |
| –gtest_color=(yes\no\auto) | |
| –gtest_print_time | |
| –gtest_output=xml[:DIRECTORY_PATH|:FILE_PATH] | |
| 异常处理 | 异常处理 |
| –gtest_break_on_failure | 调试模式下,当案例失败时停止,方便调试 |
| –gtest_throw_on_failure | |
| –gtest_catch_exceptions |
5.4 总结
本篇主要介绍了gtest案例执行时提供的一些参数的使用方法,这些参数都非常有用。在实际编写gtest测试案例时肯定会需要用到的时候。至少我现在比较常用的就是:
- –gtest_filter
//运行所有测试./my_test--gtest_filter=*//只运行 MathOperations 套件下的所有测试./my_test--gtest_filter=MathOperations.* - –gtest_output=xml[:DIRECTORY_PATH|:FILE_PATH]
- –gtest_catch_exceptions
最后再总结一下我使用过程中遇到的几个问题: - 同时使用–gtest_filter和–gtest_output=xml:时,在xml测试报告中能否只包含过滤后的测试案例的信息。
- 有时,我在代码中设置 testing::GTEST_FLAG(catch_exceptions) = 1和我在命令行中使用–gtest_catch_exceptions结果稍有不同,在代码中设置FLAG方式有时候捕捉不了某些异常,但是通过命令行参数的方式一般都不会有问题。这是我曾经遇到过的一个问题,最后我的处理办法是既在代码中设置FLAG,又在命令行参数中传入–gtest_catch_exceptions。不知道是gtest在catch_exceptions方面不够稳定,还是我自己测试案例的问题。