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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

为什么有如此多的C++测试框架 - from Google Testing Blog

發(fā)布時(shí)間:2024/4/14 c/c++ 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 为什么有如此多的C++测试框架 - from Google Testing Blog 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Why Are There So Many C++ Testing Frameworks? by Zhanyong Wan (Software Engineer)

?

最近貌似有很多人正在開發(fā)他們自己的C++測(cè)試框架,如果還沒能完工。Wiki上有一個(gè)此類框架的不完全列表。因?yàn)榇蠖鄶?shù)面向?qū)ο缶幊陶Z言只有1到2個(gè)主要的框架,對(duì)C++而言這就顯得有趣了。例如,大多數(shù)Java開發(fā)者都使用JUnit或TestNG。難道C++程序員都是瘋狂的DIY愛好者嗎?

當(dāng)我們開發(fā)并將Google Test(Google的C++測(cè)試框架)開源后,人們開始好奇為什么我們要做這件事。簡(jiǎn)單的回答是我們沒有能夠找到一個(gè)已有的并且能夠滿足需求的C++測(cè)試框架。這并不表明現(xiàn)有的框架設(shè)計(jì)和實(shí)現(xiàn)的很糟糕,事實(shí)上我們也從中學(xué)到了很多偉大的想法和實(shí)現(xiàn)技巧。但是Google有如此多的C++項(xiàng)目需要在不同的平臺(tái)上用不同的編譯器編譯,同時(shí)還有著無數(shù)的編譯選項(xiàng),我們確實(shí)需要有這么一個(gè)框架能夠在如此復(fù)雜環(huán)境下處理不同類型和規(guī)模的項(xiàng)目。

和有著著名口號(hào)“一次編程,到處運(yùn)行”的Java不同,C++代碼的編寫在一個(gè)更復(fù)雜多變的環(huán)境下進(jìn)行。由于語言本身的復(fù)雜性以及處理底層任務(wù)的需求,不同的C++編譯器甚至不同版本之間的兼容性都存在著許多問題。雖然有著C++標(biāo)準(zhǔn),但是到現(xiàn)在為止還沒有一個(gè)編譯器廠商能很好的全面支持。很多時(shí)候因?yàn)槿蝿?wù)需要,你必須使用一些不可移植的擴(kuò)展或者平臺(tái)相關(guān)的功能。以上這些原因使得編寫一個(gè)能使用不同編譯器在在不同平臺(tái)上工作的復(fù)雜系統(tǒng)變得十分困難。

更頭大的事還沒完,大多數(shù)C++編譯器允許你關(guān)閉一些標(biāo)準(zhǔn)語言特性來獲取更好的性能。不喜歡異常?關(guān)了。不喜歡動(dòng)態(tài)轉(zhuǎn)換Dynamic Cast?把動(dòng)態(tài)類型識(shí)別RTTI禁用好了,雖然它能提供動(dòng)態(tài)轉(zhuǎn)換和運(yùn)行時(shí)類型信息訪問。如果你選擇這么做,那么使用到以上特性的代碼就會(huì)編譯失敗。許多測(cè)試框架都依賴異常,想想你把異常關(guān)掉會(huì)之后發(fā)生什么?但對(duì)于我們來說這不是一個(gè)問題,因?yàn)槲覀兊拇蠖鄶?shù)項(xiàng)目都是禁用異常的。也許你會(huì)好奇,但是讓我告訴你,Google Test在默認(rèn)情況下是不需要異常和動(dòng)態(tài)類型識(shí)別的。但是當(dāng)這些特性被打開時(shí),Google Test會(huì)試著去利用它們給你提供一些新功能,比如基于異常的斷言exception assertions。

為什么不寫一個(gè)可移植的框架?是的,這是Google Test的最高設(shè)計(jì)目標(biāo),而且很多框架的設(shè)計(jì)者也已經(jīng)努力過了。但是,自由不是無代價(jià)的。跨平臺(tái)的C++開發(fā)要求大量額外的精力:

  • 你必須使用不同的編譯器,擺弄不同的編譯開關(guān),生成代碼在不同的操作系統(tǒng)上運(yùn)行測(cè)試。
  • 某些平臺(tái)的特殊要求使得你必須使用條件編譯。
  • 不同的編譯器可能存在bug,你必須小心的修改代碼繞來繞去。
  • 除非你在一臺(tái)裸機(jī)上工作,不然這一切太讓人崩潰了。
  • 所以,我的結(jié)論是:為什么我們有如此多C++測(cè)試框架的原因是出在C++實(shí)現(xiàn)自身,不同環(huán)境之間的變化使得編寫可移植的C++代碼是如此困難。張三的框架可能完美的解決了張三的問題,但是對(duì)李四卻一點(diǎn)不適用。

    另外一個(gè)原因我想是C++自身的限制使得我們無法很好的實(shí)現(xiàn)一些功能,為了繞過一些限制大家只好各顯神通了。一個(gè)顯著的例子就是C++是一個(gè)靜態(tài)類型語言并且不提供反射Reflection機(jī)制。大多數(shù)Java測(cè)試框架可以使用反射自動(dòng)找到你編寫的測(cè)試用例,這樣你就不用一個(gè)個(gè)去手工注冊(cè)了。如果需要手動(dòng)注冊(cè)的話很有可能你寫了測(cè)試用例而忘記去注冊(cè),并且手工維持更新也是很痛苦的。因?yàn)镃++沒有提供反射機(jī)制,我們只能用不同的方法。不幸的是沒有一個(gè)完美的解決方案。一些框架要求你手工注冊(cè)測(cè)試用例,而另一些框架使用腳本分析你的代碼來找到測(cè)試用例,還有一些則利用宏來完成自動(dòng)注冊(cè)。我們認(rèn)為最后一個(gè)使用宏的解決方案是最好的,并且對(duì)大多數(shù)人都有效。目前有好幾種用宏來實(shí)現(xiàn)的方法,各有各的利弊,最終結(jié)論還是有待商榷的。

    讓我們看一些實(shí)際代碼來理解Google Test是如何解決測(cè)試用例注冊(cè)問題的。最簡(jiǎn)單的方法是使用TEST宏來添加一個(gè)測(cè)試用例。

    1 TEST(Subject, HasCertainProperty) { 2 // … testing code goes here … 3 }

    它定義了一個(gè)測(cè)試用例來檢查某個(gè)Subject是否包含一些特定的屬性。宏自動(dòng)向Google Test注冊(cè)這個(gè)測(cè)試用例,所以當(dāng)測(cè)試程序執(zhí)行時(shí)這個(gè)用例會(huì)被覆蓋。

    這里有個(gè)更加實(shí)際的用來檢測(cè)階乘函數(shù)在使用正整數(shù)時(shí)能正確工作的例子:

    1 TEST(FactorialTest, HandlesPositiveInput) { 2 EXPECT_EQ(1, Factorial(1)); 3 EXPECT_EQ(2, Factorial(2)); 4 EXPECT_EQ(6, Factorial(3)); 5 EXPECT_EQ(40320, Factorial(8)); 6 }

    最后,許多C++測(cè)試框架的作者都忽略了擴(kuò)展性并且滿足于提供一個(gè)打包了的解決方案,這導(dǎo)致的后果就是我們留下了很多解決方案,每個(gè)都只針對(duì)一些特定的問題而不足夠通用。一個(gè)萬能的框架必須提供足夠的擴(kuò)展能力。我們必須明確無論如何所有人的需求是不可能被同時(shí)滿足的。我們可以提供一個(gè)一攬子解決方案滿足95%的需求,而不是為了一些很少有人用的功能而塞入大量臃腫的代碼。我們可以開放接口來讓用戶自己根據(jù)需要實(shí)現(xiàn)那些功能。如果我能輕松的擴(kuò)展已有框架來實(shí)現(xiàn)我需要的特定功能,我就不會(huì)選擇重起爐灶寫一個(gè)新的框架。但是大多數(shù)框架的作者都沒有看到可擴(kuò)展性的重要。我認(rèn)為正是這種思路導(dǎo)致了今天這種群魔亂舞的局面。在Google Test的實(shí)現(xiàn)中,我們努力使得你可以通過自定義斷言生成更有意義的錯(cuò)誤信息來簡(jiǎn)單的擴(kuò)展你的測(cè)試詞匯表。這里有個(gè)簡(jiǎn)單的例子顯示如何判斷一個(gè)值是否在給定的范圍:

    1 bool IsInRange(int value, int low, int high) { 2 return low <= value && value <= high; 3 } 4 5 // ... 6 7 EXPECT_TRUE(IsInRange(SomeFunction(), low, high));

    當(dāng)你的斷言失敗時(shí),你只知道函數(shù)SomeFunction返回的值不在[low, high]的范圍中,但是你不知道返回值和期望范圍是多少,這就使得代碼的調(diào)試變得比較麻煩了。

    但是你可以提供自己定制的信息來提供斷言失敗時(shí)更有意義的描述:

    1 EXPECT_TRUE(IsInRange(SomeFunction(), low, high)) 2 << "SomeFunction() = " << SomeFunction() 3 << ", not in range [" 4 << low << ", " << high << "]";

    如果考慮到SomeFunction可能每次返回不同的值,我們可以把代碼稍作修改:

    1 int result = SomeFunction(); 2 EXPECT_TRUE(IsInRange(result, low, high)) 3 << "result (return value of SomeFunction()) = " << result 4 << ", not in range [" << low << ", " << high << "]";

    上面的辦法看著可行但是太麻煩了,假如你要調(diào)用幾百次EXPECT_TRUE來檢測(cè)SomeFunction的返回值怎么辦?我們需要把這種模式抽象為一個(gè)可重用的結(jié)構(gòu)。

    Google Test允許你自定義類似于如下的測(cè)試斷言:

    1 AssertionResult IsInRange(int value, int low, int high) { 2 if (value < low) 3 return AssertionFailure() 4 << value << " < lower bound " << low; 5 else if (value > high) 6 return AssertionFailure() 7 << value << " > upper bound " << high; 8 else 9 return AssertionSuccess() 10 << value << " is in range [" 11 << low << ", " << high << "]"; 12 }

    當(dāng)范圍是[20, 60]而SomeFunction返回13時(shí)如下信息將被打印:

    Value of: IsInRange(SomeFunction(), low, high)Actual: false (13 < lower bound 20) Expected: true

    同樣的IsInRange定義還可以被用于EXPECT_FALSE的情況,例如"EXPECT_FALSE(AnothFunction(), 20, 60)",AnotherFunction返回25,如下信息將被打印:

    Value of: IsInRange(AnotherFunction(), low, high)Actual: true (25 is in range [20, 60]) Expected: false

    通過以上方式,你可以為特定的問題領(lǐng)域建立一個(gè)斷言庫,從這些清晰的,陳述性的代碼和有意義的錯(cuò)誤信息中獲益。

    于此一脈相承的還有Google Mock(我們的C++ mocking框架)允許你自定義matchers和系統(tǒng)自帶的matchers一起無差別的使用。我們還在Google Test引入了事件監(jiān)聽API使得用戶可以自行編寫插件。我們希望用戶能夠充分使用這些特性擴(kuò)展Google Test和Mock以滿足他們的需求,如果能提交一些好的擴(kuò)展給我們那是最好不過的了。

    就像共產(chǎn)主義一定要實(shí)現(xiàn)一樣,總有一天,C++測(cè)試框架碎片化的問題也會(huì)得到解決。

    轉(zhuǎn)載于:https://www.cnblogs.com/panda_lin/p/why_are_there_so_many_cpp_testing_frameworks.html

    總結(jié)

    以上是生活随笔為你收集整理的为什么有如此多的C++测试框架 - from Google Testing Blog的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。