青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

Google單元測(cè)試框架(轉(zhuǎn))

Google Test是Google C++ Testing Framework的一種非正式的稱謂,是google最近發(fā)布的一個(gè)開源C++測(cè)試框架。

Google測(cè)試框架是在不同平臺(tái)上(Linux,Mac OS X,Windows,Cygwin,Windows CE和Symbian)為編寫C++測(cè)試而生成的。它是基于xUnit架構(gòu)的測(cè)試框架,支持自動(dòng)發(fā)現(xiàn)測(cè)試,豐富的斷言集,用戶定義的斷言,death測(cè)試,致命與非致命的失敗,類型參數(shù)化測(cè)試,各類運(yùn)行測(cè)試的選項(xiàng)和XML的測(cè)試報(bào)告。

gtest的官方網(wǎng)站是:http://code.google.com/p/googletest/

從官方的使用文檔里,你幾乎可以獲得你想要的所有東西
http://code.google.com/p/googletest/wiki/GoogleTestPrimer
http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide

一、第一個(gè)Demo:
先來寫一個(gè)被測(cè)試函數(shù):

intFoo(int a,int b)
{
if(a==0||b==0)
{
throw "don'tdothat";
}

int c=a%b;
if(c==0)
return b;
return Foo(b,c);
}

上面的函數(shù)是用來求最大公約數(shù)的。下面我們就來編寫一個(gè)簡單的測(cè)試案例。
#include<gtest/gtest.h>

TEST(FooTest,HandleNoneZeroInput)
{
EXPECT_EQ(2,Foo(4,10));
EXPECT_EQ(6,Foo(30,18));
}
我們使用了TEST這個(gè)宏,它有兩個(gè)參數(shù),官方的對(duì)這兩個(gè)參數(shù)的解釋為:[TestCaseName,TestName],而我對(duì)這兩個(gè)參數(shù)的定義是:[TestSuiteName,TestCaseName],在下一篇我們?cè)賮砜礊槭裁催@樣定義。

對(duì)檢查點(diǎn)的檢查,我們上面使用到了EXPECT_EQ這個(gè)宏,這個(gè)宏用來比較兩個(gè)數(shù)字是否相等。Google還包裝了一系列EXPECT_* 和ASSERT_*的宏,而EXPECT系列和ASSERT系列的區(qū)別是:

1. EXPECT_* 失敗時(shí),案例繼續(xù)往下執(zhí)行。

2. ASSERT_* 失敗時(shí),案例終止運(yùn)行。

為了讓我們的案例運(yùn)行起來,我們還需要在main函數(shù)中添加如下代碼:

int_tmain(intargc,_TCHAR*argv[])
{
testing::InitGoogleTest(
&argc,argv);
return RUN_ALL_TESTS();
}

“testing::InitGoogleTest(&argc, argv);” :gtest的測(cè)試案例允許接收一系列的命令行參數(shù),因此,我們將命令行參數(shù)傳遞給gtest,進(jìn)行一些初始化操作。gtest的命令行參數(shù)非常豐富,在后面我們也會(huì)詳細(xì)了解到。

“RUN_ALL_TESTS()” :運(yùn)行所有測(cè)試案例

二、斷言
gtest中,斷言的宏可以理解為分為兩類,一類是ASSERT系列,一類是EXPECT系列。一個(gè)直觀的解釋就是:
1. ASSERT_* 系列的斷言,當(dāng)檢查點(diǎn)失敗時(shí),退出當(dāng)前案例的執(zhí)行。

2. EXPECT_* 系列的斷言,當(dāng)檢查點(diǎn)失敗時(shí),繼續(xù)往下執(zhí)行。

布爾值檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_TRUE(condition); EXPECT_TRUE(condition); condition is true
ASSERT_FALSE(condition); EXPECT_FALSE(condition); condition is false

數(shù)值型數(shù)據(jù)檢查

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

字符串檢查

Fatal assertion Nonfatal assertion Verifies
ASSERT_STREQ(expected_str, actual_str); EXPECT_STREQ(expected_str, actual_str); 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_str, actual_str); EXPECT_STRCASEEQ(expected_str, actual_str); 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
*STREQ*和*STRNE*同時(shí)支持char*和wchar_t*類型的,*STRCASEEQ*和*STRCASENE*卻只接收char*,估計(jì)是不常用吧。下面是幾個(gè)例子:

TEST(StringCmpTest,Demo)
{
char*pszCoderZh="CoderZh";
wchar_t
*wszCoderZh=L"CoderZh";
std::stringstrCoderZh
="CoderZh";
std::wstringwstrCoderZh
=L"CoderZh";

EXPECT_STREQ(
"CoderZh",pszCoderZh);
EXPECT_STREQ(L
"CoderZh",wszCoderZh);

EXPECT_STRNE(
"CnBlogs",pszCoderZh);
EXPECT_STRNE(L
"CnBlogs",wszCoderZh);

EXPECT_STRCASEEQ(
"coderzh",pszCoderZh);
//EXPECT_STRCASEEQ(L"coderzh",wszCoderZh);不支持

EXPECT_STREQ(
"CoderZh",strCoderZh.c_str());
EXPECT_STREQ(L
"CoderZh",wstrCoderZh.c_str());
}

顯示返回成功或失敗

直接返回成功:SUCCEED();

返回失敗:

Fatal assertion Nonfatal assertion
FAIL(); ADD_FAILURE();

異常檢查

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'tdothat";
}

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*);
}

Predicate Assertions

在使用EXPECT_TRUE或ASSERT_TRUE時(shí),有時(shí)希望能夠輸出更加詳細(xì)的信息,比如檢查一個(gè)函數(shù)的返回值TRUE還是FALSE時(shí),希望能夠輸出傳入的參數(shù)是什么,以便失敗后好跟蹤。因此提供了如下的斷言:

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
... ... ...

Google人說了,他們只提供<=5個(gè)參數(shù)的,如果需要測(cè)試更多的參數(shù),直接告訴他們。下面看看這個(gè)東西怎么用。

boolMutuallyPrime(intm,intn)
{
returnFoo(m,n)
>1;
}


TEST(PredicateAssertionTest,Demo)
{
intm
=5,n=6;
EXPECT_PRED2(MutuallyPrime,m,n);
}

當(dāng)失敗時(shí),返回錯(cuò)誤信息:

error: MutuallyPrime(m, n) evaluates to false, where
m evaluates to 5
n evaluates to 6

如果對(duì)這樣的輸出不滿意的話,還可以自定義輸出格式,通過如下:

Fatal assertion Nonfatal assertion Verifies
ASSERT_PRED_FORMAT1(pred_format1, val1);` EXPECT_PRED_FORMAT1(pred_format1, val1); pred_format1(val1) is successful
ASSERT_PRED_FORMAT2(pred_format2, val1, val2); EXPECT_PRED_FORMAT2(pred_format2, val1, val2); pred_format2(val1, val2) is successful
... ...

用法示例:

 

testing::AssertionResultAssertFoo(constchar*m_expr,constchar*n_expr,constchar*k_expr,intm,intn,intk){
if(Foo(m,n)==k)
returntesting::AssertionSuccess();
testing::Messagemsg;
msg
<<m_expr<<""<<n_expr<<"的最大公約數(shù)應(yīng)該是:"<<Foo(m,n)<<"而不是:"<<k_expr;
returntesting::AssertionFailure(msg);
}


TEST(AssertFooTest,HandleFail)
{
EXPECT_PRED_FORMAT3(AssertFoo,
3,6,2);
}

失敗時(shí),輸出信息:

error: 3 和 6 的最大公約數(shù)應(yīng)該是:3 而不是:2

是不是更溫馨呢,呵呵。

浮點(diǎn)型檢查

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

對(duì)相近的兩個(gè)數(shù)比較:

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

同時(shí),還可以使用:

EXPECT_PRED_FORMAT2(testing::FloatLE,val1,val2);
EXPECT_PRED_FORMAT2(testing::DoubleLE,val1,val2);


Windows HRESULT assertions

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

例如:

CComPtrshell;
ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L
"Shell.Application"));
CComVariantempty;
ASSERT_HRESULT_SUCCEEDED(shell
->ShellExecute(CComBSTR(url),empty,empty,empty,empty));

類型檢查

類型檢查失敗時(shí),直接導(dǎo)致代碼編不過,難得用處就在這?看下面的例子:

 

template<typenameT>
classFooType
{
public:
voidBar()
{
  testing::StaticAssertTypeEq
<int,T>();
}

}
;

TEST(TypeAssertionTest,Demo)
{
FooType
<bool>fooType;
fooType.Bar();
}


三、事件

gtest提供了多種事件機(jī)制,非常方便我們?cè)诎咐盎蛑笞鲆恍┎僮?。總結(jié)一下gtest的事件一共有3種:

1. 全局的,所有案例執(zhí)行前后。

2. TestSuite級(jí)別的,在某一批案例中第一個(gè)案例前,最后一個(gè)案例執(zhí)行后。

3. TestCae級(jí)別的,每個(gè)TestCase前后。
全局事件

要實(shí)現(xiàn)全局事件,必須寫一個(gè)類,繼承testing::Environment類,實(shí)現(xiàn)里面的SetUp和TearDown方法。

1. SetUp()方法在所有案例執(zhí)行前執(zhí)行

2. TearDown()方法在所有案例執(zhí)行后執(zhí)行

class FooEnvironment:public testing::Environment
{
public:
virtual void SetUp()
{
std::cout
<<"FooFooEnvironmentSetUP"<<std::endl;
}

virtual void TearDown()
{
std::cout
<<"FooFooEnvironmentTearDown"<<std::endl;
}

}
;
當(dāng)然,這樣還不夠,我們還需要告訴gtest添加這個(gè)全局事件,我們需要在main函數(shù)中通過testing::AddGlobalTestEnvironment方法將事件掛進(jìn)來,也就是說,我們可以寫很多個(gè)這樣的類,然后將他們的事件都掛上去。
int _tmain(int argc,_TCHAR* argv[])
{
testing::AddGlobalTestEnvironment(newFooEnvironment);
testing::InitGoogleTest(
&argc,argv);
return RUN_ALL_TESTS();
}
TestSuite事件

我們需要寫一個(gè)類,繼承testing::Test,然后實(shí)現(xiàn)兩個(gè)靜態(tài)方法

1. SetUpTestCase() 方法在第一個(gè)TestCase之前執(zhí)行
2.
TearDownTestCase() 方法在最后一個(gè)TestCase之后執(zhí)行
class FooTest:public testing::Test{
protected:
static void SetUpTestCase(){
shared_resource_
=new;
}

static void TearDownTestCase(){
delete shared_resource_;
shared_resource_
=NULL;
}

//Someexpensiveresourcesharedbyalltests.
staticT* shared_resource_;
}
;
在編寫測(cè)試案例時(shí),我們需要使用TEST_F這個(gè)宏,第一個(gè)參數(shù)必須是我們上面類的名字,代表一個(gè)TestSuite。
TEST_F(FooTest,Test1)
{
//youcanrefertoshared_resourcehere
}
TEST_F(FooTest,Test2)
{
//youcanrefertoshared_resourcehere
}
TestCase事件

TestCase事件是掛在每個(gè)案例執(zhí)行前后的,實(shí)現(xiàn)方式和上面的幾乎一樣,不過需要實(shí)現(xiàn)的是SetUp方法和TearDown方法:

1. SetUp()方法在每個(gè)TestCase之前執(zhí)行

2. TearDown()方法在每個(gè)TestCase之后執(zhí)行

class FooCalcTest:public testing::Test
{
protected:
virtual void SetUp()
{
m_foo.Init();
}

virtual void TearDown()
{
m_foo.Finalize();
}


FooCalc m_foo;
}
;

TEST_F(FooCalcTest,HandleNoneZeroInput)
{
EXPECT_EQ(
4,m_foo.Calc(12,16));
}


TEST_F(FooCalcTest,HandleNoneZeroInput_Error)
{
EXPECT_EQ(
5,m_foo.Calc(12,16));
}


四、參數(shù)化

在設(shè)計(jì)測(cè)試案例時(shí),經(jīng)常需要考慮給被測(cè)函數(shù)傳入不同的值的情況。我們之前的做法通常是寫一個(gè)通用方法,然后編寫在測(cè)試案例調(diào)用它。即使使用了通用方法,這樣的工作也是有很多重復(fù)性的,程序員都懶,都希望能夠少寫代碼,多復(fù)用代碼。Google的程序員也一樣,他們考慮到了這個(gè)問題,并且提供了一個(gè)靈活的參數(shù)化測(cè)試的方案。

舊的方案

為了對(duì)比,我還是把舊的方案提一下。首先我先把被測(cè)函數(shù)IsPrime帖過來(在gtest的example1.cc中),這個(gè)函數(shù)是用來判斷傳入的數(shù)值是否為質(zhì)數(shù)的。

// Returns true iff n is a prime number.
bool IsPrime(int n)
{
    
// Trivial case 1: small numbers
    if (n <= 1return false;

    
// Trivial case 2: even numbers
    if (n % 2 == 0return 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 == 0return false;
    }

    
// n has no integer factor in the range (1, n), and thus is prime.
    return true;
}

假如我要編寫判斷結(jié)果為True的測(cè)試案例,我需要傳入一系列數(shù)值讓函數(shù)IsPrime去判斷是否為True(當(dāng)然,即使傳入再多值也無法確保函數(shù)正確,呵呵),因此我需要這樣編寫如下的測(cè)試案例:

TEST(IsPrimeTest, HandleTrueReturn)
{
    EXPECT_TRUE(IsPrime(
3));
    EXPECT_TRUE(IsPrime(
5));
    EXPECT_TRUE(IsPrime(
11));
    EXPECT_TRUE(IsPrime(
23));
    EXPECT_TRUE(IsPrime(
17));
}

我們注意到,在這個(gè)測(cè)試案例中,我至少復(fù)制粘貼了4次,假如參數(shù)有50個(gè),100個(gè),怎么辦?同時(shí),上面的寫法產(chǎn)生的是1個(gè)測(cè)試案例,里面有5個(gè)檢查點(diǎn),假如我要把5個(gè)檢查變成5個(gè)單獨(dú)的案例,將會(huì)更加累人。

接下來,就來看看gtest是如何為我們解決這些問題的。
使用參數(shù)化后的方案

1. 告訴gtest你的參數(shù)類型是什么

你必須添加一個(gè)類,繼承testing::TestWithParam<T>,其中T就是你需要參數(shù)化的參數(shù)類型,比如上面的例子,我需要參數(shù)化一個(gè)int型的參數(shù)

 

class IsPrimeParamTest : public::testing::TestWithParam<int>
{

}
;

告訴gtest你拿到參數(shù)的值后,具體做些什么樣的測(cè)試

這里,我們要使用一個(gè)新的宏(嗯,挺興奮的):TEST_P,關(guān)于這個(gè)"P"的含義,Google給出的答案非常幽默,就是說你可以理解為”parameterized" 或者 "pattern"。我更傾向于parameterized"的解釋,呵呵。在TEST_P宏里,使用GetParam()獲取當(dāng)前的參數(shù)的具體值

TEST_P(IsPrimeParamTest, HandleTrueReturn)
{
    
int n =  GetParam();
    EXPECT_TRUE(IsPrime(n));
}

嗯,非常的簡潔!
告訴gtest你想要測(cè)試的參數(shù)范圍是什么

 使用INSTANTIATE_TEST_CASE_P這宏來告訴gtest你要測(cè)試的參數(shù)范圍:

INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(35112317));

第一個(gè)參數(shù)是測(cè)試案例的前綴,可以任意取。

第二個(gè)參數(shù)是測(cè)試案例的名稱,需要和之前定義的參數(shù)化的類的名稱相同,如:IsPrimeParamTest

第三個(gè)參數(shù)是可以理解為參數(shù)生成器,上面的例子使用test::Values表示使用括號(hào)內(nèi)的參數(shù)。Google提供了一系列的參數(shù)生成的函數(shù):

Range(begin, end[, step]) 范圍在begin~end之間,步長為step,不包括end
Values(v1, v2, ..., vN) v1,v2到vN的值
ValuesIn(container) and ValuesIn(begin, end) 從一個(gè)C類型的數(shù)組或是STL容器,或是迭代器中取值
Bool() false 和 true 兩個(gè)值
Combine(g1, g2, ..., gN)

這個(gè)比較強(qiáng)悍,它將g1,g2,...gN進(jìn)行排列組合,g1,g2,...gN本身是一個(gè)參數(shù)生成器,每次分別從g1,g2,..gN中各取出一個(gè)值,組合成一個(gè)元組(Tuple)作為一個(gè)參數(shù)。

說明:這個(gè)功能只在提供了<tr1/tuple>頭的系統(tǒng)中有效。gtest會(huì)自動(dòng)去判斷是否支持tr/tuple,如果你的系統(tǒng)確實(shí)支持,而gtest判斷錯(cuò)誤的話,你可以重新定義宏GTEST_HAS_TR1_TUPLE=1。

參數(shù)化后的測(cè)試案例名

因?yàn)槭褂昧藚?shù)化的方式執(zhí)行案例,我非常想知道運(yùn)行案例時(shí),每個(gè)案例名稱是如何命名的。
 命名規(guī)則大概為:

prefix/test_case_name.test.name/index
類型參數(shù)化

gtest還提供了應(yīng)付各種不同類型的數(shù)據(jù)時(shí)的方案,以及參數(shù)化類型的方案。我個(gè)人感覺這個(gè)方案有些復(fù)雜。首先要了解一下類型化測(cè)試,就用gtest里的例子了。

首先定義一個(gè)模版類,繼承testing::Test:

 

template <typename T>
class FooTest : public testing::Test {
 
public:
  
  typedef std::list
<T> List;
  
static T shared_;
  T value_;
}
;

接著我們定義需要測(cè)試到的具體數(shù)據(jù)類型,比如下面定義了需要測(cè)試char,int和unsigned int :

typedef testing::Types<charint, unsigned int> MyTypes;
TYPED_TEST_CASE(FooTest, MyTypes);

又是一個(gè)新的宏,來完成我們的測(cè)試案例,在聲明模版的數(shù)據(jù)類型時(shí),使用TypeParam

 

TYPED_TEST(FooTest, DoesBlah) {
  
// Inside a test, refer to the special name TypeParam to get the type
  
// parameter.  Since we are inside a derived class template, C++ requires
  
// us to visit the members of FooTest via 'this'.
  TypeParam n = this->value_;

  
// To visit static members of the fixture, add the 'TestFixture::'
  
// prefix.
  n += TestFixture::shared_;

  
// To refer to typedefs in the fixture, add the 'typename TestFixture::'
  
// prefix.  The 'typename' is required to satisfy the compiler.
  typename TestFixture::List values;
  values.push_back(n);
  
}

上面的例子看上去也像是類型的參數(shù)化,但是還不夠靈活,因?yàn)樾枰孪戎李愋偷牧斜怼test還提供一種更加靈活的類型參數(shù)化的方式,允許你在完成測(cè)試的邏輯代碼之后再去考慮需要參數(shù)化的類型列表,并且還可以重復(fù)的使用這個(gè)類型列表。下面也是官方的例子:

template <typename T>
class FooTest : public testing::Test {
  
};

TYPED_TEST_CASE_P(FooTest);

接著又是一個(gè)新的宏TYPED_TEST_P類完成我們的測(cè)試案例:

TYPED_TEST_P(FooTest, DoesBlah) {
  
// Inside a test, refer to TypeParam to get the type parameter.
  TypeParam n = 0;
  
}

TYPED_TEST_P(FooTest, HasPropertyA) {  }

接著,我們需要我們上面的案例,使用REGISTER_TYPED_TEST_CASE_P宏,第一個(gè)參數(shù)是testcase的名稱,后面的參數(shù)是test的名稱

REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA);

接著指定需要的類型列表:

typedef testing::Types<charint, unsigned int> MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

這種方案相比之前的方案提供更加好的靈活度,當(dāng)然,框架越靈活,復(fù)雜度也會(huì)隨之增加。

五、死亡測(cè)試
死亡測(cè)試”名字比較恐怖,這里的“死亡”指的的是程序的崩潰。通常在測(cè)試過程中,我們需要考慮各種各樣的輸入,有的輸入可能直接導(dǎo)致程序崩潰,這時(shí)我們就需要檢查程序是否按照預(yù)期的方式掛掉,這也就是所謂的“死亡測(cè)試”。gtest的死亡測(cè)試能做到在一個(gè)安全的環(huán)境下執(zhí)行崩潰的測(cè)試案例,同時(shí)又對(duì)崩潰結(jié)果進(jìn)行驗(yàn)證。
使用的宏
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 matches predicate

由于有些異常只在Debug下拋出,因此還提供了*_DEBUG_DEATH,用來處理Debug和Realease下的不同。

、*_DEATH(statement, regex`)

1. statement是被測(cè)試的代碼語句

2. regex是一個(gè)正則表達(dá)式,用來匹配異常時(shí)在stderr中輸出的內(nèi)容

如下面的例子:

void Foo()
{
    
int *pInt = 0;
    
*pInt = 42 ;
}

TEST(FooDeathTest, Demo)
{
    EXPECT_DEATH(Foo(), 
"");
}

重要:編寫死亡測(cè)試案例時(shí),TEST的第一個(gè)參數(shù),即testcase_name,請(qǐng)使用DeathTest后綴。原因是gtest會(huì)優(yōu)先運(yùn)行死亡測(cè)試案例,應(yīng)該是為線程安全考慮。

*_EXIT(statement, predicate, regex`)

1. statement是被測(cè)試的代碼語句

2. predicate 在這里必須是一個(gè)委托,接收int型參數(shù),并返回bool。只有當(dāng)返回值為true時(shí),死亡測(cè)試案例才算通過。gtest提供了一些常用的predicate:

testing::ExitedWithCode(exit_code)


如果程序正常退出并且退出碼與exit_code相同則返回 true

testing::KilledBySignal(signal_number)  // Windows下不支持

 
如果程序被signal_number信號(hào)kill的話就返回true

 regex是一個(gè)正則表達(dá)式,用來匹配異常時(shí)在stderr中輸出的內(nèi)容

這里, 要說明的是,*_DEATH其實(shí)是對(duì)*_EXIT進(jìn)行的一次包裝,*_DEATH的predicate判斷進(jìn)程是否以非0退出碼退出或被一個(gè)信號(hào)殺死。

例子:

TEST(ExitDeathTest, Demo)
{
    EXPECT_EXIT(_exit(
1),  testing::ExitedWithCode(1),  "");
}

、*_DEBUG_DEATH

先來看定義:

#ifdef NDEBUG

#define EXPECT_DEBUG_DEATH(statement, regex) \
  
do { statement; } while (false)

#define ASSERT_DEBUG_DEATH(statement, regex) \
  
do { statement; } while (false)

#else

#define EXPECT_DEBUG_DEATH(statement, regex) \
  EXPECT_DEATH(statement, regex)

#define ASSERT_DEBUG_DEATH(statement, regex) \
  ASSERT_DEATH(statement, regex)

#endif  // NDEBUG for EXPECT_DEBUG_DEATH

可以看到,在Debug版和Release版本下, *_DEBUG_DEATH的定義不一樣。因?yàn)楹芏喈惓V粫?huì)在Debug版本下拋出,而在Realease版本下不會(huì)拋出,所以針對(duì)Debug和Release分別做了不同的處理??磄test里自帶的例子就明白了:

int DieInDebugElse12(int* sideeffect) {
    
if (sideeffect) *sideeffect = 12;
#ifndef NDEBUG
    GTEST_LOG_(FATAL, 
"debug death inside DieInDebugElse12()");
#endif  // NDEBUG
    
return 12;
}

TEST(TestCase, TestDieOr12WorksInDgbAndOpt)
{
    
int sideeffect = 0;
    
// Only asserts in dbg.
    EXPECT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death");

    #ifdef NDEBUG
    
// opt-mode has sideeffect visible.
    EXPECT_EQ(12, sideeffect);
    
#else
    
// dbg-mode no visible sideeffect.
    EXPECT_EQ(0, sideeffect);
    
#endif
}

關(guān)于正則表達(dá)式

POSIX系統(tǒng)(Linux, Cygwin, 和 Mac中,gtest的死亡測(cè)試中使用的是POSIX風(fēng)格的正則表達(dá)式,想了解POSIX風(fēng)格表達(dá)式可參考:

1. POSIX extended regular expression

2. Wikipedia entry.

在Windows系統(tǒng)中,gtest的死亡測(cè)試中使用的是gtest自己實(shí)現(xiàn)的簡單的正則表達(dá)式語法。 相比POSIX風(fēng)格,gtest的簡單正則表達(dá)式少了很多內(nèi)容,比如 ("x|y"), ("(xy)"), ("[xy]") 和("x{5,7}")都不支持。

下面是簡單正則表達(dá)式支持的一些內(nèi)容:


matches any literal character c
\\d matches any decimal digit
\\D matches any character that's not a decimal digit
\\f matches \f
\\n matches \n
\\r matches \r
\\s matches any ASCII whitespace, including \n
\\S matches any character that's not a whitespace
\\t matches \t
\\v matches \v
\\w matches any letter, _, or decimal digit
\\W matches any character that \\w doesn't match
\\c matches any literal character c, which must be a punctuation
. matches any single character except \n
A? matches 0 or 1 occurrences of A
A* matches 0 or many occurrences of A
A+ matches 1 or many occurrences of A
^ matches the beginning of a string (not that of each line)
$ matches the end of a string (not that of each line)
xy matches x followed by y

gtest定義兩個(gè)宏,用來表示當(dāng)前系統(tǒng)支持哪套正則表達(dá)式風(fēng)格:

1. POSIX風(fēng)格:GTEST_USES_POSIX_RE = 1

2. Simple風(fēng)格:GTEST_USES_SIMPLE_RE=1

死亡測(cè)試運(yùn)行方式

1. fast方式(默認(rèn)的方式)

testing::FLAGS_gtest_death_test_style = "fast";

2. threadsafe方式

testing::FLAGS_gtest_death_test_style = "threadsafe";


你可以在 main() 里為所有的死亡測(cè)試設(shè)置測(cè)試形式,也可以為某次測(cè)試單獨(dú)設(shè)置。Google Test會(huì)在每次測(cè)試之前保存這個(gè)標(biāo)記并在測(cè)試完成后恢復(fù),所以你不需要去管這部分工作 。如:

TEST(MyDeathTest, TestOne) {
  testing::FLAGS_gtest_death_test_style 
= "threadsafe";
  
// This test is run in the "threadsafe" style:
  ASSERT_DEATH(ThisShouldDie(), "");
}

TEST(MyDeathTest, TestTwo) {
  
// This test is run in the "fast" style:
  ASSERT_DEATH(ThisShouldDie(), "");
}

int main(int argc, char** argv) {
  testing::InitGoogleTest(
&argc, argv);
  testing::FLAGS_gtest_death_test_style 
= "fast";
  
return RUN_ALL_TESTS();
}

注意事項(xiàng)

1. 不要在死亡測(cè)試?yán)镝尫艃?nèi)存。

2. 在父進(jìn)程里再次釋放內(nèi)存。

3. 不要在程序中使用內(nèi)存堆檢查。

六、運(yùn)行參數(shù)

使用gtest編寫的測(cè)試案例通常本身就是一個(gè)可執(zhí)行文件,因此運(yùn)行起來非常方便。同時(shí),gtest也為我們提供了一系列的運(yùn)行參數(shù)(環(huán)境變量、命令行參數(shù)或代碼里指定),使得我們可以對(duì)案例的執(zhí)行進(jìn)行一些有效的控制。

基本介紹

前面提到,對(duì)于運(yùn)行參數(shù),gtest提供了三種設(shè)置的途徑:

1. 系統(tǒng)環(huán)境變量

2. 命令行參數(shù)

3. 代碼中指定FLAG

因?yàn)樘峁┝巳N途徑,就會(huì)有優(yōu)先級(jí)的問題, 有一個(gè)原則是,最后設(shè)置的那個(gè)會(huì)生效。不過總結(jié)一下,通常情況下,比較理想的優(yōu)先級(jí)為:

命令行參數(shù) > 代碼中指定FLAG > 系統(tǒng)環(huán)境變量

為什么我們編寫的測(cè)試案例能夠處理這些命令行參數(shù)呢?是因?yàn)槲覀冊(cè)趍ain函數(shù)中,將命令行參數(shù)交給了gtest,由gtest來搞定命令行參數(shù)的問題。

int _tmain(int argc, _TCHAR* argv[])
{
    testing::InitGoogleTest(
&argc, argv);
    
return RUN_ALL_TESTS();
}

這樣,我們就擁有了接收和響應(yīng)gtest命令行參數(shù)的能力。如果需要在代碼中指定FLAG,可以使用testing::GTEST_FLAG這個(gè)宏來設(shè)置。比如相對(duì)于命令行參數(shù)--gtest_output,可以使用testing::GTEST_FLAG(output) = "xml:";來設(shè)置。注意到了,不需要加--gtest前綴了。同時(shí),推薦將這句放置InitGoogleTest之前,這樣就可以使得對(duì)于同樣的參數(shù),命令行參數(shù)優(yōu)先級(jí)高于代碼中指定。

int _tmain(int argc, _TCHAR* argv[])
{
    testing::GTEST_FLAG(output) 
= "xml:";
    testing::InitGoogleTest(
&argc, argv);
    
return RUN_ALL_TESTS();
}

最后再來說下第一種設(shè)置方式-系統(tǒng)環(huán)境變量。如果需要gtest的設(shè)置系統(tǒng)環(huán)境變量,必須注意的是:

1. 系統(tǒng)環(huán)境變量全大寫,比如對(duì)于--gtest_output,響應(yīng)的系統(tǒng)環(huán)境變量為:GTEST_OUTPUT

2.  有一個(gè)命令行參數(shù)例外,那就是--gtest_list_tests,它是不接受系統(tǒng)環(huán)境變量的。(只是用來羅列測(cè)試案例名稱)

參數(shù)列表

了解了上面的內(nèi)容,我這里就直接將所有命令行參數(shù)總結(jié)和羅列一下。如果想要獲得詳細(xì)的命令行說明,直接運(yùn)行你的案例,輸入命令行參數(shù):/? 或 --help 或 -help

1. 測(cè)試案例集合

命令行參數(shù) 說明
--gtest_list_tests 使用這個(gè)參數(shù)時(shí),將不會(huì)執(zhí)行里面的測(cè)試案例,而是輸出一個(gè)案例的列表。
--gtest_filter

對(duì)執(zhí)行的測(cè)試案例進(jìn)行過濾,支持通配符

?    單個(gè)字符

*    任意字符

-    排除,如,-a 表示除了a

:    取或,如,a:b 表示a或b

比如下面的例子:

./foo_test 沒有指定過濾條件,運(yùn)行所有案例
./foo_test --gtest_filter=* 使用通配符*,表示運(yùn)行所有案例
./foo_test --gtest_filter=FooTest.* 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”為FooTest的案例
./foo_test --gtest_filter=*Null*:*Constructor* 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”或“測(cè)試名稱(test_name)”包含Null或Constructor的案例。
./foo_test --gtest_filter=-*DeathTest.* 運(yùn)行所有非死亡測(cè)試案例。
./foo_test --gtest_filter=FooTest.*-FooTest.Bar 運(yùn)行所有“測(cè)試案例名稱(testcase_name)”為FooTest的案例,但是除了FooTest.Bar這個(gè)案例

--gtest_also_run_disabled_tests

執(zhí)行案例時(shí),同時(shí)也執(zhí)行被置為無效的測(cè)試案例。關(guān)于設(shè)置測(cè)試案例無效的方法為:

在測(cè)試案例名稱或測(cè)試名稱中添加DISABLED前綴,比如:

// Tests that Foo does Abc.
TEST(FooTest, DISABLED_DoesAbc) {  }

class DISABLED_BarTest : public testing::Test {  };

// Tests that Bar does Xyz.
TEST_F(DISABLED_BarTest, DoesXyz) {  }
--gtest_repeat=[COUNT]

設(shè)置案例重復(fù)運(yùn)行次數(shù),非常棒的功能!比如:

--gtest_repeat=1000      重復(fù)執(zhí)行1000次,即使中途出現(xiàn)錯(cuò)誤。
--gtest_repeat=-1          無限次數(shù)執(zhí)行。。。。
--gtest_repeat=1000 --gtest_break_on_failure     重復(fù)執(zhí)行1000次,并且在第一個(gè)錯(cuò)誤發(fā)生時(shí)立即停止。這個(gè)功能對(duì)調(diào)試非常有用。
--gtest_repeat=1000 --gtest_filter=FooBar     重復(fù)執(zhí)行1000次測(cè)試案例名稱為FooBar的案例。

測(cè)試案例輸出
命令行參數(shù) 說明
--gtest_color=(yes|no|auto) 輸出命令行時(shí)是否使用一些五顏六色的顏色。默認(rèn)是auto。
--gtest_print_time 輸出命令行時(shí)是否打印每個(gè)測(cè)試案例的執(zhí)行時(shí)間。默認(rèn)是不打印的。
--gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]

將測(cè)試結(jié)果輸出到一個(gè)xml中。

1.--gtest_output=xml:    不指定輸出路徑時(shí),默認(rèn)為案例當(dāng)前路徑。

2.--gtest_output=xml:d:\ 指定輸出到某個(gè)目錄

3.--gtest_output=xml:d:\foo.xml 指定輸出到d:\foo.xml

如果不是指定了特定的文件路徑,gtest每次輸出的報(bào)告不會(huì)覆蓋,而會(huì)以數(shù)字后綴的方式創(chuàng)建。xml的輸出內(nèi)容后面介紹吧。

對(duì)案例的異常處理
命令行參數(shù) 說明
--gtest_break_on_failure 調(diào)試模式下,當(dāng)案例失敗時(shí)停止,方便調(diào)試
--gtest_throw_on_failure 當(dāng)案例失敗時(shí)以C++異常的方式拋出
--gtest_catch_exceptions

是否捕捉異常。gtest默認(rèn)是不捕捉異常的,因此假如你的測(cè)試案例拋了一個(gè)異常,很可能會(huì)彈出一個(gè)對(duì)話框,這非常的不友好,同時(shí)也阻礙了測(cè)試案例的運(yùn)行。如果想不彈這個(gè)框,可以通過設(shè)置這個(gè)參數(shù)來實(shí)現(xiàn)。如將--gtest_catch_exceptions設(shè)置為一個(gè)非零的數(shù)。

注意:這個(gè)參數(shù)只在Windows下有效。

XML報(bào)告輸出格式

<?xml version="1.0" encoding="UTF-8"?>
<testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
  
<testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15">
    
<testcase name="Addition" status="run" time="7" classname="">
      
<failure message="Value of: add(1, 1)  Actual: 3 Expected: 2" type=""/>
      
<failure message="Value of: add(1, -1)  Actual: 1 Expected: 0" type=""/>
    
</testcase>
    
<testcase name="Subtraction" status="run" time="5" classname="">
    
</testcase>
  
</testsuite>
  
<testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
    
<testcase name="NonContradiction" status="run" time="5" classname="">
    
</testcase>
  
</testsuite>
</testsuites>

從報(bào)告里可以看出,我們之前在TEST等宏中定義的測(cè)試案例名稱(testcase_name)在xml測(cè)試報(bào)告中其實(shí)是一個(gè)testsuite name,而宏中的測(cè)試名稱(test_name)在xml測(cè)試報(bào)告中是一個(gè)testcase name,概念上似乎有點(diǎn)混淆,就看你怎么看吧。

當(dāng)檢查點(diǎn)通過時(shí),不會(huì)輸出任何檢查點(diǎn)的信息。當(dāng)檢查點(diǎn)失敗時(shí),會(huì)有詳細(xì)的失敗信息輸出來failure節(jié)點(diǎn)。

在我使用過程中發(fā)現(xiàn)一個(gè)問題,當(dāng)我同時(shí)設(shè)置了--gtest_filter參數(shù)時(shí),輸出的xml報(bào)告中還是會(huì)包含所有測(cè)試案例的信息,只不過那些不被執(zhí)行的測(cè)試案例的status值為“notrun”。而我之前認(rèn)為的輸出的xml報(bào)告應(yīng)該只包含我需要運(yùn)行的測(cè)試案例的信息。不知是否可提供一個(gè)只輸出需要執(zhí)行的測(cè)試案例的xml報(bào)告。因?yàn)楫?dāng)我需要在1000個(gè)案例中執(zhí)行其中1個(gè)案例時(shí),在報(bào)告中很難找到我運(yùn)行的那個(gè)案例,雖然可以查找,但還是很麻煩。

總結(jié)

本篇主要介紹了gtest案例執(zhí)行時(shí)提供的一些參數(shù)的使用方法,這些參數(shù)都非常有用。在實(shí)際編寫gtest測(cè)試案例時(shí)肯定會(huì)需要用到的時(shí)候。至少我現(xiàn)在比較常用的就是:

1. --gtest_filter

2. --gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]

3. --gtest_catch_exceptions

最后再總結(jié)一下我使用過程中遇到的幾個(gè)問題:

1. 同時(shí)使用--gtest_filter和--gtest_output=xml:時(shí),在xml測(cè)試報(bào)告中能否只包含過濾后的測(cè)試案例的信息。

2. 有時(shí),我在代碼中設(shè)置 testing::GTEST_FLAG(catch_exceptions) = 1和我在命令行中使用--gtest_catch_exceptions結(jié)果稍有不同,在代碼中設(shè)置FLAG方式有時(shí)候捕捉不了某些異常,但是通過命令行參數(shù)的方式一般都不會(huì)有問題。這是我曾經(jīng)遇到過的一個(gè)問題,最后我的處理辦法是既在代碼中設(shè)置FLAG,又在命令行參數(shù)中傳入--gtest_catch_exceptions。不知道是gtest在catch_exceptions方面不夠穩(wěn)定,還是我自己測(cè)試案例的問題。


posted on 2009-06-02 11:19 Randy 閱讀(2376) 評(píng)論(0)  編輯 收藏 引用


只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


<2009年6月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

留言簿(3)

隨筆檔案

搜索

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            午夜精品av| 99国产精品| 欧美成人午夜激情在线| 久久精品国产99国产精品| 欧美中文在线观看国产| 久久婷婷国产综合精品青草| 久久最新视频| 欧美伦理a级免费电影| 欧美日韩一区二区在线观看视频| 欧美日韩午夜在线视频| 国产精品av免费在线观看| 国产精品久久久久永久免费观看| 久久九九99视频| 禁久久精品乱码| 国内自拍亚洲| 亚洲精品黄色| 亚洲欧美日韩电影| 久久久久久伊人| 亚洲欧洲精品一区| 亚洲精品久久久蜜桃 | 欧美成人a视频| 91久久久亚洲精品| 亚洲欧美国产精品va在线观看| 久久久久久久久伊人| 欧美精品激情| 精品成人在线观看| 亚洲伊人第一页| 女人色偷偷aa久久天堂| 一区二区三区黄色| 久久亚洲春色中文字幕| 国产精品爱啪在线线免费观看 | 国产欧美日韩中文字幕在线| 亚洲高清免费视频| 香蕉久久夜色精品国产| 亚洲成人在线网| 亚洲欧美电影在线观看| 欧美va亚洲va日韩∨a综合色| 国产精品大全| 亚洲免费av电影| 老司机精品视频一区二区三区| 亚洲美女电影在线| 老巨人导航500精品| 国产亚洲一区二区三区| 亚洲在线中文字幕| 亚洲精品美女| 欧美成人资源网| 亚洲国产精品久久久久秋霞影院| 欧美一区二区三区在线播放| 亚洲精品久久| 欧美国产日韩一二三区| 伊人久久亚洲热| 久久gogo国模啪啪人体图| 一区二区av在线| 欧美日韩亚洲一区在线观看| 亚洲三级免费| 亚洲高清久久网| 裸体一区二区三区| 亚洲福利在线观看| 麻豆成人在线| 久久久久久夜精品精品免费| 国产日韩亚洲欧美| 欧美影片第一页| 午夜电影亚洲| 国精品一区二区| 久久久久久网| 久久福利资源站| 禁久久精品乱码| 欧美国产在线观看| 久久综合国产精品| 久久日韩粉嫩一区二区三区| 亚洲欧美日韩一区| 国产精品永久免费在线| 午夜视频在线观看一区二区三区| 亚洲素人在线| 国产精品五区| 久久婷婷麻豆| 免费影视亚洲| 一本不卡影院| 亚洲一区黄色| 娇妻被交换粗又大又硬视频欧美| 欧美a级片网| 欧美激情综合| 亚洲一区二区三区乱码aⅴ| 亚洲一区二区三区涩| 国产一区二区三区不卡在线观看 | 亚洲国产精品一区在线观看不卡| 欧美激情一区二区三区四区 | 亚洲肉体裸体xxxx137| 亚洲精品日韩激情在线电影| 国产精品久久一区主播| 狂野欧美一区| 欧美日韩一级大片网址| 久久精品99久久香蕉国产色戒 | 欧美—级在线免费片| 亚洲欧美日韩成人| 免费中文字幕日韩欧美| 午夜久久99| 免费黄网站欧美| 亚洲女人天堂成人av在线| 久久久久综合网| 亚洲一区二区三区影院| 久久精品国产成人| 国产精品99久久久久久久vr | 亚洲精品国产拍免费91在线| 亚洲私人影院在线观看| 最新热久久免费视频| 亚洲永久网站| 日韩视频中文字幕| 久久gogo国模啪啪人体图| 99亚洲伊人久久精品影院红桃| 午夜在线精品| 亚洲午夜视频在线| 狂野欧美激情性xxxx| 久久国产精品99久久久久久老狼| 欧美精品福利在线| 美女精品视频一区| 国产精品呻吟| 夜夜爽夜夜爽精品视频| 亚洲精品中文字幕有码专区| 久久精品盗摄| 亚洲欧洲av一区二区| 欧美精品不卡| 亚洲国内精品| 欧美日本中文字幕| 国内一区二区在线视频观看| 99ri日韩精品视频| 亚洲日本欧美| 美女福利精品视频| 免费久久久一本精品久久区| 国产日韩一区| 一区二区动漫| 亚洲无线视频| 国产精品av久久久久久麻豆网| 亚洲美女中文字幕| 一区二区三区日韩欧美精品| 欧美精品日韩一本| 亚洲国产国产亚洲一二三| 在线日韩av| 久久综合999| 欧美电影在线免费观看网站| 亚洲国产成人久久| 免费欧美在线| 亚洲日本aⅴ片在线观看香蕉| 亚洲精品一区二区三区福利| 欧美黄色片免费观看| 亚洲精品国产视频| 亚洲天堂成人| 国产美女一区二区| 欧美一区国产二区| 久久人人爽人人爽| 亚洲高清一区二区三区| 欧美jjzz| 中文在线资源观看网站视频免费不卡| 一本色道久久综合亚洲精品按摩| 欧美日韩国产免费| 亚洲一区二区伦理| 久久久亚洲人| 亚洲精品美女在线| 欧美日韩在线播放三区| 亚洲性av在线| 快播亚洲色图| 一区二区三区免费网站| 国产精品综合色区在线观看| 欧美专区在线播放| 亚洲国产综合在线| 欧美一区二区在线| 亚洲国产精品悠悠久久琪琪| 欧美日韩国产三级| 欧美一区免费| 亚洲欧洲另类| 亚洲欧美一区二区视频| 影音先锋中文字幕一区二区| 欧美久久综合| 欧美一区日韩一区| 亚洲国产精品视频| 欧美一区二区三区视频免费| 亚洲电影视频在线| 国产精品久久一级| 免费中文日韩| 香蕉久久夜色精品| 亚洲激情另类| 久久久久久亚洲精品杨幂换脸 | 麻豆9191精品国产| 亚洲视频免费观看| 精品二区久久| 国产精品一区二区三区久久| 麻豆精品视频在线观看视频| 亚洲一区二区毛片| 亚洲国产精品第一区二区| 欧美在线观看视频| aaa亚洲精品一二三区| 国产综合亚洲精品一区二| 亚洲欧美成人在线| 久久九九久久九九| 91久久精品美女| 国产日韩av在线播放| 欧美日韩午夜| 欧美精品日日鲁夜夜添| 久久在线免费观看| 欧美一区二区播放|