qileilove

          blog已經轉移至github,大家請訪問 http://qaseven.github.io/

          編寫優美的GTest測試案例

           使用gtest也有很長一段時間了,這期間也積累了一些經驗,所以分享一下。GTest為我們提供了便捷的測試框架,讓我們只需要關注案例本身。如何在GTest框架下寫出優美的測試案例,我覺得必須要做到:
            案例的層次結構一定要清晰
            案例的檢查點一定要明確
            案例失敗時一定要能精確的定位問題
            案例執行結果一定要穩定
            案例執行的時間一定不能太長
            案例一定不能對測試環境造成破壞
            案例一定獨立,不能與其他案例有先后關系的依賴
            案例的命名一定清晰,容易理解
            案例的可維護性也是非常重要,如果做到上面的8點,自然也就做到了可維護性。下面來分享一下我對于上面8點的經驗:
            1. 案例的層次結構一定要清晰
            所謂層次結構,至少要讓人一眼就能分辨出被測代碼和測試代碼。簡單的說,就是知道你在測什么。由于是進行接口測試,我已經習慣了如下的案例層次:
            DataDefine
            我會將測試案例所需要的數據,以及數據之間的聯系全部在預先定義好。測試數據與案例邏輯的分離,有利于維護和擴展測試案例。同時,GTest先天就支持測試數據參數化,為測試數據的分離提供了進一步的便捷。什么是測試數據參數化?就是你可以預先定義好一批各種各樣的數據,而你只需要編寫一個測試案例的邏輯代碼,gtest會將定義好的數據逐個套入測試案例中進行執行。具體的做法請見:玩轉Google開源C++單元測試框架Google Test系列(gtest)之四 - 參數化
            SUT
            SUT,即system under test,表明你的測試對象是什么,它可以是一個類(CUT),對象(OUT),函數(MUT),甚至可以是整個應用程序(AUT)。我單獨將這個層次劃分出來,主要有兩個目的:
            (1)明確的表示出你的測試對象是什么
            (2)為復雜調用對象包裝簡單調用接口
            明確表示測試對象是什么,便于之后對測試案例的維護和對測試案例的理解。同時,對于一些被測對象,你想要調用它需要經過一系列煩瑣的過程,這時,就需要將這一煩瑣的調用過程隱藏起來,而只關注被測對象的輸入和輸出。
            TestCase
            測試工程中,必須非常明確的表示出哪些是測試案例,哪些是其他的輔助文件。通常,我們會在測試案例的文件名加上Test前綴(或者后綴)。我建議,將所有的測試案例文件或代碼放在最顯眼的地方,讓所有看到你的測試工程的人,第一眼看到的就是測試案例,這很重要。

            Checker
            對于一個復雜系統的接口測試,僅僅堅持輸入和輸出是遠遠不夠的。比如測試一個寫數據庫的函數,函數的返回值告訴你數據已經成功寫入是遠遠不夠的,你必須親身去數據庫中查個究竟才行。因此,對于某一類的測試案例,我們可以抽象出一些通用的檢查點代碼。
            如果做到上面的分層,那么一個測試案例寫出來的結構應該會是這個樣子:
          TEST(TestFoo, JustDemo)
          {
          GetTestData(); // 獲取測試數據
          CallSUT(); // 調用被測方法
          CheckSomething(); // 檢查點驗證
          }
            這樣的測試案例,一目了然。
            2. 案例的檢查點一定要明確
            一定要明確案例的檢查點是什么,并且讓檢查點盡量集中。有一個不好的習慣就是核心的檢查點在分布在多個函數中,需要不斷的跳轉才能了解到這個案例檢查了些什么。好的做法應該是盡量讓檢查點集中,能夠非常清晰的分辨出案例對被測代碼做了哪些檢查。所以,盡量讓Gtest的ASSERT_和EXPECT_系列的宏放在明顯和正確的地方。
            3. 案例失敗時一定要能精確的定位問題
            測試案例失敗時,我們通常手忙腳亂。如果一個測試案例Failed,卻不能立即推斷是被測代碼的Bug的話,這個測試案例也有待改進。我們可以在一些復雜的檢查點斷言中加入一些輔助信息,方便我們定位問題。比如下面這個測試案例:
          int n = -1;
          bool actualResult = Foo::Dosometing(n);
          ASSERT_TRUE(actualResult)
            如果測試案例失敗了,會得到下面的信息:
          Value of: actualResult
          Actual: false
          Expected:true
            這樣的結果對于我們來說,幾乎沒有什么用。因為我們根本不知道actualResult是什么,以及在什么情況下才會出現非預期值。因此,在斷言處多加入一些信息,將有助于定位問題:
          int n = -1;
          bool actualResult = Foo::Dosometing(n);
          ASSERT_TRUE(actualResult) << L"Call Foo::Dosometing(n) when n = " << n;
            4. 案例執行結果一定要穩定
            要保證測試案例在什么時候、什么情況下執行的結果都是一樣的。一個一會成功一會失敗的案例是沒有意義的。要保證案例穩定性的方法有很多,比如杜絕案例之間的影響,有時候,由于前一個案例執行完后,將一些系統的環境破壞了,導致后面的案例執行失敗。在測試某些本身就存在一定幾率或延時的系統時,使用超時機制是比較簡單的辦法。比如,你需要測試一個啟動Windows服務的方法,如果我們在調用了該方法后立即進行檢查,很可能檢查點會失敗,有時候也許又是通過的。這是因為Windows服務由Stop狀態到Running狀態,中間還要經過一個Padding狀態。所以,簡單的做法是使用超時機制,隔斷時間檢查一次,直到超過某個最大忍受時間。
          ASSERT_TRUE(StartService('xxx'));
          int tryTimes = 0;
          int status = GetServiceStatus('xxx');
          while (status != Running)
          {
          if (tryTimes >= 10)
          break;
          ::Sleep(200);
          tryTimes++;
          status = GetServiceStatus('xxx');
          }
          ASSERT_EQ(Running, status) << "Check the status after StartService('xxx')";
            5. 案例執行的時間一定不能太長
            我們應該盡量讓案例能夠快速的執行,一方面,我們可以通過優化我們的代碼來減少運行時間,比如,減少對重復內容的讀取。一方面,對于一些比較耗時的操作,比如文件系統,網絡操作,我們可以使用Mock對象來替代真實的對象。使用GMock是一個不錯的選擇。
            6. 案例一定不能對測試環境造成破壞
            有的案例需要在特定的環境下來能執行,因此會在案例的初始化時對環境進行一些修改。注意,不管對什么東西進行了修改,一定要保證在案例執行完成的TearDown中將這些環境都還原回來。否則有可能對后面的案例造成影響,或者出現一些莫名其妙的錯誤。
            7. 案例一定獨立,不能與其他案例有先后關系的依賴
            任何一個案例都不依賴于其他測試案例,任何一個案例的執行結果都不應該影響到別的案例。任何一個案例都可以單獨拿出去正確的執行。所以,不能寄希望于前一個案例所做的環境準備,因為這是不對的。
            8. 案例的命名一定清晰,容易理解
            案例的名字要規范,長不要緊,一定要清晰的表達測試案例的用途。比如,下面的測試案例名稱都是不好的:
          TEST(TestFoo, Test)
          TEST(TestFoo, Normal)
          TEST(TestFoo, Alright)
            比如像下面的案例名稱就會好一點:
          TEST(TestFoo, Return_True_When_ParameterN_Larger_Then_Zero)
          TEST(TestFoo, Return_False_When_ParameterN_Is_Zero)

          posted on 2013-11-08 14:17 順其自然EVO 閱讀(450) 評論(0)  編輯  收藏 所屬分類: selenium and watir webdrivers 自動化測試學習

          <2013年11月>
          272829303112
          3456789
          10111213141516
          17181920212223
          24252627282930
          1234567

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 朝阳市| 资源县| 张家港市| 张家口市| 蒙山县| 阿鲁科尔沁旗| 光泽县| 灵台县| 平潭县| 泸定县| 德令哈市| 栖霞市| 夹江县| 山西省| 东城区| 天长市| 邓州市| 扶绥县| 巫溪县| 寻乌县| 磐安县| 绥化市| 大安市| 定结县| 江达县| 周至县| 万山特区| 项城市| 南宫市| 甘德县| 九江县| 静宁县| 吉安市| 汉源县| 宣恩县| 邯郸市| 栖霞市| 云浮市| 寻甸| 普洱| 阳城县|