Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上
本文是gtest高級(jí)測(cè)試指南的譯文,由于文章太長(zhǎng),分上下兩部分。
一、簡(jiǎn)介
? ?本文檔將向您展示更多的斷言,以及如何構(gòu)造復(fù)雜的失敗消息,傳播致命的故障,重用和加速您的測(cè)試夾具,并在您的測(cè)試使用各種標(biāo)志。
二、更多斷言
? 本節(jié)包括一些不太常用,但仍然重要的斷言。
? 2.1 顯式成功和失敗
? 這三個(gè)斷言實(shí)際上不測(cè)試值或表達(dá)式。 相反,它們直接產(chǎn)生成功或失敗。 與實(shí)際執(zhí)行測(cè)試的宏類似,您可以將自定義失敗消息流入它們。
SUCCEED();生成成功。 這不會(huì)使整體測(cè)試成功。 只有當(dāng)測(cè)試在其執(zhí)行期間沒有任何斷言失敗時(shí),測(cè)試才被認(rèn)為是成功的。
注意:SUCCEED()是純紀(jì)錄片,目前不生成任何用戶可見的輸出。 但是,我們可能會(huì)在未來向Google Test的輸出中添加SUCCEED()消息。
FAIL(); ADD_FAILURE(); ADD_FAILURE_AT("file_path",line_number);FAIL()產(chǎn)生致命故障,而ADD_FAILURE()和ADD_FAILURE_AT()產(chǎn)生非致命故障。 當(dāng)控制流而不是布爾表達(dá)式確定測(cè)試的成功或失敗時(shí),這些是有用的。 例如,您可能想要寫如下:
switch(expression) {case 1: ... some checks ...case 2: ... some other checks...default: FAIL() << "We shouldn't get here."; }注意:你只能在返回void的函數(shù)中使用FAIL()。 有關(guān)詳細(xì)信息,請(qǐng)參閱?Assertion Placement section?部分。
?2.2 異常斷言
這些用于驗(yàn)證一段代碼拋出(或不拋出)給定類型的異常:
| 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 |
Examples:
ASSERT_THROW(Foo(5), bar_exception);EXPECT_NO_THROW({int n = 5;Bar(&n); });三、更好的錯(cuò)誤消息的謂詞斷言
雖然Google測(cè)試有一套豐富的斷言,但它們永遠(yuǎn)不可能完整,因?yàn)樗豢赡?#xff08;也不是一個(gè)好主意)預(yù)測(cè)用戶可能遇到的所有情況。 因此,有時(shí)用戶必須使用EXPECT_TRUE()來檢查復(fù)雜表達(dá)式,因?yàn)槿鄙俑玫暮辍?這有一個(gè)問題,沒有顯示你的表達(dá)式的部分的值,使得很難理解什么錯(cuò)誤。 作為解決方法,一些用戶選擇自己構(gòu)造失敗消息,將其流式傳輸?shù)紼XPECT_TRUE()。 然而,這是尷尬,特別是當(dāng)表達(dá)式有副作用或評(píng)價(jià)昂貴。
Google測(cè)試提供三種不同的選項(xiàng)來解決這個(gè)問題:
?3.1使用現(xiàn)有的布爾函數(shù)
如果你已經(jīng)有一個(gè)函數(shù)或函數(shù)返回bool(或一個(gè)可以隱式轉(zhuǎn)換為bool的類型),你可以在謂詞斷言中使用它來獲得免費(fèi)打印的函數(shù)參數(shù):
| 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 |
| ... | ... | ... |
在上面,predn是一個(gè)n元謂詞函數(shù)或函子,其中val1,val2,...和valn是它的參數(shù)。 如果謂詞在應(yīng)用于給定參數(shù)時(shí)返回true,則斷言成功,否則失敗。 當(dāng)斷言失敗時(shí),它打印每個(gè)參數(shù)的值。 在任何一種情況下,參數(shù)只計(jì)算一次。
Here's an example:
// Returns true iff m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10;斷言EXPECT_PRED2(Mutual Prime,a,b); 將成功,而斷言EXPECT_PRED2(MutuallyPrime,b,c); 將失敗。
!MutuallyPrime(b, c) is false, whereb is 4c is 10注意:
?1. 如果在使用ASSERT_PRED *或EXPECT_PRED *時(shí)看到編譯器錯(cuò)誤“no matching function to call(無匹配函數(shù)調(diào)用)”,請(qǐng)參閱此常見問題解答?this FAQ?以了解如何解決它。
?2. 目前我們只提供arity <= 5的謂詞斷言。如果你需要更高級(jí)的斷言,讓我們知道。
3.2 使用返回AssertionResult的函數(shù)
雖然EXPECT_PRED *()和friends對(duì)快速工作很方便,但是語(yǔ)法不令人滿意:你必須使用不同的宏不同的arities,它感覺更像Lisp而不是C ++。 :: testing :: AssertionResult類解決了這個(gè)問題。
AssertionResult對(duì)象表示斷言的結(jié)果(無論它是成功還是失敗,以及相關(guān)聯(lián)的消息)。 您可以使用以下工廠函數(shù)之一創(chuàng)建AssertionResult:
namespace testing {// Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess();// Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure();}然后,您可以使用<<運(yùn)算符將消息流式傳輸?shù)紸ssertionResult對(duì)象。
要在布爾斷言(例如EXPECT_TRUE())中提供更多可讀消息,請(qǐng)編寫一個(gè)返回AssertionResult而不是bool的謂詞函數(shù)。 例如,如果您將IsEven()定義為:
::testing::AssertionResult IsEven(int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess();elsereturn ::testing::AssertionFailure() << n << " is odd"; }而不是:
bool IsEven(int n) {return (n % 2) == 0; }the failed assertion?EXPECT_TRUE(IsEven(Fib(4)))?will print:
Value of: IsEven(Fib(4))Actual: false (*3 is odd*)Expected: trueinstead of a more opaque:
Value of: IsEven(Fib(4))Actual: falseExpected: true如果您希望在EXPECT FALSE和ASSERT_FALSE中看到提供信息的消息,并且在成功的情況下使謂詞變慢,您可以提供一個(gè)成功消息:
::testing::AssertionResult IsEven(int n) {if ((n % 2) == 0)return ::testing::AssertionSuccess() << n << " is even";elsereturn ::testing::AssertionFailure() << n << " is odd"; }Then the statement?EXPECT_FALSE(IsEven(Fib(6)))?will print
Value of: IsEven(Fib(6))Actual: true (8 is even)Expected: false3.3 使用謂詞格式化
? ?如果你發(fā)現(xiàn)由(ASSERT | EXPECT)_PRED *和(ASSERT | EXPECT)_(TRUE | FALSE)生成的默認(rèn)消息不令人滿意,或者您的謂詞的某些參數(shù)不支持流到ostream,您可以使用以下謂詞 - 格式化程序斷言 以完全自定義消息的格式化:
| 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 |
| ... | ... | ... |
這和前兩組宏的區(qū)別是,不是一個(gè)謂詞,(ASSERT | EXPECT)_PRED_FORMAT *采用謂詞格式化器(pred_formatn),它是一個(gè)函數(shù)或函數(shù)簽名:
::testing::AssertionResult PredicateFormattern(const char*expr1, const char*expr2, ... const char*exprn, T1val1, T2val2, ... Tnvaln);四、浮點(diǎn)比較
比較浮點(diǎn)數(shù)是棘手的。 由于舍入誤差,兩個(gè)浮點(diǎn)不太可能完全匹配。 因此,ASSERT_EQ的幼稚比較通常不起作用。 并且由于浮點(diǎn)可以具有寬的值范圍,沒有單個(gè)固定誤差界限工作。 最好通過固定的相對(duì)誤差界限進(jìn)行比較,除了接近0的值由于精度的損失。
一般來說,對(duì)于浮點(diǎn)比較有意義,用戶需要仔細(xì)選擇誤差界限。 如果他們不想要或關(guān)心,根據(jù)最后地點(diǎn)(ULP)中的單位進(jìn)行比較是一個(gè)很好的默認(rèn)值,Google測(cè)試提供了斷言來做到這一點(diǎn)。 關(guān)于ULP的完整詳細(xì)信息相當(dāng)長(zhǎng); 如果你想了解更多,請(qǐng)參閱這篇關(guān)于浮動(dòng)比較的文章?this article on float comparison.。
Floating-Point Macros
| ASSERT_FLOAT_EQ(val1, val2); | EXPECT_FLOAT_EQ(val1, val2); | the two?float?values are almost equal |
| ASSERT_DOUBLE_EQ(val1, val2); | EXPECT_DOUBLE_EQ(val1, val2); | the two?double?values are almost equal |
“幾乎相等”是指兩個(gè)值彼此在4個(gè)ULP內(nèi)。
以下斷言允許您選擇可接受的誤差界限:
| 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í)再去看。
五、Windows HRESULT斷言
這些斷言測(cè)試HRESULT成功或失敗。
| 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 |
生成的輸出包含與expression返回的HRESULT代碼相關(guān)聯(lián)的人工可讀錯(cuò)誤消息。
You might use them like this:
CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty));六、類型斷言
?
::testing::StaticAssertTypeEq<T1, T2>();您可以調(diào)用該函數(shù),來聲稱斷言類型T1和T2是相同的。 如果滿足斷言,該函數(shù)不執(zhí)行任何操作。 如果類型不同,函數(shù)調(diào)用將無法編譯,編譯器錯(cuò)誤消息(取決于編譯器)將顯示T1和T2的實(shí)際值。 這主要在模板代碼中有用。
注意:當(dāng)在類模板或函數(shù)模板的成員函數(shù)中使用時(shí),StaticAssertTypeEq <T1,T2>()僅在函數(shù)實(shí)例化時(shí)有效。 例如,給定:
template <typename T> class Foo {public:void Bar() { ::testing::StaticAssertTypeEq<int, T>(); } };the code:
void Test1() { Foo<bool> foo; }將不會(huì)生成編譯器錯(cuò)誤,因?yàn)镕oo <bool> :: Bar()永遠(yuǎn)不會(huì)實(shí)際實(shí)例化。 相反,您需要:
void Test2() { Foo<bool> foo; foo.Bar(); }導(dǎo)致編譯器錯(cuò)誤。
七、Assertion Placement(斷言放置)
你可以在任何C ++函數(shù)中使用斷言。 特別地,它不必是測(cè)試夾具類的方法。 一個(gè)約束是生成致命故障(FAIL *和ASSERT_ *)的斷言只能在void返回函數(shù)中使用。 這是Google測(cè)試不使用exceptions的后果。 如果將它放在一個(gè)非void函數(shù)中,你會(huì)得到一個(gè)令人困惑的編譯錯(cuò)誤,如“error: void value not ignored as it ought to be”。
如果需要在返回非void的函數(shù)中使用斷言,一個(gè)選項(xiàng)是使函數(shù)返回out參數(shù)中的值。 例如,您可以將T2 Foo(T1 x)重寫為void Foo(T1 x,T2 * result)。 你需要確保* result包含一些合理的值,即使該函數(shù)過早返回。 由于函數(shù)現(xiàn)在返回void,你可以在它里面使用任何斷言。
如果更改函數(shù)的類型不是一個(gè)選項(xiàng),則應(yīng)該使用生成非致命失敗的斷言,例如ADD_FAILURE *和EXPECT_ *。
注意:根據(jù)C ++語(yǔ)言規(guī)范,構(gòu)造函數(shù)和析構(gòu)函數(shù)不被視為void返回函數(shù),因此您不能在其中使用致命斷言。 如果你嘗試,你會(huì)得到一個(gè)編譯錯(cuò)誤。 一個(gè)簡(jiǎn)單的解決方法是將構(gòu)造函數(shù)或析構(gòu)函數(shù)的整個(gè)體轉(zhuǎn)移到私有void返回方法。 然而,你應(yīng)該意識(shí)到,構(gòu)造函數(shù)中的致命斷言失敗并不會(huì)終止當(dāng)前的測(cè)試,正如你的直覺所暗示的那樣; 它只是從構(gòu)造函數(shù)早期返回,可能使您的對(duì)象處于部分構(gòu)造狀態(tài)。 同樣,析構(gòu)函數(shù)中的致命斷言失敗可能使您的對(duì)象處于部分破壞狀態(tài)。 在這些情況下仔細(xì)使用斷言!
八、教學(xué)Google測(cè)試如何打印您的值
當(dāng)測(cè)試聲明(如EXPECT_EQ)失敗時(shí),Google Test會(huì)打印參數(shù)值以幫助您調(diào)試。 它使用用戶可擴(kuò)展值打印機(jī)。
此打印機(jī)知道如何打印內(nèi)置的C ++類型,native數(shù)組,STL容器和任何支持<<運(yùn)算符的類型。 對(duì)于其他類型,它打印值中的原始字節(jié),并希望用戶可以計(jì)算出來。
如前所述,打印機(jī)是可擴(kuò)展的。 這意味著你可以教它做一個(gè)更好的工作,打印你的特定類型,而不是轉(zhuǎn)儲(chǔ)字節(jié)。 要做到這一點(diǎn),定義<<您的類型:
#include <iostream>namespace foo {class Bar { ... }; // We want Google Test to be able to print instances of this.// It's important that the << operator is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. ::std::ostream& operator<<(::std::ostream& os, const Bar& bar) {return os << bar.DebugString(); // whatever needed to print bar to os }} // namespace foo有時(shí),這可能不是一個(gè)選項(xiàng):你的團(tuán)隊(duì)可能認(rèn)為它的壞風(fēng)格有一個(gè)<<運(yùn)算符的Bar,或者Bar可能已經(jīng)有一個(gè)<<運(yùn)算符,不做你想要的(你不能改變它)。 如果是這樣,您可以定義一個(gè)PrintTo()函數(shù),如下所示:
#include <iostream>namespace foo {class Bar { ... };// It's important that PrintTo() is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. void PrintTo(const Bar& bar, ::std::ostream* os) {*os << bar.DebugString(); // whatever needed to print bar to os }} // namespace foo如果您定義了<<和PrintTo(),后者將在Google測(cè)試時(shí)使用。 這允許您自定義值如何顯示在Google測(cè)試的輸出中,而不影響依賴于其<<運(yùn)算符的行為的代碼。
如果你想使用Google Test的值打印機(jī)自己打印一個(gè)值x,只需調(diào)用:: testing :: PrintToString(x),它返回一個(gè)std :: string:
vector<pair<Bar, int> > bar_ints = GetBarIntVector();EXPECT_TRUE(IsCorrectBarIntVector(bar_ints))<< "bar_ints = " << ::testing::PrintToString(bar_ints);Extending Google Test by Handling Test Events
這個(gè)挺復(fù)雜,寫在單獨(dú)的文檔中:?http://www.cnblogs.com/jycboy/p/gtest_handlingEvent.html
?
轉(zhuǎn)載請(qǐng)注明出處:http://www.cnblogs.com/jycboy/p/gtest_AdvancedGuide.html
?
轉(zhuǎn)載于:https://www.cnblogs.com/jycboy/p/gtest_AdvancedGuide.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的Google C++单元测试框架GoogleTest---AdvancedGuide(译文)上的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux(八)__yum工具
- 下一篇: C++11 笔记