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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

Google Test(GTest)使用方法和源码解析——断言的使用方法和解析

發布時間:2023/11/27 生活经验 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google Test(GTest)使用方法和源码解析——断言的使用方法和解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 在之前博文的基礎上,我們將介紹部分斷言的使用,同時穿插一些源碼。(轉載請指明出于breaksoftware的csdn博客)

斷言(Assertions)

? ? ? ? 斷言是GTest局部測試中最簡單的使用方法,我們之前博文中舉得例子都是使用斷言去做判斷的。

基礎斷言

? ? ? ? 我們先看一個基礎的斷言

Fatal assertionNonfatal assertionVerifies
ASSERT_TRUE(condition);EXPECT_TRUE(condition);condition is true
ASSERT_FALSE(condition);EXPECT_FALSE(condition);condition is false

? ? ? ? GTest中斷言都是成對出現的。即分為兩個系列:

  1. ASSERT_*系列;
  2. EXPECT_*系列;

? ? ? ? EXPECT_*系列是比較常用的。在一個測試特例中,如果局部測試使用了EXPECT_*系列函數,它將保證本次局部測試結果不會影響之后的流程。但是ASSERT_*系列在出錯的情況下,當前測試特例中剩下的流程就不走了。

TEST(BaseCheck, Assert) {ASSERT_TRUE(1==1);ASSERT_TRUE(2==3);ASSERT_TRUE(3==3);
}
TEST(BaseCheck, Expect) {EXPECT_TRUE(1==1);EXPECT_TRUE(2==3);EXPECT_TRUE(3==3);
}

? ? ? ? 上面兩個測試特例中,第二個局部測試都是不成立的。由于EXPECT_*不會影響執行流程,所以即使第8行出錯,之后的流程(第9行)也執行了。但是ASSERT_*會影響,所以第3行出錯后,第4行沒有執行。那么GTest是如何做到的呢?我們對比下EXPECT_TRUE和ASSERT_TRUE的實現

#define EXPECT_TRUE(condition) \GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \GTEST_NONFATAL_FAILURE_)
#define ASSERT_TRUE(condition) \GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \GTEST_FATAL_FAILURE_)

? ? ? ? 可以見得,他們的區別就是在是出錯時調用了GTEST_NONFATAL_FAILURE_還是GTEST_FATAL_FAILURE_

#define GTEST_FATAL_FAILURE_(message) \return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure)#define GTEST_NONFATAL_FAILURE_(message) \GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure)

? ? ? ? 這兒調用到《Google Test(GTest)使用方法和源碼解析——結果統計機制分析》中介紹保存局部測試結果的宏——GTEST_MESSAGE_。但是這個不是重點,重點是GTEST_FATAL_FAILURE_宏調用了return——函數返回了。我們再看下GTEST_TEST_BOOLEAN_的實現

#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (const ::testing::AssertionResult gtest_ar_ = \::testing::AssertionResult(expression)) \; \else \fail(::testing::internal::GetBoolAssertionFailureMessage(\gtest_ar_, text, #actual, #expected).c_str())

? ? ? ? 在出錯的情況下,ASSERT_*的else里return了。而EXPECT_*的else沒有return。

二進制比較斷言

? ? ? ? GTest還提供了二進制對比宏

Fatal assertionNonfatal assertionVerifies全稱
ASSERT_EQ(val1,val2);EXPECT_EQ(val1,val2);val1 == val2equal
ASSERT_NE(val1,val2);EXPECT_NE(val1,val2);val1 != val2not equal
ASSERT_LT(val1,val2);EXPECT_LT(val1,val2);val1 < val2less than
ASSERT_LE(val1,val2);EXPECT_LE(val1,val2);val1 <= val2less equal
ASSERT_GT(val1,val2);EXPECT_GT(val1,val2);val1 > val2big than
ASSERT_GE(val1,val2);EXPECT_GE(val1,val2);val1 >= val2big equal

? ? ? ? 雖然宏很多,但是還是很好記,大家只要記住全稱那列,就知道怎么對應關系了。我們再查看下二進制對比系列宏的ASSERT_*和EXPECT_*的區別(以EQ為例)

#define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2)
#define GTEST_ASSERT_EQ(val1, val2) \ASSERT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
#define EXPECT_EQ(val1, val2) \EXPECT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
// Binary predicate assertion macros.
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
#define EXPECT_PRED2(pred, v1, v2) \GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
#define ASSERT_PRED2(pred, v1, v2) \GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)

? ? ? ? 可以見得它們和基本斷言一樣——EXPECT在失敗的情況下沒有return(失敗時調用了GTEST_NONFATAL_FAILURE_),而ASSERT在失敗的情況下return掉了(失敗時調用了GTEST_FATAL_FAILURE_)。

? ? ? ? 一般來說二進制比較,都是對比其結構體所在內存的內容。C++大部分原生類型都是可以使用二進制對比的。但是對于自定義類型,我們就要定義一些操作符的行為,比如=、<等,我這兒就不舉例了。

字符串對比斷言

? ? ? ? 對于string類型,可以使用如下宏

Fatal assertionNonfatal assertionVerifies全稱
ASSERT_STREQ(str1,str2);EXPECT_STREQ(str1,_str_2);the two C strings have the same contentstring equal
ASSERT_STRNE(str1,str2);EXPECT_STRNE(str1,str2);the two C strings have different contentstring not equal
ASSERT_STRCASEEQ(str1,str2);EXPECT_STRCASEEQ(str1,str2);the two C strings have the same content, ignoring casestring (ignoring) case equal
ASSERT_STRCASENE(str1,str2);EXPECT_STRCASENE(str1,str2);the two C strings have different content, ignoring casestring (ignoring) case not euqal

? ? ? ? 在源碼上,string對比宏和二進制對比只是在對比函數的選擇上有差異,以Equal為例

#define EXPECT_EQ(val1, val2) \EXPECT_PRED_FORMAT2(::testing::internal:: \EqHelper<GTEST_IS_NULL_LITERAL_(val1)>::Compare, \val1, val2)
#define EXPECT_STREQ(s1, s2) \EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2)

浮點對比斷言

? ? ? ??在對比數據方面,我們往往會討論到浮點數的對比。因為在一些情況下,浮點數的計算精度將影響對比結果,所以這塊都會單獨拿出來說。GTest對于浮點數的對比也是單獨的

Fatal assertionNonfatal assertionVerifies
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

? ? ? ? almost euqal表示兩個數只是近似相似,默認的是是指兩者的差值在4ULP之內(Units in the Last Place)。我們還可以自己制定精度

Fatal assertionNonfatal assertionVerifies
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

? ? ? ? 使用方法是

  ASSERT_NEAR(-1.0f, -1.1f, 0.2f);ASSERT_NEAR(2.0f, 3.0f, 1.0f);

? ? ? ? 對于浮點數的比較,感興趣的同學可以查看下GTest的源碼,還是有點意思的。

成功失敗斷言

? ? ? ? 該類斷言用于直接標記是否成功或者失敗??梢允褂肧UCCEED()宏標記成功,使用FAIL()宏標記致命錯誤(同ASSERT_*),ADD_FAILURE()宏標記非致命錯誤(同EXPECT_*)。舉個例子

if (Check) {SUCCEED();
}
else {FAIL();
}

? ? ? ? 我們直接在自己的判斷下設置斷言。這兒有個地方需要說一下,SUCCEED()宏會調用GTEST_MESSAGE_AT_宏,從而會影響TestResult的test_part_results結構體,這也是唯一的成功情況下影響該結構體的地方。詳細的分析可以見《Google Test(GTest)使用方法和源碼解析——結果統計機制分析》。

類型對比斷言

? ? ? ? 該類斷言只有一個::testing::StaticAssertTypeEq<T, T>()。當類型相同時,它不會執行任何內容。如果不同則會引起編譯錯誤。但是需要注意的是,要使代碼觸發編譯器推導類型,否則也會發生編譯錯誤。如

template <typename T> class Foo {public:void Bar() { ::testing::StaticAssertTypeEq<int, T>(); }
};

? ? ? ? 如下的代碼就不會引起編譯沖突

void Test1() { Foo<bool> foo; }

? ? ? ? 但是下面的代碼由于引發了編譯器的類型推導,所以會觸發編譯錯誤

void Test2() { Foo<bool> foo; foo.Bar(); }

異常斷言

? ? ? ? 異常斷言是在斷言中接收一定類型的異常,并轉換成斷言形式。它有如下幾種

Fatal assertionNonfatal assertionVerifies
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

? ? ? ? 我們舉一個例子

void ThrowException(int n) {switch (n) {case 0:throw 0;case 1:throw "const char*";case 2:throw 1.1f;case 3:return;}
}TEST(ThrowException, Check) {EXPECT_THROW(ThrowException(0), int);EXPECT_THROW(ThrowException(1), const char*);ASSERT_ANY_THROW(ThrowException(2)); ASSERT_NO_THROW(ThrowException(3));  
}

? ? ? ? 這組測試特例中,我們預期ThrowException在傳入0時,會返回int型異常;傳入1時,會返回const char*異常。傳入2時,會返回異常,但是異常類型我們并不關心。傳入3時,不返回任何異常。當然ThrowExeception的實現也是按以上預期設計的。

? ? ? ? 我們看下源碼,我們只看ASSERT_型的,EXPECT_型和ASSERT_型的區別在前文很多次講到,所以不再羅列代碼了。

#define ASSERT_THROW(statement, expected_exception) \GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_)
#define ASSERT_NO_THROW(statement) \GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_)
#define ASSERT_ANY_THROW(statement) \GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_)

? ? ? ? 我們先看最簡單的GTEST_TEST_NO_THROW_的實現

#define GTEST_TEST_NO_THROW_(statement, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::AlwaysTrue()) { \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (...) { \goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \fail("Expected: " #statement " doesn't throw an exception.\n" \"  Actual: it throws.")

? ? ? ? 只要表達式拋出異常,就會goto到else中進行錯誤處理。

? ? ? ? 再看下GTEST_TEST_ANY_THROW_的實現

#define GTEST_TEST_ANY_THROW_(statement, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::AlwaysTrue()) { \bool gtest_caught_any = false; \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (...) { \gtest_caught_any = true; \} \if (!gtest_caught_any) { \goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \fail("Expected: " #statement " throws an exception.\n" \"  Actual: it doesn't.")

? ? ? ? 只要拋出異常,就認為是正確的。否則goto到else代碼中進行錯誤處理。

? ? ? ? 再看下稍微復雜點的GTEST_TEST_THROW_

#define GTEST_TEST_THROW_(statement, expected_exception, fail) \GTEST_AMBIGUOUS_ELSE_BLOCKER_ \if (::testing::internal::ConstCharPtr gtest_msg = "") { \bool gtest_caught_expected = false; \try { \GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \} \catch (expected_exception const&) { \gtest_caught_expected = true; \} \catch (...) { \gtest_msg.value = \"Expected: " #statement " throws an exception of type " \#expected_exception ".\n  Actual: it throws a different type."; \goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \} \if (!gtest_caught_expected) { \gtest_msg.value = \"Expected: " #statement " throws an exception of type " \#expected_exception ".\n  Actual: it throws nothing."; \goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \} \} else \GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \fail(gtest_msg.value)

? ? ? ? 只有接收到了傳入的特定類型的異常,否則都會goto到else代碼中進行錯誤處理。

參數名輸出斷言

? ? ? ? 在之前的介紹的斷言中,如果在出錯的情況下,我們會對局部測試相關信息進行輸出,但是并不涉及其可能傳入的參數。參數名輸出斷言,可以把參數名和對應的值給輸出出來。

Fatal assertionNonfatal assertionVerifies
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
.........

? ? ? ? 目前版本的GTest支持5個參數的版本ASSERT/EXPECT_PRED5宏。其使用方法是

template <typename T1, typename T2>
bool GreaterThan(T1 x1, T2 x2) {return x1 > x2;
}
TEST(PredicateAssertionTest, AcceptsTemplateFunction) {int a = 5;int b = 6;ASSERT_PRED2((GreaterThan<int, int>), a, b);
}

? ? ? ? 其輸出是

error: (GreaterThan<int, int>)(a, b) evaluates to false, where
a evaluates to 5
b evaluates to 6

? ? ? ? 其源碼也沒什么太多奧秘,只是簡單的把結果輸出

template <typename Pred,typename T1,typename T2>
AssertionResult AssertPred2Helper(const char* pred_text,const char* e1,const char* e2,Pred pred,const T1& v1,const T2& v2) {if (pred(v1, v2)) return AssertionSuccess();return AssertionFailure() << pred_text << "("<< e1 << ", "<< e2 << ") evaluates to false, where"<< "\n" << e1 << " evaluates to " << v1<< "\n" << e2 << " evaluates to " << v2;
}

? ? ? ? 這兒需要注意的是,判斷的表達式可以使用if語句判斷返回結果,所以最好是bool類型。

子過程中使用斷言

? ? ? ? 經過之前的分析,我們可以想到,如果子過程中使用了斷言,則結果輸出只會指向子過程,而不會指向父過程中的某個調用。為了便于閱讀我們可以使用SCOPED_TRACE宏去標記下位置

void Sub(int n) {ASSERT_EQ(1, n);
}TEST(SubTest, Test1) {{SCOPED_TRACE("A");Sub(2);}Sub(3);
}

? ? ? ? 其結果輸出時標記了下A這行位置,可見如果沒有這個標記,是很難區分出是哪個Sub失敗的。

..\test\gtest_unittest.cc(87): error:       Expected: 1
To be equal to: nWhich is: 2
Google Test trace:
..\test\gtest_unittest.cc(92): A
..\test\gtest_unittest.cc(87): error:       Expected: 1
To be equal to: nWhich is: 3

? ? ? ? 我們再注意下Sub的實現,其使用了ASSERT_EQ斷言,該斷言并不會影響Test1測試特例的運行,其原因我們在之前做過分析了。為了消除這種可能存在的誤解,GTest推薦使用在子過程中使用ASSERT/EXPECT_NO_FATAL_FAILURE(statement);

? ? ? ? 如果父過程一定要在子過程發生錯誤時退出怎么辦?我們可以使用::testing::Test::HasFatalFailure()去判斷當前線程中是否產生過錯誤。

TEST(SubTest, Test1) {{SCOPED_TRACE("A");Sub(2);}if (::testing::Test::HasFatalFailure())return;Sub(3);
}

總結

以上是生活随笔為你收集整理的Google Test(GTest)使用方法和源码解析——断言的使用方法和解析的全部內容,希望文章能夠幫你解決所遇到的問題。

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