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

歡迎訪問 生活随笔!

生活随笔

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

生活经验

Google Test(GTest)使用方法和源码解析——概况

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

? ? ? ? GTest是很多開源工程的測試框架。雖然介紹它的博文非常多,但是我覺得可以深入到源碼層來解析它的實現原理以及使用方法。這樣我們不僅可以在開源工程中學習到實用知識,還能學習到一些思想和技巧。我覺得有時候思想和技巧是更重要的。(轉載請指明出于breaksoftware的csdn博客)

? ? ? ? 我們即將要分析的是GTest1.7版本。我們可以通過https://github.com/google/googletest.git得到代碼。

? ? ? ? 官方文檔見:

  • https://github.com/google/googletest/blob/master/googletest/docs/primer.md
  • https://github.com/google/googletest/blob/master/googletest/docs/advanced.md

? ? ? ? 我們先大致熟悉一下GTest的特性。GTest和很多開源工程一樣,并不只是針對特定的平臺,否則其使用范圍將大打折扣,所以GTest具有很好的移植特性可復用性,我們以工程中的代碼為例

template <class T, typename Result>
Result HandleSehExceptionsInMethodIfSupported(T* object, Result (T::*method)(), const char* location) {
#if GTEST_HAS_SEH__try {return (object->*method)();} __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINTGetExceptionCode())) {std::string* exception_message = FormatSehExceptionMessage(GetExceptionCode(), location);internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,*exception_message);delete exception_message;return static_cast<Result>(0);}
#else(void)location;return (object->*method)();
#endif  // GTEST_HAS_SEH
}

? ? ? ? 這段代碼只是為了執行模板類T對象的method函數指針指向的方法。其核心就是(object->*method)()這句,但是它卻使用了20行的代碼去實現,就是為了解決平臺的兼容問題。從名字我們可以看出它為了兼容SEH機制——結構化異常處理——一種windows系統上提供給用戶處理異常的機制。而這種機制在linux系統上沒有。這個函數是GTest為移植特性所做工作的一個很好的代表,我們將在之后的源碼介紹中經常見到它的身影。

? ? ? ? 我們編碼時,有時候我們不僅考究邏輯的嚴謹,還非常注意編碼的風格和布局的優美。其實代碼就像一件作品,一個不負責任的作者可能是毫無章法的涂鴉手法,而有些有著一定境界的程序員可能就會按照自己的“畫風”去繪制——他的“畫風”可能你并不喜歡,但是那種風格卻是獨立和鮮明的,甚至是有一定道理的。而且如果一旦“畫風”確定,對于臨摹者來說只要照著這樣的套路去做,而不用自己發揮自己的風格,這對一個庫的發展也是非常有益的。 GTest同樣有著良好的組織結構,我們以其自帶的Sample1為例

// Tests factorial of negative numbers.
TEST(FactorialTest, Negative) {EXPECT_EQ(1, Factorial(-5));EXPECT_EQ(1, Factorial(-1));EXPECT_GT(Factorial(-10), 0);
}// Tests factorial of 0.
TEST(FactorialTest, Zero) {EXPECT_EQ(1, Factorial(0));
}// Tests factorial of positive numbers.
TEST(FactorialTest, Positive) {EXPECT_EQ(1, Factorial(1));EXPECT_EQ(2, Factorial(2));EXPECT_EQ(6, Factorial(3));EXPECT_EQ(40320, Factorial(8));
}

? ? ? ? 這段代碼是一套完整的測試代碼??梢杂^察發現,每個邏輯使用一個TEST宏控制,其內部也是一系列EXPECT_*宏堆砌。先不論其他風格,單從整齊有規律的書寫方式上來說,GTest也算是一個便于結構性編碼的樣板。我們使用者只要照著這樣的樣板去編寫測試用例,是非常方便的,這也將大大降低我們使用GTest庫的門檻。

? ? ? ? TEST宏是一個很重要的宏,它構成一個測試特例。現在有必要介紹下其構成,TEST宏的第一個參數是“測試用例名”,第二個參數是“測試特例名”。測試用例(Test Case)是為某個特殊目標而編制的一組測試輸入、執行條件以及預期結果,以便測試某個程序路徑或核實是否滿足某個特定需求(引百度百科),測試特例是測試用例下的一組測試。以以上代碼為例,三段TEST宏構成的是一個測試用例——測試用例名是FactorialTest(階乘方法檢測,測試Factorial函數),該用例覆蓋了三種測試特例——Negative、Zero和Positive——即檢測輸入參數是負數、0和正數這三種特例情況。

? ? ? ? 我們再看一組檢測素數的測試用例

TEST(IsPrimeTest, Negative) {// This test belongs to the IsPrimeTest test case.EXPECT_FALSE(IsPrime(-1));EXPECT_FALSE(IsPrime(-2));EXPECT_FALSE(IsPrime(INT_MIN));
}// Tests some trivial cases.
TEST(IsPrimeTest, Trivial) {EXPECT_FALSE(IsPrime(0));EXPECT_FALSE(IsPrime(1));EXPECT_TRUE(IsPrime(2));EXPECT_TRUE(IsPrime(3));
}// Tests positive input.
TEST(IsPrimeTest, Positive) {EXPECT_FALSE(IsPrime(4));EXPECT_TRUE(IsPrime(5));EXPECT_FALSE(IsPrime(6));EXPECT_TRUE(IsPrime(23));
}

? ? ? ? 這組測試用例的名是IsPrimeTest(測試IsPrime函數),三個測試特例是Negative(錯誤結果場景)、Trivial(有對有錯的場景)和Positive(正確結果場景)。

? ? ? ? 對于測試用例名和測試特例名,不能有下劃線(_)。因為GTest源碼中需要使用下劃線把它們連接成一個獨立的類名

// Expands to the name of the class that implements the given test.
#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \test_case_name##_##test_name##_Test

? ? ? ? 這樣也就要求,我們不能有相同的“測試用例名和特例名”的組合——否則類名重合。

? ? ? ? 測試用例名和測試特例名的分開,使得我們編寫的測試代碼有著更加清晰的結構——即有相關性也有獨立性。相關性是通過相同的測試用例名聯系的,而獨立性通過不同的測試特例名體現的。我們通過這段測試代碼的運行結果查看一下這兩個特性

Running main() from gtest_main.cc
[==========] Running 6 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (0 ms total)[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)[----------] Global test environment tear-down
[==========] 6 tests from 2 test cases ran. (14 ms total)
[  PASSED  ] 6 tests.

? ? ? ? 從輸出結果上,我們看到GTest框架將我們相同測試用例名的場景合并在一起,不同測試特例名的場景分開展現。而且我們還發現GTest有自動統計結果、自動格式化輸出結果、自動調度執行等特性。這些特性也將是之后博文分析的重點。? ? ?

? ? ? ? 雖然上例中,所有的執行都是正確的,但是如果以上測試中發生一個錯誤,也不能影響其他測試——不同測試用例不相互影響、相同測試用例不同測試特例不相互影響。我們稱之為獨立性。除了獨立性,也不失靈活性——一個測試測試特例中可以通過不同宏(ASSERT_*類宏會影響之后執行,EXPECT_*類宏不會)控制是否影響之后的執行。

? ? ? ? 如果我們編寫的測試用例組(如上例是兩組)中一組發生了錯誤,我們希望沒出錯的那組不用執行了,出錯的那組再執行一遍。一般情況下,我們可能需要去刪除執行正確的那段測試代碼,但是這種方式非常不優美——需要編譯或者忘記恢復代碼。GTest框架可以讓我們通過在程序參數控制執行哪個測試用例,比如我們希望只執行Factorial測試,就可以這樣調用程序

./sample1_unittest --gtest_filter=Factorial*

? ? ? ? 我們可以將以上特性稱之為選擇性測試。

? ? ? ? 最后一個特性便是預處理。我們測試時,往往要構造復雜的數據。如果我們在每個測試特例中都要構造一遍數據,將是非常繁瑣和不美觀的。GTest提供了一種提前構建數據的方式。我們以如下代碼為例

class ListTest : public testing::Test {protected:virtual void SetUp() {_m_list[0] = 11;_m_list[1] = 12;_m_list[2] = 13;}int _m_list[3];
};
TEST_F(ListTest, FirstElement) {EXPECT_EQ(11, _m_list[0]);
}TEST_F(ListTest, SecondElement) {EXPECT_EQ(12, _m_list[1]);
}TEST_F(ListTest, ThirdElement) {EXPECT_EQ(13, _m_list[2]);
}

? ? ? ? 我們讓ListTest類繼承于GTest提供的基類testing::Test,并重載SetUp方法。這樣我們每次執行ListTest的一個測試特例時,SetUp方法都會執行一次,從而將數據準備完畢。這樣我們只要在一個類中構建好數據就行了。這兒需要注意一下TEST_F宏,它的第一參數要求是類名——即ListTest——不像TEST宏的第一個參數我們可以隨便命名。

總結

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

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

主站蜘蛛池模板: 国产不卡免费视频 | 色哟哟视频网站 | 午夜aaa片一区二区专区 | 播播激情网 | 国产激情久久 | 久久久久久久久免费 | 国内露脸中年夫妇交换 | 欧美日韩精品久久久免费观看 | 91亚洲欧美激情 | 成人无码av片在线观看 | 欧美3p在线观看 | 欧美一区二区影院 | 99热99热 | 蜜臀av一区 | 少妇2做爰交换朴银狐 | 天堂婷婷 | 欧美激情精品久久久久久变态 | 色狠狠操 | 爱爱15p| 深夜av| 国产女人高潮时对白 | 男人操女人免费 | 国产精品电影网站 | 猛男被粗大男男1069 | 国产精品视频大全 | 亚洲一区二区影视 | 黑人多p混交群体交乱 | 神马午夜91 | av中字 | 日韩欧美大片在线观看 | 秋霞影院午夜伦 | 成年人免费网站视频 | 国产精品18 | 国产一级二级三级 | 久久久久久久久久久影视 | 成人动漫一区 | 噜噜噜色 | 国产在线视频网站 | 日韩欧美成人一区二区 | 国产成人精品午夜福利Av免费 | 黄色美女毛片 | 日韩六九视频 | 女人叫床高潮娇喘声录音mp3 | 在线看免费av | 国产av人人夜夜澡人人爽 | 欧洲av片 | 绿帽视频| 18禁免费无码无遮挡不卡网站 | 久久久久亚洲精品中文字幕 | 69视频免费在线观看 | 日韩人成 | 老色批影视 | 久久国产精品波多野结衣 | jizz日本大全| 久草视频免费在线播放 | 国产精品乱码一区二区三区 | 久久久久久久九九九九 | 日韩一区二区三免费高清在线观看 | 最好看的日本字幕mv视频大全 | 亚洲精品国产成人久久av盗摄 | 国产午夜精品久久 | 欧美视频一区二区三区在线观看 | 最新成人| 亚洲精品一区二区口爆 | 翔田千里x88aⅴ | 久久国产精品影院 | 国产特黄毛片 | 伊人网在线免费观看 | 佐佐木明希av在线 | 久久视频免费在线观看 | 亚洲高潮av| 天降女子在线 | jizz在线看 | 狼性av懂色av禁果av | 无码国产精品一区二区免费式直播 | 蜜桃综合网 | 国产一区二区三区精品愉拍 | 亚欧综合在线 | 狠狠的干狠狠的操 | 2018av在线| 日本大尺度做爰呻吟 | 久久国| 5个黑人躁我一个视频 | 香蕉视频在线观看黄 | 成人免费观看网站 | 国产一区二区免费在线 | 午夜剧场免费在线观看 | 国产福利在线观看 | 日本人妻丰满熟妇久久久久久 | 午夜激情视频 | 香蕉蜜桃视频 | 欧美日韩二区三区 | 中文字幕一区二区三区免费 | 与子敌伦刺激对白播放的优点 | 日韩高清影视 | 黄色一级片a | 久久国产精品免费视频 | 免费在线激情视频 | 亚洲欧美电影 |