軟件單元測試方法.ppt_第1頁
軟件單元測試方法.ppt_第2頁
軟件單元測試方法.ppt_第3頁
軟件單元測試方法.ppt_第4頁
軟件單元測試方法.ppt_第5頁
已閱讀5頁,還剩88頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

軟件單元測試方法,工業(yè)通訊技術(shù)部 張國亮,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,序言(1),要向客戶演示系統(tǒng)的基本功能,且臨近最終期限時(shí),兩個(gè)開發(fā)者的兩種不同的做法: 第一個(gè)開發(fā)者:每天著急地寫代碼,寫完一個(gè)類又寫一個(gè)類,寫完一個(gè)方法又接著寫兩一個(gè)方法,有時(shí)不得不停下來做一些調(diào)整,使得代碼能夠編譯通過。 第二個(gè)模塊者:寫一個(gè)模塊的時(shí)候,會附帶寫一個(gè)簡短的測試程序來測試這個(gè)方法。并且在未對剛寫的方法做出確認(rèn)(通過測試確認(rèn)之前的方法和他所期望的結(jié)果一致)之前,是不會接著寫新代碼的。,序言(2),兩種不同的做法帶來的兩種不同的結(jié)果: 第一個(gè)開發(fā)者:期限的前一天,集成演示時(shí),一點(diǎn)輸出都沒有;利用調(diào)試器跟蹤,經(jīng)過長時(shí)間的琢磨,找到并糾正了這個(gè)bug,但是,同時(shí)又發(fā)現(xiàn)了其他好幾個(gè)bug。結(jié)果,筋疲力盡,而且未能及時(shí)完成任務(wù)。 第二個(gè)開發(fā)者:期限的前一天,集成代碼到整個(gè)系統(tǒng)中,并且能夠很好的運(yùn)行;雖然在其中也出現(xiàn)了一個(gè)小問題,但是很對就發(fā)現(xiàn)了問題所在,并在幾分鐘之內(nèi)就解決了這個(gè)問題。,序言(3),不寫測試的借口 編寫單元測試太花時(shí)間了 運(yùn)行測試的時(shí)間太長了 測試代碼并不是我的工作 我并不清楚代碼的行為,所以也就無從測試 這些代碼都能夠編譯通過 公司請我來是為了寫代碼,而不是寫測試 如果我讓測試員或者QA人員沒有工作,那么我會覺得很內(nèi)疚 我的公司并不會讓我在真實(shí)系統(tǒng)中運(yùn)行單元測試,單元測試,什么是單元測試 單元測試是開發(fā)者編寫的一小段代碼,用于檢驗(yàn)被測代碼的一個(gè)很小的、很明確的功能是否正確。 通常而言,一個(gè)單元測試是用于判斷某個(gè)特定條件(或者場景)下某個(gè)特定函數(shù)的行為。 執(zhí)行單元測試,是為了證明某段代碼的行為確實(shí)和開發(fā)者所期望的一致 為什么要使用單元測試 單元測試不但會使你的工作完成的更輕松,而且會令你的設(shè)計(jì)變得更好,甚至大大減少你花在調(diào)試上面的時(shí)間。 單元測試可以提高底層代碼的正確性,從而提高調(diào)用它的高層代碼的正確性。 使用單元測試這個(gè)簡單有效的技術(shù)就是為了令代碼變得更加完美。,目的與范圍,目的 為了提高軟件開發(fā)效率和質(zhì)量 統(tǒng)一單元測試風(fēng)格 保證文檔與單元 測試編碼的一致性 方便開發(fā)人員進(jìn)行單元測試的開發(fā) 使單元測試能夠有效正常的自動執(zhí)行 范圍 單元測試屬于軟件模塊開發(fā)過程中的活動,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,一個(gè)單元測試(1),簡單的例子: 查找list中的最大值:int Largest(int list, int length); 首份實(shí)現(xiàn)代碼如下: int Largest(int list, int length) int i,max; for(i = 0; i max) max=listi; return max; ,一個(gè)單元測試(2),計(jì)劃你的測試 給定一個(gè)數(shù)組7,8,9,這個(gè)方法返回9。這就構(gòu)成了一個(gè)合理的測試。 你能想出其他一些測試么? 如果list中有兩個(gè)相等的最大值,將會出現(xiàn)什么情況? 7,9,8,9 9 如果list中只有一個(gè)元素,結(jié)果會是怎么樣的呢? 1 1 如果list所包含的是負(fù)數(shù),結(jié)果又會怎么樣呢? -9,-8,-7 -7,一個(gè)單元測試(3),測試一個(gè)簡單的方法 編寫測試代碼 TEST(CheckResult, Max_Int) int list = 7,8,9; CHECK(Largest(List, 3) = 9); 編譯結(jié)果如下,一個(gè)單元測試(4),源程序中被測試方法的錯(cuò)誤查找與修改 發(fā)現(xiàn)max值沒初始化 然后進(jìn)行修改并且設(shè)置max的初始數(shù)值:max=0 重新編譯并運(yùn)行測試 測試運(yùn)行結(jié)果如下:,一個(gè)單元測試(5),再次進(jìn)行源文件被測試方法的bug查找與修改 為什么返回的最大值是8,好像程序根本沒有考慮list中的最后一個(gè)元素似的。 查看源文件,發(fā)現(xiàn)for循環(huán)結(jié)束得早了。 修改:將for循環(huán)中i length-1修改成為i length 編譯源文件并運(yùn)行該測試,程序?qū)]有failure輸出。,一個(gè)單元測試(6),其他考慮到的測試方法的嘗試 存在重復(fù)的最大值的情況 9,7,9,8 只有一個(gè)元素的情況 1 全是負(fù)值的情況 -9,-8,-7 編譯源文件并運(yùn)行修改后的測試,發(fā)現(xiàn)重復(fù)最大值和只有一個(gè)元素的情況,測試都通過了。但是全是負(fù)值的情況出現(xiàn)了問題,如下:,一個(gè)單元測試(7),第三次進(jìn)行源文件被測試方法的bug查找與修改 為什么返回的最大值是0,它是從哪里來的? 看來用0來初始化max是個(gè)錯(cuò)誤的做法 我們應(yīng)該用list0來作為max的初始值 修改過后,便以并重新運(yùn)行該測試,結(jié)果也通過了該測試。,一個(gè)單元測試(8),是否說明獲取數(shù)組最大值的方法已經(jīng)完全沒有問題了呢? 如果數(shù)組為null,會出現(xiàn)什么情況? 如果數(shù)組的長度為0,會出現(xiàn)什么情況? 通常,我們會認(rèn)為這是一個(gè)錯(cuò)誤,將拋出一個(gè)異常,修改方法: int Largest(int list, int length) int i, max; if ( list = null | length = 0) return 0; ,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,測試內(nèi)容,單元測試的對象:軟件設(shè)計(jì)的最小單位模塊或函數(shù),輸入數(shù)據(jù)和形參的定義是否一致; 是否修改了只做輸入用的形式參數(shù); 全局變量的定義在各模塊中是否一致; ,模塊接口,出錯(cuò)處理,獨(dú)立路徑,邊界條件,局部數(shù)據(jù)結(jié)構(gòu),局部變量類型是否正確 是否初始化了 錯(cuò)誤的初始值或錯(cuò)誤的默認(rèn)值 ,運(yùn)算是否正確 邏輯是否正確 是否會產(chǎn)生死循環(huán)、不可終止的迭代 ,對錯(cuò)誤條件的處理不正確 在對錯(cuò)誤進(jìn)行處理之前,錯(cuò)誤條件已經(jīng)引起系統(tǒng)的干預(yù) 模塊是否能恢復(fù)正常 ,在循環(huán)的第0次、1次、n次 運(yùn)算或判斷中取最大最小值時(shí) 輸入?yún)?shù)的最大最小值 ,測試方法:Right-BICEP(1),6個(gè)值得測試的具體部位,他們能夠提高你的測試技巧 Right結(jié)果是否正確? B是否所有的邊界條件都是正確的? I能查一下反向關(guān)聯(lián)嗎? C能用其他手段交叉檢查一下結(jié)果嗎? E你是否可以強(qiáng)制錯(cuò)誤條件發(fā)生? P是否滿足性能要求?,測試方法:Right-BICEP(2),結(jié)果是否正確 如果代碼能夠運(yùn)行正確,我要怎么才知道他是正確的呢? 至少需要確認(rèn)代碼所做的和你的期望是一致的。 使用數(shù)據(jù)文件 對于有大量測試數(shù)據(jù)的測試,考慮使用一個(gè)獨(dú)立的數(shù)據(jù)文件來存儲這些測試數(shù)據(jù),然后單元測試讀取該文件。 對于驗(yàn)證被測方法是正確的這件事情,如果某些做法能夠使它變得更加容易,那就采納它吧。 邊界條件 一個(gè)想到可能的邊界條件的簡單辦法就是記住助記短語CORRECT。 Conformance(一致性):值是否和預(yù)期的一致 Ordering(順序性):值是否如應(yīng)該的那樣,是有序或者無序的 Range(區(qū)間性):值是否位于合理的最小值和最大值之間 Reference(依賴性):代碼是否引用了一些不在代碼本身控制范圍內(nèi)的外部資源 Existence(存在性):值是否存在(是否非null,非0,在一個(gè)集合中等) Cardinatity(基數(shù)性):是否恰好有足夠的值 Time(絕對或者相對的時(shí)間性):所有的事情的發(fā)生是否是有序的?是否是在正確的時(shí)刻?是否恰好及時(shí)?,測試方法:Right-BICEP(3),檢查反向關(guān)聯(lián) 對于某些方法,可以使用反向的邏輯關(guān)系來驗(yàn)證他們。 用對結(jié)果進(jìn)行平方的方式來檢查一個(gè)計(jì)算平方根的方法,然后測試結(jié)果是否和原數(shù)據(jù)很接近 為了檢查某條記錄是否成功插入了數(shù)據(jù)庫,你可以通過查詢這條記錄來驗(yàn)證。 使用其他手段來實(shí)現(xiàn)交叉檢查 計(jì)算一個(gè)量會存在一個(gè)以上的方法??梢岳昧硪粋€(gè)方法來交叉測試原方法的結(jié)果。 使用類本身不同組成部分的數(shù)據(jù)來進(jìn)行交叉檢查。如圖書館的數(shù)據(jù)系統(tǒng),可以通過借出數(shù)和庫存數(shù)之和必定等于所藏書籍總量這種約束來進(jìn)行檢查。,測試方法:Right-BICEP(4),強(qiáng)制產(chǎn)生錯(cuò)誤條件 真實(shí)世界中出現(xiàn)的錯(cuò)誤:磁盤滿,網(wǎng)絡(luò)斷等,可以利用Mock對象 環(huán)境方面的約束的考慮:系統(tǒng)過載、內(nèi)存耗光等 性能特性 要檢查的是性能特性,而不是性能本身。 性能特性有著“隨著輸入尺寸慢慢變大,問題慢慢變復(fù)雜”的趨勢 性能特性的快速回歸測試 由于測試時(shí)間較長,可以考慮每隔幾天運(yùn)行一次 需要使用一些測試工具,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,CORRECT邊界條件(1),邊界條件 一致性(Conformance):值是否符合預(yù)期的格式 有序性(Ordering):一組值是該有序的,還是該無序的 區(qū)間性(Range):值是否在一個(gè)合理的最大值和最小值的范圍之內(nèi) 引用、耦合性(Reference):代碼是否引用了一些不受代碼本身直接控制的外部因素 存在性(Existence):值是否存在(例如,非null,非零,包含于某個(gè)集合等) 基數(shù)性(Cardinality):是否恰好有足夠的值 時(shí)間性(Time):所有事情是否都是按順序發(fā)生的?是否在正確的時(shí)間?是否及時(shí)?,CORRECT邊界條件(2),一致性 很多情況下,你所期望的或產(chǎn)生的數(shù)據(jù)必須符合某種特定的格式。 例如Email地址: 可能還會有一些附加的用點(diǎn)(.)隔開的部分: 可能還會有更少見的格式:firstname.lastname% 再如一類報(bào)告數(shù)據(jù),包括一個(gè)頭部記錄,這個(gè)頭部記錄鏈接到了一些數(shù)據(jù)記錄,最后是尾部記錄。需要測試多少情況? 1.如果沒有頭部記錄,只有數(shù)據(jù)記錄和尾部記錄,要怎樣處理? 2.如果沒有數(shù)據(jù)記錄,只有頭部記錄和尾部記錄,要怎樣處理? 3.如果沒有尾部記錄,只有頭部記錄和數(shù)據(jù)記錄,要怎樣處理? 4.如果只有一個(gè)尾部記錄,要怎樣處理? 5.如果只有一個(gè)頭部記錄,要怎樣處理? 6.如果只有一個(gè)數(shù)據(jù)記錄,要怎樣處理?,CORRECT邊界條件(3),有序性 有時(shí)需要考慮數(shù)據(jù)的順序或者是一個(gè)很大的數(shù)據(jù)集合中某一數(shù)據(jù)的位置 有時(shí)一個(gè)數(shù)據(jù)位于集合中的最前或者最后的時(shí)候,程序中的bug會暴露出來。這是有序性的一個(gè)方面,如查找最大值的方法 有時(shí)需要對一系列數(shù)據(jù)集合按照某種預(yù)定的情況進(jìn)行排序操作。這是有序性的另一個(gè)方面。例如餐館的菜單的集合。 還需要考慮一個(gè)數(shù)據(jù)集合已經(jīng)排好序的情況或者已經(jīng)反向排好序的情況。,CORRECT邊界條件(4),區(qū)間性 對于一個(gè)變量,它所屬類型的取值范圍可能比你需要或想要得更加寬廣。 如我們通常用整形來表示一個(gè)人的歲數(shù),但是顯然沒有人能夠活到20000歲,盡管20000是一個(gè)合法的整型值。 一個(gè)羅盤頭指向的角度不可能大于360度等。 幾乎所有的索引概念都應(yīng)該被大量的測試 開始索引和結(jié)束索引有相同的值 第一個(gè)索引值大于最后一個(gè)索引值 索引值是負(fù)的 索引值大于允許值 Count不能匹配確切索引的個(gè)數(shù) ,CORRECT邊界條件(5),引用/耦合性 程序引用了哪些位于程序之外的事物 程序引用了哪些外部依賴 類應(yīng)該處于什么樣的狀態(tài) 程序運(yùn)行還需要存在哪些其他的條件 一個(gè)已知方法的前條件:系統(tǒng)必須處于什么狀態(tài)下該方法才能運(yùn)行。 一個(gè)已知方法的后條件:你的方法將會保證哪些狀態(tài)發(fā)生,CORRECT邊界條件(6),存在性 給定的事物存在嗎? 如果它為null 如果它為空值 如果它等于0 其他與存在性相關(guān)的陷阱 確認(rèn)你的方法處理了“不存在”的情況,CORRECT邊界條件(7),基數(shù)性 這里的基數(shù)指的就是計(jì)數(shù)(counting) “0-1-n”原則 這是一個(gè)存在性相關(guān)的問題,但是你需要確信:你計(jì)算得到的數(shù)目和你所需要的數(shù)目是一致的。在大部分情況下,只須考慮下面三個(gè)問題: 1.零 2.一 3.多于一 針對基數(shù)性的測試主要考慮:是否具有兩個(gè)或者多個(gè)測試對象。在某些情況下,具體數(shù)目的不同可能也會引入一些差異。 一個(gè)網(wǎng)店系統(tǒng),當(dāng)老板要求實(shí)時(shí)將客戶預(yù)定的前十個(gè)產(chǎn)品的條目發(fā)送到老板的PDA上時(shí),你需要測試哪些內(nèi)容? 列表?xiàng)l目不足十個(gè),列表為空,產(chǎn)品本身就沒有十個(gè)等等,所有這些情況下,能出報(bào)表么? 突然過了三天老板需要前20個(gè)產(chǎn)品的條目,怎么辦? 過了一周后老板又馬上只要前5個(gè)產(chǎn)品的條目,怎么解決? 正確答案是“一行代碼”,類似下面的 #define NUMBER_TO_RETAIN = 20;,CORRECT邊界條件(8),時(shí)間性 需要始終記得以下這些與時(shí)間相關(guān)的方面: 相對時(shí)間(時(shí)間上的順序) 絕對時(shí)間(消耗的時(shí)間和鐘表上的時(shí)間) 并發(fā)問題 問題: 一年中的每一天都是24小時(shí)嗎? 答案:“要看情況”。 在UTC(Universal Coordinated Time,Greenwich Mean Time即GMT的現(xiàn)代版)中,答案是“正確”; 在不遵守DST(Daylight Savings Time)的地方,答案是“正確”; 而在美國的大部分地區(qū)(),答案是“錯(cuò)誤”。四月,會遇到23小時(shí)的一天;十月,會遇到25小時(shí)的一天。 不要期望底層庫會替你正確處理這些問題。不幸的是,底層庫遇到時(shí)間問題,很多代碼會出問題。,CORRECT邊界條件(9),問題 在前面的例子中我們使用了哪些邊界條件?,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,單元測試工具,針對C/C+ 開源 xUnit框架 CppUnit :JUnit移植而來 CppUnitLite:CppUnit的輕量級版本 Google Test:功能強(qiáng)大 Unity :C語言 cMockery :C語言,集成Mock功能,CppUnitLite(1),文件目錄 om CppUnitLite Failure.cpp Failure.h . CppUnitTests Cpp StackMain.cpp StackTest.cpp Stack.h readme.txt,核心代碼,主程序,測試代碼,CppUnitLite(2),使用VC 2008新建工程,CppUnitLite(3),導(dǎo)入文件 CppUintLite的源代碼 測試代碼,CppUnitLite(4),設(shè)置路徑,CppUnitLite(5),主函數(shù)修改 int main() TestResult tr; TestRegistry:runAllTests(tr); getch(); return 0; ,CppUnitLite(6),被測函數(shù) int Add(int Num1, int Num2) return (Num1 + Num2); 編寫測試代碼 TEST(CheckResult, Add) CHECK(Add(0x1, 0x2) = 0x3); ,CppUnitLite(7),運(yùn)行編譯結(jié)果,CppUnitLite(8),編寫測試代碼 TEST(CheckResult, Add) CHECK(0x3 = Add(0x1, 0x2) ); CHECK(0x3 = Add(0x2, 0x2) ); ,Google Test的安裝(1),下載源代碼 /files/gtest-1.3.0.zip 編譯生成Lib文件 使用VC 2008編譯msvc目錄下的工程,生成gtestd.lib,Google Test的安裝(2),設(shè)置gtest頭文件路徑,Google Test的安裝(3),設(shè)置gtest.lib路徑,Google Test的安裝(4),Runtime Library設(shè)置,Google Test的使用(1),主函數(shù)的修改 void _tmain(int argc, _TCHAR* argv) testing:InitGoogleTest( ,Google Test的使用(2),被測函數(shù) int Add(int Num1, int Num2) return (Num1 + Num2); 測試代碼 TEST(AddTest, HandleNoneZeroInput) EXPECT_EQ(3, Add(1, 2); ,Google Test的使用(3),編譯結(jié)果,Google Test的使用(4),測試代碼 TEST(AddTest, HandleNoneZeroInput) EXPECT_EQ(3, Add(1, 2); EXPECT_EQ(3, Add(2, 2); ,Google Test的使用(5),兩類斷言 ASSERT_* 系列 當(dāng)檢查點(diǎn)失敗時(shí),退出當(dāng)前函數(shù)。 EXPECT_* 系列 當(dāng)檢查點(diǎn)失敗時(shí),繼續(xù)往下執(zhí)行。,Google Test的使用(6),檢查的種類 布爾值檢查 數(shù)值型數(shù)據(jù)檢查 字符串檢查 顯示返回成功或失敗 異常檢查 浮點(diǎn)型檢查 類型檢查,Google Test的使用(7),數(shù)值型數(shù)據(jù)檢查,Google Test的參數(shù)化(1),需要測試多組數(shù)據(jù)時(shí) TEST(IsPrimeTest, HandleTrueReturn) EXPECT_EQ(4, Add(1, 3); EXPECT_EQ(5, Add(2, 3); EXPECT_EQ(6, Add(3, 3); EXPECT_EQ(7, Add(4, 3); EXPECT_EQ(8, Add(5, 3); ,Google Test的參數(shù)化(2),參數(shù)化 class IsPrimeParamTest : public:testing:TestWithParam ; INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing:Values(1, 2, 3, 4, 5); TEST_P(IsPrimeParamTest, HandleTrueReturn) int n = GetParam(); EXPECT_EQ(n+3, Add(n, 3); ,參數(shù)生成器,Google Test的參數(shù)化(3),Google Test的參數(shù)化(4),運(yùn)行結(jié)果,Google Test的死亡測試(1),死亡測試 通常在測試過程中,我們需要考慮各種各樣的輸入,有的輸入可能直接導(dǎo)致程序崩潰,這時(shí)我們就需要檢查程序是否按照預(yù)期的方式掛掉,這也就是所謂的“死亡測試”。 Google Test的死亡測試能做到在一個(gè)安全的環(huán)境下執(zhí)行崩潰的測試案例,同時(shí)又對崩潰結(jié)果進(jìn)行驗(yàn)證。 宏定義,Google Test的死亡測試(2),示例 int Div(int Num1, int Num2) return Num1/Num2; TEST(DivDeathTest, Demo) EXPECT_DEATH(Add(1,0), “); ,Google Test的死亡測試(3),運(yùn)行結(jié)果,Unity(1),C語言 2個(gè)文件 unity.c unity.h 可以用TC、GCC、STD等編譯,并下載到板卡運(yùn)行,Unity(1),主程序 int main(void) Unity.TestFile = “main.c“; UnityBegin(); RUN_TEST(test_Add); /*添加測試函數(shù)*/ UnityEnd(); getch(); return 0; ,Unity(3),被測函數(shù) int Add(int Num1, int Num2) return (Num1 + Num2); 測試代碼 void test_Add(void) TEST_ASSERT_EQUAL(3, Add(1,2); ,Unity(4),編譯運(yùn)行結(jié)果,單元測試工具總結(jié),優(yōu)點(diǎn) 自動化 高效率 容易進(jìn)行回歸測試 案例庫(測試用例)不斷豐富,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,Mock對象(1),設(shè)計(jì)了一個(gè)定時(shí)器,每天下午17:00時(shí)產(chǎn)生報(bào)警。 測試時(shí),是否真要等待到17:00?,Mock對象(2),示例:調(diào)用getTime()來返回系統(tǒng)當(dāng)前的日期和時(shí)間 int Alarm() int i = getTime();/讀取時(shí)鐘芯片 if ( 17=i ) Sound();/發(fā)出報(bào)警聲 return 1; else return 0; ,Mock對象(3),在進(jìn)行測試時(shí),可能需要的時(shí)間并非是系統(tǒng)當(dāng)前的時(shí)間,怎么辦?我們可以如下替換: int getTime() if(debug) return debug_cur_time; else /讀取時(shí)鐘芯片 上面的方法是替換的真正功能的手段之一,但有些凌亂,Mock對象(3),Mock對象 Mock對象可以幫助我們解決之前的替換功能。 Mock對象是真實(shí)對象在調(diào)試器的替代品。 系統(tǒng)中真實(shí)對象的一些情況: 真實(shí)對象具有不確定的行為(產(chǎn)生不可預(yù)料的結(jié)果,如股票行情) 真實(shí)對象很難被創(chuàng)建 真實(shí)對象的某些行為很難觸發(fā)(如網(wǎng)絡(luò)錯(cuò)誤) 真實(shí)對象令程序的運(yùn)行速度很慢 真實(shí)對象有(或者是)用戶界面 測試需要詢問真實(shí)對象他是如何被調(diào)用的 真實(shí)對象實(shí)際上并不存在(當(dāng)需要和其他開發(fā)小組,或者新的硬件系統(tǒng)打交道的時(shí)候,這是一個(gè)普遍問題),Mock對象(4),借助于Mock對象,我們可以解決上面提到的所有問題,使用Mock對象的三個(gè)關(guān)鍵步驟: 使用一個(gè)接口來描述這個(gè)對象 為產(chǎn)品代碼實(shí)現(xiàn)這個(gè)接口 以測試為目的,在Mock對象中實(shí)現(xiàn)這個(gè)接口 因?yàn)楸粶y試代碼只會通過接口來引用對象,所以他完全可以不知道他引用的究竟是真實(shí)對象還是Mock對象,cMockery(1),Google在2008年9月15日公開 C單元測試的一個(gè)輕量級的框架 免費(fèi)且開源,google提供技術(shù)支持 輕量級的框架,使測試更加快速簡單; 避免使用復(fù)雜的編譯器特性,對老版本的編譯器來講,兼容性好 并不強(qiáng)制要求待測代碼必須依賴C99標(biāo)準(zhǔn),這一特性對許多嵌入式系統(tǒng)的開發(fā)很有用,cMockery(2),C語言 2個(gè)文件 cmockery.c cmockery.h 可以用GCC等編譯,并下載到板卡運(yùn)行,cMockery(3),模擬接口 int getTime(void) return mock(); 測試代碼 void test_Alarm_succ(void *state) will_return(getTime, 18); assert_true(Alarm() = 0); void test_Alarm_fail(void *state) will_return(getTime, 17); assert_true(Alarm() = 1); ,cMockery(4),主函數(shù) void main() const UnitTest tests = unit_test(test_Alarm_succ), unit_test(test_Alarm_fail), ; run_tests(tests); getch(); ,cMockery(5),編譯運(yùn)行,cMockery(6),分配一塊內(nèi)存,用來存儲你在will_return中設(shè)定的返回值,用函數(shù)名字符串做索引; 在mock()中則通過調(diào)用mock的函數(shù)的名字去匹配,得到已經(jīng)設(shè)定好的存儲在堆內(nèi)存上的那個(gè)值,并返回; 使被測試代碼并不知道測試環(huán)境和真實(shí)環(huán)境之間的區(qū)別,因?yàn)樗鼈兌紝?shí)現(xiàn)了相同的接口; 這樣,我們就可以借助Mock對象,通過把時(shí)間設(shè)置為已知值,進(jìn)而編寫測試; 所有這些,就是Mock對象的全部:偽裝出真實(shí)世界的某些部分,使你可以集中精力測試好自己編寫的代碼。,提綱,序言 一個(gè)單元測試示例 測試內(nèi)容及方法 邊界條件 單元測試工具 Mock對象 好的測試品質(zhì) 在項(xiàng)目中進(jìn)行測試,好的測試品質(zhì)(1),好的測試應(yīng)該具有以下品質(zhì),合稱為A-TRIP 自動化(Automatic) 徹底的(Thorough) 可重復(fù)的(Repeatable) 獨(dú)立的(Independent) 專業(yè)的(Professional),好的測試品質(zhì)(2),自動化 調(diào)用測試自動化 調(diào)用一個(gè)或多個(gè)單元測試對你而言必須是非常容易的 維護(hù)這個(gè)環(huán)境最重要的在于:不要引入一個(gè)由于需要手動步驟而打破這個(gè)自動化模型的測試。 確保任何代碼的簽入都不會損壞位于任何機(jī)器的任何測試的機(jī)制 能夠持續(xù)構(gòu)建和測試 檢查結(jié)果自動化 測試必須能夠自己決定它是通過了還是失敗了。 一致性回歸的一個(gè)重要特征就是讓測試能夠檢查自身。,好的測試品質(zhì)(3),徹底的 他們測試了所有可能會出問題的情況 一個(gè)極端:對于每行代碼、代碼可能達(dá)到的每個(gè)分支、每個(gè)可能拋出的異常等等,都可以作為測試的對象。 另一個(gè)極端:你僅僅測試最可能的情況邊界條件、殘缺和畸形的數(shù)據(jù)等等。 Bug并不是均勻分布在原代碼之中的,它們更傾向于扎堆于一塊問題區(qū)域之中。,好的測試品質(zhì)(4),代碼覆蓋 路徑覆蓋,好的測試品質(zhì)(5),可重復(fù) 測試應(yīng)該能夠以任意的順序一次又一次的運(yùn)行,并且產(chǎn)生相同的結(jié)果。 每個(gè)測試應(yīng)當(dāng)每次產(chǎn)生相同的結(jié)果。如果沒有,那么它應(yīng)當(dāng)告訴你代碼中存在有真正的bug。 獨(dú)立的 測試應(yīng)該是簡潔而且精煉的,這意味著每個(gè)測試都應(yīng)該有很強(qiáng)的針對性,并且獨(dú)立于環(huán)境和其他的測試。 編寫測試時(shí),確保你一次只測試了一樣?xùn)|西。 使用每個(gè)測試都有的setup和teardown以及每個(gè)類的setup和teardown來確保每個(gè)測試獲得一個(gè)全新的開始。,好的測試品質(zhì)(6),專業(yè)的 必須使用和產(chǎn)品代碼相同的專業(yè)水準(zhǔn)來編寫和維護(hù)測試代碼。 測試代碼必須以同產(chǎn)品代碼相同的風(fēng)格來編寫。 測試必須是完整的 意料中的結(jié)果是編寫的測試代碼至少和產(chǎn)品代碼一樣多。,好的測試品質(zhì)(7),對測試進(jìn)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論