软件测试基础 (一): 单元测试
Hello!大家好,我是BugBear,一個(gè)專注于分享軟件測試干貨的測試開發(fā)。
對(duì)于軟件測試,我們先按照開發(fā)階段來進(jìn)行劃分,將軟件測試分為單元測試、集成測試、系統(tǒng)測試、驗(yàn)收測試,下面我們來聊聊單元測試。
1、什么是單元測試?
在正式闡述什么是單元測試之前,我先給大家分享一個(gè)工廠組裝手機(jī)的例子。
手機(jī)組裝流水線按照?qǐng)D紙將各個(gè)電子元件組裝焊接為各個(gè)模塊組件(如喇叭,聽筒,麥克,FPC,按鍵板,攝像頭,LCD等),再將各個(gè)模塊組件組裝成一部完整的手機(jī)。
如果一起順利,在給手機(jī)安裝系統(tǒng)后就可以正常使用了。但是很不幸,大多數(shù)情況下的手機(jī)是無法使用的,那么就需要將已經(jīng)組裝好的手機(jī)重新拆機(jī),逐個(gè)模塊排查問題,在每個(gè)模塊排查中需要對(duì)每個(gè)電子元件進(jìn)行檢測,通過花費(fèi)大量的時(shí)間和精力才能定位到問題原因。
那么在后續(xù)的生產(chǎn)中,如何才能避免這種問題的發(fā)生呢?
你可能立即就會(huì)想到,為什么不在組裝焊接前,就先測試每個(gè)要用到的電子元器件呢?這樣你就可以先排除有問題的元器件,最大程度地防止組裝完成后逐級(jí)排查問題的事情發(fā)生。
實(shí)踐也證明,這的確是一個(gè)行之有效的好辦法。
如果把手機(jī)的生產(chǎn)、測試和軟件的開發(fā)、測試進(jìn)行類比,你可以發(fā)現(xiàn):
-
電子元器件就像是軟件中的單元,通常是函數(shù)或者類,對(duì)單個(gè)元器件的測試就像是軟件測試中的單元測試;
-
組裝完成的功能模塊組件如喇叭,聽筒,麥克,FPC,按鍵板,攝像頭,LCD等就像是軟件中的模塊,對(duì)功能模塊組件的測試就像是軟件中的集成測試;
-
手機(jī)全部組裝并安裝系統(tǒng)就像是軟件完成了預(yù)發(fā)布版本,手機(jī)全部組裝并安裝系統(tǒng)完成后的開機(jī)測試就像是軟件中的系統(tǒng)測試;
通過這個(gè)類比,相信你已經(jīng)體會(huì)到了單元測試對(duì)于軟件整體質(zhì)量的重要性,那么單元測試到底是什么呢?
單元測試是指,對(duì)軟件中的最小可測試單元在與程序其他部分相隔離的情況下進(jìn)行檢查和驗(yàn)證的工作,這里的最小可測試單元通常是指函數(shù)或者類。
2、什么是好的單元測試?
好的單元測試應(yīng)當(dāng)包含四種特性:正確,清晰,完整,健壯
-
正確:單元測試是最基礎(chǔ)的要求,必須要保證所寫的函數(shù)或者類實(shí)現(xiàn)的功能是正確的,如果實(shí)現(xiàn)的功能都不能滿足,那就是缺陷!
-
清晰:單元測試可以幫助其他開發(fā)理解函數(shù)或者類的實(shí)現(xiàn),所以要求單元測試用例簡潔、清晰,需要有良好的可讀性
-
完整:單元測試需要考慮輸入與輸出組合的各種場景,保證單元測試的覆蓋率
-
健壯:健壯性是最容易被忽略的一項(xiàng),當(dāng)被測試的類或者函數(shù)被修改內(nèi)部實(shí)現(xiàn)或者添加功能時(shí),?個(gè)好的單測應(yīng)該完全不需要被修改或者只有極少的修改。?如?個(gè)排序函數(shù)的單測實(shí)現(xiàn)是完全穩(wěn)定的,它不應(yīng)該跟著不同的排序算法?變化
3、怎么寫單元測試?
可能大多數(shù)的測試人員不會(huì)接觸到單元測試的編寫,因?yàn)榘凑瘴覀€(gè)人的看法,開發(fā)人員根據(jù)自己寫的代碼編寫單測用例是最合適不過的,也是最高效的。
雖然我們不需要實(shí)際去編寫單測用例,但是我們還是需要了解怎么寫單元測試。
單元測試的代碼結(jié)構(gòu)一般包含三部分:分別是準(zhǔn)備、調(diào)用與斷言
-
準(zhǔn)備:準(zhǔn)備部分的?的是準(zhǔn)備好調(diào)?所需要的外部環(huán)境,如數(shù)據(jù),Stub(樁代碼),Mock,臨時(shí)變量,調(diào)?請(qǐng)求,環(huán)境背景變量等等。
-
調(diào)用:調(diào)?部分則是實(shí)際調(diào)?需要測試?法,即函數(shù)或者流程本身。
-
斷言:斷?部分判斷調(diào)?部分的返回結(jié)果是否符合預(yù)期。
每個(gè)單元測試都應(yīng)該能清晰地分出這三部分,當(dāng)然有時(shí)調(diào)?斷?兩部分合在?起也是?較常見的。
4、玩轉(zhuǎn)單元測試
下面我們來聊聊單元測試編寫用例的相關(guān)知識(shí),首先我們需要了解單元測試的三個(gè)重要部分,即驅(qū)動(dòng)程序、樁程序、Mock
驅(qū)動(dòng)程序:驅(qū)動(dòng)程序(Driver)也稱作驅(qū)動(dòng)模塊,用以模擬被測模塊的上級(jí)模塊,能夠調(diào)用被測模塊。在測試過程中,驅(qū)動(dòng)模塊接收測試數(shù)據(jù),調(diào)用被測模塊并把相關(guān)的數(shù)據(jù)傳送給被測模塊。
簡單說就是你負(fù)責(zé)測試的模塊沒有main()方法入口,所以需要寫一個(gè)帶main的方法來調(diào)用你的模塊或方法。這個(gè)就是驅(qū)動(dòng)測試
樁程序:樁程序(Stub),也稱樁模塊,用以模擬被測模塊工作過程中所調(diào)用的下層模塊,即被測模塊本身調(diào)用的其他關(guān)聯(lián)函數(shù)。樁模塊由被測模塊調(diào)用,它們一般只進(jìn)行很少的數(shù)據(jù)處理。
樁是指用來代替關(guān)聯(lián)代碼或者未實(shí)現(xiàn)的代碼,為了讓測試對(duì)象可以正常的執(zhí)行,其實(shí)一般會(huì)硬編碼一些輸入和輸出,保證被測模塊能夠正常運(yùn)行?
Mock:Mock除了保證Stub的功能之外,還可深入的模擬對(duì)象之間的交互方式,如:調(diào)用了幾次、在某種情況下是否會(huì)拋出異常以及提供數(shù)據(jù)斷言
接下來我們通過一個(gè)實(shí)例來學(xué)習(xí)單元測試用例的編寫
# 待測試的方法 def calculator(type):# 調(diào)用樁代碼獲取數(shù)據(jù)num1 = __stub1()num2 = __stub2()# 調(diào)用mockmock_data = __mock_check()# +if type.lower() == 'add':type = 'add'ret = num1+num2assert ret == mock_data[type]print('{} + {} = {}'.format(num1,num2,ret))return ret# -if type.lower() == 'minus':type = 'minus'ret = num1-num2assert ret == mock_data[type]print('{} - {} = {}'.format(num1,num2,ret))return ret# *if type.lower() == 'multiply':type = 'multiply'ret = num1*num2assert ret == mock_data[type]print('{} * {} = {}'.format(num1,num2,ret))return ret# /if type.lower() == 'divide':type = 'divide'if num2 == 0:print('除法分母不能為0')return '除法分母不能為0'else:ret = num1/num2assert ret == mock_data[type]print('{} / {} = {}'.format(num1,num2,ret))return ret# 樁代碼1 def __stub1():output = 20print('my stub的值是{}'.format(output))return output# 樁代碼2 def __stub2():output = 5print('my stub的值是{}'.format(output))return output# Mock代碼 => 提供斷言數(shù)據(jù) def __mock_check():mock_result = {}mock_result['add'] = 25mock_result['minus'] = 15mock_result['multiply'] = 100mock_result['divide'] = 4return mock_result# 驅(qū)動(dòng)程序 if __name__=="__main__":print(calculator('add'))print(calculator('minus'))print(calculator('multiply'))print(calculator('divide'))?上面提供的是一個(gè)簡單的單元測試,包含了驅(qū)動(dòng)程序、被測對(duì)象、樁程序以及Mock代碼
-
驅(qū)動(dòng)程序__main__作為被測對(duì)象的上級(jí)模塊,運(yùn)行時(shí)調(diào)用被測函數(shù)calculator
-
被測函數(shù)calculator被調(diào)用后,通過樁代碼__stub1、__stub2提供測試數(shù)據(jù)
-
被測函數(shù)calculator通過不同的入?yún)⑵ヅ洳煌膱鼍?#xff0c;不同場景獲取的結(jié)果與Mock函數(shù)__mock_check進(jìn)行比對(duì)斷言,校驗(yàn)結(jié)果是否符合預(yù)期
被測函數(shù)成功返回如下:
my stub的值是20 my stub的值是5 20 + 5 = 25 25被測函數(shù)失敗返回如下:
my stub的值是20 Traceback (most recent call last): my stub的值是5File "/Users/Desktop/demo/unittest_demo/ut_demo.py", line 73, in <module>print(calculator('add'))File "/Users/Desktop/demo/unittest_demo/ut_demo.py", line 21, in calculatorassert ret == mock_data[type] AssertionErrorBugBear軟件測試,專注于分享測試干貨,在分享的過程中提升自己,歡迎關(guān)注,交流成長。
總結(jié)
以上是生活随笔為你收集整理的软件测试基础 (一): 单元测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++远征之多态篇——运行时类型识别(R
- 下一篇: 字符设备驱动基础篇0——驱动开发初体验