一、前言
這篇文章主要參考 玩轉Google開源C++單元測試框架Google Test系列(gtest)之二 - 斷言 ,結合自己平時使用的Linux環境適當刪減修改。
Assertion引發的三種結果
Assertions會引發3種結果:success、Non-Fatal Failure、Fatal Failure
Non-Fatal Failure 和 Fatal Failure啥區別?
前者失敗后還會繼續執行,后者失敗后停止執行。ASSERT_* 系列的斷言屬於fatal assertion,EXPECT_* 系列的斷言屬於nonfatal assertion。
二、示例
#include <cstdio> #include <gtest/gtest.h> int Add(const int& a, const int& b) { return a + b; } namespace { TEST(AddTest, test_001) { EXPECT_EQ(4, Add(1 , 2)); } } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
假如你的Add(1, 2) 結果為4的話,會在結果中輸出:

[==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from AddTest [ RUN ] AddTest.test_001 /root/projects/Gtest_assertion/main.cpp:10: Failure Expected equality of these values: 4 Add(1 , 2) Which is: 3 [ FAILED ] AddTest.test_001 (0 ms) [----------] 1 test from AddTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (1 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] AddTest.test_001 1 FAILED TEST
如果是將結果輸出到xml里的話,將輸出:(關於將結果輸出為xml,見:http://www.cnblogs.com/coderzh/archive/2009/04/10/1432789.html)
由於我使用的環境是VS2017遠程連接Linux開發,所有代碼最終還是在Linux上面,VS里面沒有辦法指定--gtest_output,我只能在Linux上面手動指定
Gtest_assertion.out --gtest_output="xml:report.xml"

[root@1708 Debug]# cat report.xml <?xml version="1.0" encoding="UTF-8"?> <testsuites tests="1" failures="1" disabled="0" errors="0" timestamp="2019-01-05T19:36:28" time="0.001" name="AllTests"> <testsuite name="AddTest" tests="1" failures="1" disabled="0" errors="0" time="0.001"> <testcase name="test_001" status="run" time="0.001" classname="AddTest"> <failure message="/root/projects/Gtest_assertion/main.cpp:10 Expected equality of these values: 4 Add(1 , 2) Which is: 3" type=""><![CDATA[/root/projects/Gtest_assertion/main.cpp:10 Expected equality of these values: 4 Add(1 , 2) Which is: 3]]></failure> </testcase> </testsuite> </testsuites>
如果你對自動輸出的出錯信息不滿意的話,你還可以通過操作符<<將一些自定義的信息輸出,通常,這對於調試或是對一些檢查點的補充說明來說,非常有用!
改進上面代碼

#include <cstdio> #include <gtest/gtest.h> int Add(const int& a, const int& b) { return a + b; } namespace { TEST(AddTest, test_001) { EXPECT_EQ(4, Add(1 , 2)) << "Add(1 , 2)= " << Add(1, 2); } } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }
使用<<操作符將一些重要信息輸出的話:

[==========] Running 1 test from 1 test case. [----------] Global test environment set-up. [----------] 1 test from AddTest [ RUN ] AddTest.test_001 /root/projects/Gtest_assertion/main.cpp:10: Failure Expected equality of these values: 4 Add(1 , 2) Which is: 3 Add(1 , 2)= 3 [ FAILED ] AddTest.test_001 (0 ms) [----------] 1 test from AddTest (0 ms total) [----------] Global test environment tear-down [==========] 1 test from 1 test case ran. (0 ms total) [ PASSED ] 0 tests. [ FAILED ] 1 test, listed below: [ FAILED ] AddTest.test_001 1 FAILED TEST
三、布爾值檢查
Fatal assertion | Nonfatal assertion | Verifies |
ASSERT_TRUE(condition); | EXPECT_TRUE(condition); | condition is true |
ASSERT_FALSE(condition); | EXPECT_FALSE(condition); | condition is false |
四、數值型數據檢查
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*同時支持char*和wchar_t*類型的,*STRCASEEQ*和*STRCASENE*卻只接收char*,估計是不常用吧。下面是幾個例子:

TEST(StringCmpTest, Demo) { char* pszCoderZh = "CoderZh"; wchar_t* wszCoderZh = L"CoderZh"; std::string strCoderZh = "CoderZh"; std::wstring wstrCoderZh = 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();
直接返回成功:
生成成功。 這不會使整體測試成功。 只有當測試在其執行期間沒有任何斷言失敗時,測試才被認為是成功的。
注意:SUCCEED() is purely documentary,目前不生成任何用戶可見的輸出。 但是,我們可能會在未來向Google Test的輸出中添加SUCCEED()消息
Fatal assertion | Nonfatal assertion | Nonfatal assertion |
FAIL(); | ADD_FAILURE(); | ADD_FAILURE_AT("file_path",line_number); |
FAIL()產生致命故障,而ADD_FAILURE()和ADD_FAILURE_AT()產生非致命故障。
如果用於控制流程而不是單純判斷boolean expression,這3個宏會很有用。代碼如下

TEST(ExplicitTest, Demo) { ADD_FAILURE() << "Sorry"; // None Fatal Asserton,繼續往下執行。 //FAIL(); // Fatal Assertion,不往下執行該案例。 SUCCEED(); }
注意:你只能在返回void的函數中使用FAIL()。 有關詳細信息,請參閱 Assertion Placement section 部分。
七、異常斷言
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 |
例如:

int Foo(int a, int b) { if (a == 0 || b == 0) { throw "don't do that"; } int c = a % b; if (c == 0) return b; return Foo(b, c); } TEST(FooTest, HandleZeroInput) { EXPECT_ANY_THROW(Foo(10, 0)); EXPECT_THROW(Foo(0, 5), char*); }
八、Predicate Assertions for Better Error Messages
盡管Google Test擁有豐富的斷言,但它們永遠不會完整,因為預測用戶可能遇到的所有場景是不可能的(也不是一個好主意)。因此,有時用戶必須使用EXPECT_TRUE()來檢查復雜表達式,因為缺少更好的宏。這樣做有個問題,EXPECT_TRUE()沒有顯示表達式部分的值,這使你很難理解出錯的地方。作為一種解決方法,一些用戶選擇自己構造失敗消息,將其流式傳輸到EXPECT_TRUE()。但是當表達式有副作用(side-effects)又或者計算費時 ,可能會導致某些奇怪問題。
Gtest提供了3種不同方式解決這個問題。
使用現有的布爾函數
如果你已經有一個function或functor返回bool(或一個可以隱式轉換為bool的類型),你可以在謂詞斷言(predicate assertion)中不受任何限制的打印出函數參數。
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 |
... | ... | ... |
在上面,predn是一個n元predicate function 或 functor,,其中val1,val2,...和valn是它的參數。 如果謂詞(predicate )在應用於給定參數時返回true,則斷言成功,否則失敗。 當斷言失敗時,它打印每個參數的值。 在任何一種情況下,參數只計算一次。
Here's an example:
//如果m和n沒有除1之外的公約數,則返回true。 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, where b is 4 c is 10
注意:
1. 如果在使用ASSERT_PRED *或EXPECT_PRED *時看到編譯器錯誤“no matching function to call(無匹配函數調用)”,請參閱此常見問題解答 this FAQ 以了解如何解決它。
2. 目前我們只提供 <= 5個參數的的predicate assertions。
使用返回AssertionResult的函數
雖然EXPECT_PRED*() and friends對快速工作很方便,但是語法不令人滿意:應對不同情況你必須使用不同的宏,它感覺更像Lisp而不是C ++。 :: testing :: AssertionResult類解決了這個問題。
AssertionResult對象表示斷言的結果(無論它是成功還是失敗,以及相關聯的消息)。 您可以使用以下工廠函數之一創建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(); }
你可以使用<<運算符將消息流式傳輸到AssertionResult對象。
要在布爾斷言(例如EXPECT_TRUE())中提供更多可讀消息,請編寫一個返回AssertionResult而不是bool的謂詞函數。 例如,如果您將IsEven()定義為:
::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; }
而不是
bool IsEven(int n) { return (n % 2) == 0; }
針對EXPECT_TRUE(IsEven(Fib(4)))錯誤的斷言將要輸出
Value of: IsEven(Fib(4)) Actual: false (*3 is odd*) Expected: true
而不是這種特別模糊的輸出
Value of: IsEven(Fib(4)) Actual: false Expected: true
如果想要在EXPECT_FALSE and ASSERT_FALSE中也輸出大量有用信息們可以這樣做
::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; }
EXPECT_FALSE(IsEven(Fib(6)))將會打印輸出
Value of: IsEven(Fib(6)) Actual: true (8 is even) Expected: false
使用謂詞格式化(Predicate-Formatter)
如果你發現由(ASSERT | EXPECT)_PRED *和(ASSERT | EXPECT)_(TRUE | FALSE)生成的默認消息不令人滿意,或者您的predicate的某些參數不支持流到ostream,您可以使用以下predicate-formatter assertions來完全定義消息的格式:
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 |
... |
... |
... |
這和(ASSERT | EXPECT)_PRED *宏的區別是,這一節講的宏不是一個謂詞,(ASSERT | EXPECT)_PRED_FORMAT *接收一個predicate-formatter(pred_formatn),它是一個函數或函數簽名
::testing::AssertionResult PredicateFormattern(const char*expr1, const char*expr2, ... const char*exprn, T1 val1, T2 val2, ... Tn valn);
val1, val2, ..., 和valn 是predicate arguments的值。expr1, expr2, ..., 和 exprn是出現在代碼中相應的表達式。T1, T2, ..., 和Tn可以試值類型,也可以是引用類型。舉例來說,如果一個參數的類型是Foo,你把T*設置成Foo或const Foo&都可以。
predicate-formatter返回一個::testing::AssertionResult對象用於指明斷言(assertion)成功與否,創建::testing::AssertionResult對象的唯一方式是使用下列工廠函數(factory functions)
一個例子,改善之前使用EXPECT_PRED2()那個例子的錯誤信息
// Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); }
借助predicate-formatter,我們可以使用
EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c);
會生成消息
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
事實上前面引入的許多斷言都是(EXPECT|ASSERT)_PRED_FORMAT*的特例,他們中大多數也是使用(EXPECT|ASSERT)_PRED_FORMAT*.定義的。
九、浮點型檢查
比較浮點數是棘手的。 由於舍入誤差,兩個浮點不太可能完全匹配。 因此,ASSERT_EQ的較傻的比較通常不起作用。 並且由於浮點可以具有寬的值范圍,沒有單個固定誤差界限工作。 最好通過固定的相對誤差界限進行比較,除了接近0的值由於精度的損失。
一般來說,對於浮點比較有意義,用戶需要仔細選擇誤差界限。 如果他們不想要或關心,根據最后地點(ULP)中的單位進行比較是一個很好的默認值,Google測試提供了斷言來做到這一點。 關於ULP的完整詳細信息相當長; 如果你想了解更多,請參閱這篇關於浮動比較的文章 this article on float comparison.。
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 |
對相近的兩個數比較:
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 |
同時,還可以使用:
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 |
例如:
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>();
來聲稱斷言類型T1和T2是相同的。 如果滿足斷言,該函數不執行任何操作。 如果類型不同,函數調用將無法編譯,編譯器錯誤消息(取決於編譯器)將顯示T1和T2的實際值。 這主要在模板代碼中有用。
注意:當在類模板或函數模板的成員函數中使用時,StaticAssertTypeEq <T1,T2>()僅在函數實例化時有效。 例如,給定:
template <typename T> class Foo { public: void Bar() { ::testing::StaticAssertTypeEq<int, T>(); } };
the code:
void Test1() { Foo<bool> foo; }
將不會生成編譯器錯誤,因為Foo <bool> :: Bar()永遠不會實際實例化。 相反,您需要:
void Test2() { Foo<bool> foo; foo.Bar(); }
導致編譯器錯誤。
暫時用到的就這些,剩下的參考:
Gtest AdvancedGuide 對於國內譯文 Google C++單元測試框架GoogleTest---AdvancedGuide(譯文)上 (疑問有多處翻譯bug,看的時候別全信)
其他文章:
專題: