GTest使用手册.docx

上传人:b****5 文档编号:8354694 上传时间:2023-01-30 格式:DOCX 页数:29 大小:33.82KB
下载 相关 举报
GTest使用手册.docx_第1页
第1页 / 共29页
GTest使用手册.docx_第2页
第2页 / 共29页
GTest使用手册.docx_第3页
第3页 / 共29页
GTest使用手册.docx_第4页
第4页 / 共29页
GTest使用手册.docx_第5页
第5页 / 共29页
点击查看更多>>
下载资源
资源描述

GTest使用手册.docx

《GTest使用手册.docx》由会员分享,可在线阅读,更多相关《GTest使用手册.docx(29页珍藏版)》请在冰豆网上搜索。

GTest使用手册.docx

GTest使用手册

玩转Google开源C++单元测试框架GoogleTest系列(gtest)(总)

前段时间学习和了解了下Google的开源C++单元测试框架GoogleTest,简称gtest,非常的不错。

我们原来使用的是自己实现的一套单元测试框架,在使用过程中,发现越来越多使用不便之处,而这样不便之处,gtest恰恰很好的解决了。

其实gtest本身的实现并不复杂,我们完全可以模仿gtest,不断的完善我们的测试框架,但最后我们还是决定使用gtest取代掉原来的自己的测试框架,原因是:

1.不断完善我们的测试框架之后就会发觉相当于把gtest重新做了一遍,虽然轮子造的很爽,但是不是必要的。

2.使用gtest可以免去维护测试框架的麻烦,让我们有更多精力投入到案例设计上。

提高了非常完善的功能,并且简单易用,极大的提高了编写测试案例的效率。

如果想对gtest内部探个究竟,就把它的代码下载下来研究吧,这就是开源的好处,哈!

官方已经有如此完备的文档了,为什么我还要写呢?

一方面是自己记记笔记,好记性不如烂笔头,以后自己想查查一些用法也可以直接在这里查到,一方面是对于不想去看一大堆英文文档的朋友,在我这里可以快速的找到gtest相关的内容。

一、初识gtest

1、前言

本篇将介绍一些gtest的基本使用,包括下载,安装,编译,建立我们第一个测试Demo工程,以及编写一个最简单的测试案例。

2、下载

3、如果不记得网址,直接在google里搜gtest,第一个就是。

目前gtest的最新版本为编译

下载解压后,里面有个msvc目录:

使用VS的同学可以直接打开msvc里面的工程文件,如果你在使用的是VS2005或是VS2008,打开后会提示你升级,升完级后,我们直接编译里面的“gtest”工程,可以直接编过的。

这里要提醒一下的是,如果你升级为VS2008的工程,那么你的测试Demo最好也是VS2008工程,不然你会发现很郁闷,你的Demo怎么也编不过,我也曾折腾了好久,当时我升级为了VS2008工程,结果我使用VS2005工程建Demo,死活编不过。

(这里有人误解了,并不是说只能在VS2008中编译,在VS2005中同样可以。

如果要编译VS2005版本,最好保证gtest和你的测试工程都使用VS2005工程。

编译之后,在msvc里面的Debug或是Release目录里看到编译出来的或是文件。

4、第一个Demo

下面我们开始建立我们的第一个Demo了,假如之前使用的VS2008编译的gtest,那么,我们在VS2008中,新建一个Win32ConsoleApplication。

接着就是设置工程属性,总结如下:

1.设置gtest头文件路径

2.设置路径

Library设置

如果是Release版本,RuntimeLibrary设为/MT。

当然,其实你也可以选择动态链接(/MD),前提是你之前编译的gtest也使用了同样是/MD选项。

工程设置后了后,我们来编写一个最简单测试案例试试,我们先来写一个被测试函数:

intFoo(inta,intb)

{if(a==0||b==0)

{throw"don'tdothat";

}intc=a%b;if(c==0)returnb;returnFoo(b,c);

}

没错,上面的函数是用来求最大公约数的。

下面我们就来编写一个简单的测试案例。

#include

TEST(FooTest,HandleNoneZeroInput)

{

EXPECT_EQ(2,Foo(4,10));

EXPECT_EQ(6,Foo(30,18));

}

上面可以看到,编写一个测试案例是多么的简单。

我们使用了TEST这个宏,它有两个参数,官方的对这两个参数的解释为:

[TestCaseName,TestName],而我对这两个参数的定义是:

[TestSuiteName,TestCaseName],在下一篇我们再来看为什么这样定义。

对检查点的检查,我们上面使用到了EXPECT_EQ这个宏,这个宏用来比较两个数字是否相等。

Google还包装了一系列EXPECT_*和ASSERT_*的宏,而EXPECT系列和ASSERT系列的区别是:

1.EXPECT_*失败时,案例继续往下执行。

2.ASSERT_*失败时,直接在当前函数中返回,当前函数中ASSERT_*后面的语句将不会执行。

在下一篇,我们再来具体讨论这些断言宏。

为了让我们的案例运行起来,我们还需要在main函数中添加如下代码:

int_tmain(intargc,_TCHAR*argv[])

{

testing:

:

InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();

}

“testing:

:

InitGoogleTest(&argc,argv);”:

gtest的测试案例允许接收一系列的命令行参数,因此,我们将命令行参数传递给gtest,进行一些初始化操作。

gtest的命令行参数非常丰富,在后面我们也会详细了解到。

“RUN_ALL_TESTS()”:

运行所有测试案例

OK,一切就绪了,我们直接运行案例试试(一片绿色,非常爽):

5、总结

本篇内容确实是非常的初级,目的是让从来没有接触过gtest的同学了解gtest最基本的使用。

gtest还有很多更高级的使用方法,我们将会在后面讨论。

总结本篇的内容的话:

1.使用VS编译文件

2.设置测试工程的属性(头文件,lib文件,/MT参数(和编译gtest时使用一样的参数就行了))

3.使用TEST宏开始一个测试案例,使用EXPECT_*,ASSER_*系列设置检查点。

4.在Main函数中初始化环境,再使用RUN_ALL_TEST()宏运行测试案例。

优点:

1.我们的测试案例本身就是一个exe工程,编译之后可以直接运行,非常的方便。

2.编写测试案例变的非常简单(使用一些简单的宏如TEST),让我们将更多精力花在案例的设计和编写上。

3.提供了强大丰富的断言的宏,用于对各种不同检查点的检查。

4.提高了丰富的命令行参数对案例运行进行一系列的设置。

二、断言

1、前言

这篇文章主要总结gtest中的所有断言相关的宏。

gtest中,断言的宏可以理解为分为两类,一类是ASSERT系列,一类是EXPECT系列。

一个直观的解释就是:

1.ASSERT_*系列的断言,当检查点失败时,退出当前函数(注意:

并非退出当前案例)。

2.EXPECT_*系列的断言,当检查点失败时,继续往下执行。

2、示例

3、

4、

5、

6、

.

...

...

Google人说了,他们只提供<=5个参数的,如果需要测试更多的参数,直接告诉他们。

下面看看这个东西怎么用。

boolMutuallyPrime(intm,intn)

{returnFoo(m,n)>1;

}

TEST(PredicateAssertionTest,Demo)

{intm=5,n=6;

EXPECT_PRED2(MutuallyPrime,m,n);

}

当失败时,返回错误信息:

error:

MutuallyPrime(m,n)evaluatestofalse,where

mevaluatesto5

nevaluatesto6

如果对这样的输出不满意的话,还可以自定义输出格式,通过如下:

Fatalassertion

Nonfatalassertion

Verifies

ASSERT_PRED_FORMAT1(pred_format1,val1);`

EXPECT_PRED_FORMAT1(pred_format1,val1);

pred_format1(val1)issuccessful

ASSERT_PRED_FORMAT2(pred_format2,val1,val2);

EXPECT_PRED_FORMAT2(pred_format2,val1,val2);

pred_format2(val1,val2)issuccessful

...

...

用法示例:

testing:

:

AssertionResultAssertFoo(constchar*m_expr,constchar*n_expr,constchar*k_expr,intm,intn,intk){if(Foo(m,n)==k)returntesting:

:

AssertionSuccess();

testing:

:

Messagemsg;

msg<

"<

"<

:

AssertionFailure(msg);

}

TEST(AssertFooTest,HandleFail)

{

EXPECT_PRED_FORMAT3(AssertFoo,3,6,2);

}

失败时,输出信息:

error:

3和6的最大公约数应该是:

3而不是:

2

是不是更温馨呢,呵呵。

7、浮点型检查

Fatalassertion

Nonfatalassertion

Verifies

ASSERT_FLOAT_EQ(expected,actual);

EXPECT_FLOAT_EQ(expected,actual);

thetwofloatvaluesarealmostequal

ASSERT_DOUBLE_EQ(expected,actual);

EXPECT_DOUBLE_EQ(expected,actual);

thetwodoublevaluesarealmostequal

对相近的两个数比较:

Fatalassertion

Nonfatalassertion

Verifies

ASSERT_NEAR(val1,val2,abs_error);

EXPECT_NEAR(val1,val2,abs_error);

thedifferencebetweenval1andval2doesn'texceedthegivenabsoluteerror

同时,还可以使用:

EXPECT_PRED_FORMAT2(testing:

:

FloatLE,val1,val2);

EXPECT_PRED_FORMAT2(testing:

:

DoubleLE,val1,val2);

8、WindowsHRESULTassertions

Fatalassertion

Nonfatalassertion

Verifies

ASSERT_HRESULT_SUCCEEDED(expression);

EXPECT_HRESULT_SUCCEEDED(expression);

expressionisasuccessHRESULT

ASSERT_HRESULT_FAILED(expression);

EXPECT_HRESULT_FAILED(expression);

expressionisafailureHRESULT

例如:

CComPtrshell;

ASSERT_HRESULT_SUCCEEDED(L""));

CComVariantempty;

ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url),empty,empty,empty,empty));

9、类型检查

类型检查失败时,直接导致代码编不过,难得用处就在这?

看下面的例子:

templateclassFooType{public:

voidBar(){testing:

:

StaticAssertTypeEq();}

};

TEST(TypeAssertionTest,Demo)

{

FooTypefooType;

();

}

10、总结

本篇将常用的断言都介绍了一遍,内容比较多,有些还是很有用的。

要真的到写案例的时候,也行只是一两种是最常用的,现在时知道有这么多种选择,以后才方便查询。

三、事件机制

1、前言

gtest提供了多种事件机制,非常方便我们在案例之前或之后做一些操作。

总结一下gtest的事件一共有3种:

1.全局的,所有案例执行前后。

2.TestSuite级别的,在某一批案例中第一个案例前,最后一个案例执行后。

3.TestCase级别的,每个TestCase前后。

2、全局事件

要实现全局事件,必须写一个类,继承testing:

:

Environment类,实现里面的SetUp和TearDown方法。

1.SetUp()方法在所有案例执行前执行

2.TearDown()方法在所有案例执行后执行

classFooEnvironment:

publictesting:

:

Environment

{public:

virtualvoidSetUp()

{

std:

:

cout<<"FooFooEnvironmentSetUP"<

:

endl;

}virtualvoidTearDown()

{

std:

:

cout<<"FooFooEnvironmentTearDown"<

:

endl;

}

};

当然,这样还不够,我们还需要告诉gtest添加这个全局事件,我们需要在main函数中通过testing:

:

AddGlobalTestEnvironment方法将事件挂进来,也就是说,我们可以写很多个这样的类,然后将他们的事件都挂上去。

int_tmain(intargc,_TCHAR*argv[])

{

testing:

:

AddGlobalTestEnvironment(newFooEnvironment);

testing:

:

InitGoogleTest(&argc,argv);returnRUN_ALL_TESTS();

}

3、TestSuite事件

我们需要写一个类,继承testing:

:

Test,然后实现两个静态方法

1.SetUpTestCase()方法在第一个TestCase之前执行

()方法在最后一个TestCase之后执行

classFooTest:

publictesting:

:

Test{protected:

staticvoidSetUpTestCase(){

shared_resource_=new;

}staticvoidTearDownTestCase(){

deleteshared_resource_;

shared_resource_=NULL;

}staticT*shared_resource_;

};

在编写测试案例时,我们需要使用TEST_F这个宏,第一个参数必须是我们上面类的名字,代表一个TestSuite。

TEST_F(FooTest,Test1)

{SetUp()方法在每个TestCase之前执行

2.TearDown()方法在每个TestCase之后执行

classFooCalcTest:

publictesting:

:

Test

{protected:

virtualvoidSetUp()

{

();

}virtualvoidTearDown()

{

();

}

FooCalcm_foo;

};

TEST_F(FooCalcTest,HandleNoneZeroInput)

{

EXPECT_EQ(4,(12,16));

}

TEST_F(FooCalcTest,HandleNoneZeroInput_Error)

{

EXPECT_EQ(5,(12,16));

}

4、总结

gtest提供的这三种事件机制还是非常的简单和灵活的。

同时,通过继承Test类,使用TEST_F宏,我们可以在案例之间共享一些通用方法,共享资源。

使得我们的案例更加的简洁,清晰。

四、参数化

1、前言

在设计测试案例时,经常需要考虑给被测函数传入不同的值的情况。

我们之前的做法通常是写一个通用方法,然后编写在测试案例调用它。

即使使用了通用方法,这样的工作也是有很多重复性的,程序员都懒,都希望能够少写代码,多复用代码。

Google的程序员也一样,他们考虑到了这个问题,并且提供了一个灵活的参数化测试的方案。

2、旧的方案

为了对比,我还是把旧的方案提一下。

首先我先把被测函数IsPrime帖过来(在gtest的中),这个函数是用来判断传入的数值是否为质数的。

if(n%i==0)returnfalse;

}returntrue;

}

假如我要编写判断结果为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次,假如参数有50个,100个,怎么办?

同时,上面的写法产生的是1个测试案例,里面有5个检查点,假如我要把5个检查变成5个单独的案例,将会更加累人。

接下来,就来看看gtest是如何为我们解决这些问题的。

3、使用参数化后的方案

1.告诉gtest你的参数类型是什么

你必须添加一个类,继承testing:

:

TestWithParam,其中T就是你需要参数化的参数类型,比如上面的例子,我需要参数化一个int型的参数

classIsPrimeParamTest:

public:

:

testing:

:

TestWithParam

{

};

2.告诉gtest你拿到参数的值后,具体做些什么样的测试

这里,我们要使用一个新的宏(嗯,挺兴奋的):

TEST_P,关于这个"P"的含义,Google给出的答案非常幽默,就是说你可以理解为”parameterized"或者"pattern"。

我更倾向于”parameterized"的解释,呵呵。

在TEST_P宏里,使用GetParam()获取当前的参数的具体值。

TEST_P(IsPrimeParamTest,HandleTrueReturn)

{intn=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)andValuesIn(begin,end)

从一个C类型的数组或是STL容器,或是迭代器中取值

Bool()

取false和true两个值

Combine(g1,g2,...,gN)

这个比较强悍,它将g1,g2,...gN进行排列组合,g1,g2,...gN本身是一个参数生成器,每次分别从g1,g2,..gN中各取出一个值,组合成一个元组(Tuple)作为一个参数。

说明:

这个功能只在提供了头的系统中有效。

gtest会自动去判断是否支持tr/tuple,如果你的系统确实支持,而gtest判断错误的话,你可以重新定义宏GTEST_HAS_TR1_TUPLE=1。

4、参数化后的测试案例名

因为使用了参数化的方式执行案例,我非常想知道运行案例时,每个案例名称是如何命名的。

我执行了上面的代码,输出如下:

从上面的框框中的案例名称大概能够看出案例的命名规则,对于需要了解每个案例的名称的我来说,这非常重要。

命名规则大概为:

prefix/

5、类型参数化

gtest还提供了应付各种不同类型的数据时的方案,以及参数化类型的方案。

我个人感觉这个方案有些复杂。

首先要了解一下类型化测试,就用gtest里的例子了。

首先定义一个模版类,继承testing:

:

Test:

templateclassFooTest:

publictesting:

:

Test{public:

typedefstd:

:

listList;staticTshared_;

Tvalue_;

};

接着我们定义需要测试到的具体数据类型,比如下面定义了需要测试char,int和unsignedint:

typedeftesting:

:

TypesMyTypes;

TYPED_TEST_CASE(FooTest,MyTypes);

又是一个新的宏,来完成我们的测试案例,在声明模版的数据类型时,使用TypeParam

TYPED_TEST(FooTest,DoesBlah){Sincewearei

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 初中教育

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1