日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化

發(fā)布時(shí)間:2024/4/11 c/c++ 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、前言

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

二、舊的方案

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

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

????
//?Trivial?case?2:?even?numbers
????if?(n?%?2?==?0)?return?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?==?0)?return?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)然,即使傳入再多值也無(wú)法確保函數(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è)試案例中,我至少?gòu)?fù)制粘貼了4次,假如參數(shù)有50個(gè),100個(gè),怎么辦?同時(shí),上面的寫法產(chǎn)生的是1個(gè)測(cè)試案例,里面有5個(gè)檢查點(diǎn),假如我要把5個(gè)檢查變成5個(gè)單獨(dú)的案例,將會(huì)更加累人。

接下來(lái),就來(lái)看看gtest是如何為我們解決這些問(wèn)題的。?

三、使用參數(shù)化后的方案

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

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

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

};

?

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

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

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

?

嗯,非常的簡(jiǎn)潔!

3. 告訴gtest你想要測(cè)試的參數(shù)范圍是什么

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

INSTANTIATE_TEST_CASE_P(TrueReturn,?IsPrimeParamTest,?testing::Values(3,?5,?11,?23,?17));

?

第一個(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之間,步長(zhǎng)為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ù)。

說(shuō)明:這個(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è)案例名稱是如何命名的。我執(zhí)行了上面的代碼,輸出如下:


從上面的框框中的案例名稱大概能夠看出案例的命名規(guī)則,對(duì)于需要了解每個(gè)案例的名稱的我來(lái)說(shuō),這非常重要。 命名規(guī)則大概為:

prefix/test_case_name.test.name/index?

五、類型參數(shù)化?

gtest還提供了應(yīng)付各種不同類型的數(shù)據(jù)時(shí)的方案,以及參數(shù)化類型的方案。我個(gè)人感覺(jué)這個(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<char,?int,?unsigned?int>?MyTypes;
TYPED_TEST_CASE(FooTest,?MyTypes);

?

又是一個(gè)新的宏,來(lái)完成我們的測(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<char,?int,?unsigned?int>?MyTypes;
INSTANTIATE_TYPED_TEST_CASE_P(My,?FooTest,?MyTypes);

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

六、總結(jié)?

gtest為我們提供的參數(shù)化測(cè)試的功能給我們的測(cè)試帶來(lái)了極大的方便,使得我們可以寫更少更優(yōu)美的代碼,完成多種參數(shù)類型的測(cè)試案例。?

總結(jié)

以上是生活随笔為你收集整理的玩转Google开源C++单元测试框架Google Test系列(gtest)之四 - 参数化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。