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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)

發布時間:2024/2/28 c/c++ 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Setting Expectations

????成功地使用Mock對象的關鍵是在它上面設置合適的期望。如果你設置的期望太過嚴格,你的測試可能會因為無關的改變而失敗。如果你把期望設置的太過松馳,bugs可能會溜過去。而你需要的是你的測試可以剛好捕獲你想要捕獲的那一種bugGoogle Mock提供了一些方法可以讓你的測試尺度剛好( just right )

General Syntax

????Goolge Mock中,我們用EXPECT_CALL()宏來設置一個Mock函數上的期望。一般語法是:

EXPECT_CALL(mock_object, method(matchers))< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />

????.Times(cardinality)

????.WillOnce(action)

.WillRepeatedly(action);

這個宏有兩個參數:第一個是Mock對象,第二個參數是函數和它的參數。注意兩個參數是用逗號( , )分隔的,而不是句號( . )

這個宏可以跟一些可選子句,這些子句可以提供關于期望更多的信息。我們將會在下面的小節中介紹每個子句有什么意義。

這些語法設計的一個目的是讓它們讀起來像是英語。比如你可能會直接猜出下面的代碼是有什么含義

using?::testing::Return;...

EXPECT_CALL(turtle, GetX())

????.Times(5)

????.WillOnce(Return(100))

????.WillOnce(Return(150))

.WillRepeatedly(Return(200));

公布答案,turtle對象的GetX()方法會被調用5次,它第一次返回100,第二次返回150,然后每次返回200。許多人喜歡稱這種語法方式為特定領域語言( Domain-Specific Language (DSL) )

注意:為什么我們要用宏來實現呢?有兩個原因:第一,它讓期望更容易被認出來(?無論是grep還是人去閱讀?),第二,它允許Google Mock可以得到失敗期望在源文件的位置,從而使Debug更容易。

Matchers: What Arguments Do We Expect?

????當一個Mock函數需要帶參數時,我們必須指定我們期望的參數的是什么;比如:

// Expects the turtle to move forward by 100 units.

EXPECT_CALL(turtle, Forward(100));

????有時你可能不想指定的太精確(?還記得前面測試不應太嚴格嗎?指定的太精確會導致測試健壯性不足,并影響測試的本意。所以我們鼓勵你只指定那些必須要指定的參數,不要多,也不要少?)。如果你只關心Forward是否會被調用,而不關心它用什么參數,你可以寫_作為參數,它的意義是“任意”參數。

using?::testing::_;

...

// Expects the turtle to move forward.

EXPECT_CALL(turtle, Forward(_));

????_是我們稱為Matchers的一個例子,一個matcher是像一個斷言,它可測試一個參數是否是我們期望的。你可用在EXPECT_CALL()中任何寫函數參數期望的地方用matcher

????一個內置的matchers可以在CheatSheet中找到,比如,下面是Ge( greater than or equal ) matcher的應用。

using?::testing::Ge;...

EXPECT_CALL(turtle, Forward(Ge(100)));

????這個測試是檢查turtle是否被告知要至少前進至少100個單位。

Cardinalities: How Many Times Will It Be Called?

????EXPECT_CALL()之后第一個我們可以指定的子句是Times()。我們稱Times的參數為cardinality,因為它是指這個函數應該被調用多少次。Times可以讓我們指定一個期望多次,而不用去寫一次次地寫這個期望。更重要的是,cardinality可以是“模糊”的,就像matcher一樣。它可以讓測試者更準確地表達他測試的目的。

????一個有趣的特例是我們指定Times(0)。你也許已經猜到了,它是指函數在指定參數下不應該被調用,如果這個函數被調用了,Google Mock會報告一個Google Test失敗。

????我們已經見過AtLeast(n)這個模糊cardinalities的例子了。你可以在CheatSheet中找一個內置cardinalities列表。

????Times()子句可以省略。如果你省略Times()Google Mock會推斷出cardinality的值是什么。這個規則很容易記:

l??如果在EXPECT_CALL既沒有WillOnce()也沒有WillRepeatedly(),那推斷出的cardinality就是Times(1)

l??如果有nWillOnce(),但沒有WillRepeatedl(),其中n >= 1,那么cardinality就是Times(n)

l??如果有nWillOnce(),和一個WillRepeatedly(),其中n >= 0,那么cardinality就是Times(AtLeast(n))

小測試:如果一個函數期望被調用2次,但被調用了4次,你認為會發生什么呢?

Actions: What Should It Do?

????請記住一個Mock對象其實是沒有實現的。是我們這些用戶去告訴它當一個函數被調用時它應該做什么。這在Google Mock中是很簡單的。

????首先,如果Mock函數的返回類型是一個指針或是內置類型,那這個函數是有默認行為(?一個void函數直接返回,bool函數返回false,其它函數返回0 )。如果你不想改變它,那這種行為就會被應用。

????其次,如果一個Mock函數沒有默認行為,或默認行為不適合你,你可以用WillOnce來指定每一次的返回值是什么,最后可以選用WillRepeatedly來結束。比如:

using?::testing::Return;...

EXPECT_CALL(turtle, GetX())

????.WillOnce(Return(100))

????.WillOnce(Return(200))

?.WillOnce(Return(300));

上面的意思是turtle.GetX()會被調用恰好3次,并分別返回100200300

using?::testing::Return;...

EXPECT_CALL(turtle, GetY())

.WillOnce(Return(100))

???.WillOnce(Return(200))

.WillRepeatedly(Return(300));

上面的意思是指turtle.GetY()將至少被調用2次,第一次返回100,第二次返回200,從第三次以后都返回300

當然,你如果你明確寫上Times()Google Mock不會去推斷cardinality了。如果你指定的cardinality大于WillOnce()子句的個數時會發生什么呢?嗯,當WillOnce()用完了之后,Google Mock會每次對函數采用默認行為。

????我們在WillOnce()里除了寫Return()我們還能做些什么呢?你可以用ReturnRef( variable ),或是調用一個預先定義好的函數,自己在Others中找吧。

重要提示:EXPECT_CALL()只對行為子句求一次值,盡管這個行為可能出現很多次。所以你必須小心這種副作用。下面的代碼的結果可能與你想的不太一樣。

int?n = 100;

EXPECT_CALL(turtle, GetX())

.Times(4)

.WillRepeatedly(Return(n++));

????它并不是依次返回100101102...,而是每次都返回100,因為n++只會被求一次值。類似的,Return(new Foo)EXPECT_CALL()求值時只會創建一個Foo對象,所以它會每次都返回相同的指針。如果你希望每次都看到不同的結果,你需要定義一個自定義行為,我們將在CookBook中指導你。

????現在又是一個小測驗的時候了!你認為下面的代碼是什么意思?

using?::testing::Return;...

EXPECT_CALL(turtle, GetY())

.Times(4)

.WillOnce(Return(100));

????顯然,turtle.Get()期望被調用4次。但如果你認為它每次都會返回100,那你就要再考慮一下了!記住,每次調用都會消耗一個WillOnce()子句,消耗完之后,就會使用默認行為。所以正確的答案是turtle.GetY()第一次返回100,以后每次都返回0,因為0是默認行為的返回值。

Using Multiple Expectations

????至今為止,我們只展示了如何使用單個期望。但是在現實中,你可能想指定來自不同Mock對象的Mock函數上的期望。

????默認情況下,當一個Mock函數被調用時,Google Mock會通過定義順序的逆序去查找期望,當找到一個與參數匹配的有效的期望時就停下來(?你可以把這個它想成是“老的規則覆蓋新的規則“?)。如果匹配的期望不能再接受更多的調用時,你就會收到一個超出上界的失敗,下面是一個例子:

using?::testing::_;...

EXPECT_CALL(turtle, Forward(_));??// #1

EXPECT_CALL(turtle, Forward(10))??// #2

????.Times(2);

如果Forward(10)被連續調用3次,第3次調用它會報出一個錯誤,因為最后一個匹配期望(#2)已經飽和了。但是如果第3次的Forward(10)替換為Forward(20),那它就不會報錯,因數現在#1將會是匹配的期望了。

邊注:為什么Google Mock會以逆序去匹配期望呢?原因是為了可以讓用戶開始時使用Mock對象的默認行為,或是一些比較松馳的匹配條件,然后寫一些更明確的期望。所以,如果你在同一個函數上有兩個期望,你當然是想先匹配更明確的期望,然后再匹配其它的,或是可以說明確的規則會隱藏更寬泛的規則。

Ordered vs Unordered Calls

????默認情況下,即使是在前一個期望沒有被匹配的情況下,一個期望仍然可以被匹配。換句話說,調用的匹配順序不會按照期望指定的順序去匹配。

????有時,你可能想讓所有的期望調用都以一個嚴格的順序來匹配,這在Google Mock中是很容易的:

using?::testing::InSequence;...

TEST(FooTest, DrawsLineSegment) {

??...

??{

????InSequence dummy;

?

????EXPECT_CALL(turtle, PenDown());

????EXPECT_CALL(turtle, Forward(100));

????EXPECT_CALL(turtle, PenUp());

??}

??Foo();

}

????創建InSequence的一個對象后,在這個對象作用域中的期望都會以順序存放,并要求調用以這個順序匹配。因為我們只是依賴這個對象的構造函數和析構函數來完成任務,所以對象的名字并不重要。

(?如果你只是關心某些調用的相對順序,而不是所有調用的順序?可以指定一個任意的相對順序嗎?答案是...可以!如果你比較心急,你可以在CookBook中找到相關的細節。)

All Expectations Are Sticky (Unless Said Otherwise)

????現在讓我們做一個小測驗,看你掌握Mock到什么程度了。你如何測試turtle恰好經過原點兩次?

????當你想出你的解法之后,看一下我們的答案比較一下(?先自己想,別作弊?)

using?::testing::_;...

EXPECT_CALL(turtle, GoTo(_, _))??// #1

????.Times(AnyNumber());

EXPECT_CALL(turtle, GoTo(0, 0))??// #2

.Times(2);

假設turtle.GoTo(0,0)被調用了3次。在第3次,Google Mock會找到參數匹配期望#2。因為我們想要的是恰好經過原點兩次,所以Google Mock會立即報告一個錯誤。上面的內容其實就是我們在“Using Multiple Expectations”中說過的。

????上面的例子說明了Google Mock默認情況下期望是嚴格的,即是指期望在達到它們指定的調用次數上界后仍然是有效的。這是一個很重要的規則,因為它影響著指定的意義,而且這種規則與許多別的Mock框架中是不一樣(?我們為什么會設計的不一樣?因為我們認為我們的規則會使一般的用例更容易表達和理解?)

????簡單?讓我看一下你是不是真懂了:下面的代碼是什么意思:

using?::testing::Return;

...

for?(int?i = n; i > 0; i--) {

??EXPECT_CALL(turtle, GetX())

??????.WillOnce(Return(10*i));

}

????如果你認為turtle.GetX()會被調用n次,并依次返回10, 20, 30, ...,唉,你還是再想想吧!問題是,我們都說過了,期望是嚴格的。所以第2turtle.GetX()被調用時,最后一個EXPECT_CALL()會被匹配,所以馬上會引起“超出上界”的錯誤。上面的代碼其實沒什么用途。

????一個正確表達turtle.GetX()返回10, 20, 30,...,的方法是明確地說明期望不是嚴格的。換句話說,在期望飽和之后就失效。

using?::testing::Return;

...

for?(int?i = n; i > 0; i--) {

??EXPECT_CALL(turtle, GetX())

????.WillOnce(Return(10*i))

????.RetiresOnSaturation();

}

????并且,有一個更好的解決方法,在這個例子中,我們期望調用以特定順序執行。因為順序是一個重要的因素,我們應該用InSequence明確地表達出順序:

using?::testing::InSequence;

using?::testing::Return;

...

{

??InSequence s;

?

??for?(int?i = 1; i <= n; i++) {

????EXPECT_CALL(turtle, GetX())

????????.WillOnce(Return(10*i))

????????.RetiresOnSaturation();

??}

}

????順便說一下,另一個期望可能不嚴格的情況是當它在一個順序中,當這個期望飽和后,它就自動失效,從而讓下一個期望有效。

Uninteresting Calls

????一個Mock對象可能有很多函數,但并不是所有的函數你都關心。比如,在一些測試中,你可能不關心GetX()GetY()被調用多少次。

????Google Mock中,你如果不關心一個函數,很簡單,你什么也不寫就可以了。如果這個函數的調用發生了,你會看到測試輸出一個警告,但它不會是一個失敗。

What Now?

????恭喜!你已經學習了足夠的Google Mock的知識了,你可以開始使用它了。現在你也許想加入googlemock討論組,并開始真正地用Google Mock開始寫一些測試——它是很有意思的,嗨,這可能是會上癮的,我可是警告過你了喔!

????如果你想提高你的Mock等級,你可以移步至CookBook。你可以在那學習更多的Google Mock高級特性——并提高你的幸福指數和測試快樂級別。

Copyright notice

???? 所有的內容全部翻譯自 Google 的文檔 Google C++ Mocking Framework for Dummies Koala++/ 屈偉 ?

總結

以上是生活随笔為你收集整理的Google Mock启蒙篇 [2] (Google C++ Mocking Framework for Dummies 翻译)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。