🍅 點擊文末小卡片,免費獲取軟件測試全套資料,資料在手,漲薪更快
對于軟件測試,我們先按照開發階段來進行劃分,將軟件測試分為單元測試、集成測試、系統測試、驗收測試,下面我們來聊聊單元測試。
1、什么是單元測試?
在正式闡述什么是單元測試之前,我先給大家分享一個工廠組裝手機的例子。
手機組裝流水線按照圖紙將各個電子元件組裝焊接為各個模塊組件(如喇叭,聽筒,麥克,FPC,按鍵板,攝像頭,LCD等),再將各個模塊組件組裝成一部完整的手機。
如果一起順利,在給手機安裝系統后就可以正常使用了。但是很不幸,大多數情況下的手機是無法使用的,那么就需要將已經組裝好的手機重新拆機,逐個模塊排查問題,在每個模塊排查中需要對每個電子元件進行檢測,通過花費大量的時間和精力才能定位到問題原因。
那么在后續的生產中,如何才能避免這種問題的發生呢?
你可能立即就會想到,為什么不在組裝焊接前,就先測試每個要用到的電子元器件呢?這樣你就可以先排除有問題的元器件,最大程度地防止組裝完成后逐級排查問題的事情發生。
實踐也證明,這的確是一個行之有效的好辦法。
如果把手機的生產、測試和軟件的開發、測試進行類比,你可以發現:
- 電子元器件就像是軟件中的單元,通常是函數或者類,對單個元器件的測試就像是軟件測試中的單元測試;
- 組裝完成的功能模塊組件如喇叭,聽筒,麥克,FPC,按鍵板,攝像頭,LCD等就像是軟件中的模塊,對功能模塊組件的測試就像是軟件中的集成測試;
- 手機全部組裝并安裝系統就像是軟件完成了預發布版本,手機全部組裝并安裝系統完成后的開機測試就像是軟件中的系統測試;
通過這個類比,相信你已經體會到了單元測試對于軟件整體質量的重要性,那么單元測試到底是什么呢?
單元測試是指,對軟件中的最小可測試單元在與程序其他部分相隔離的情況下進行檢查和驗證的工作,這里的最小可測試單元通常是指函數或者類。
2、什么是好的單元測試?
好的單元測試應當包含四種特性:正確,清晰,完整,健壯
- 正確:單元測試是最基礎的要求,必須要保證所寫的函數或者類實現的功能是正確的,如果實現的功能都不能滿足,那就是缺陷!
- 清晰:單元測試可以幫助其他開發理解函數或者類的實現,所以要求單元測試用例簡潔、清晰,需要有良好的可讀性
- 完整:單元測試需要考慮輸入與輸出組合的各種場景,保證單元測試的覆蓋率
- 健壯:健壯性是最容易被忽略的一項,當被測試的類或者函數被修改內部實現或者添加功能時,一個好的單測應該完全不需要被修改或者只有極少的修改。比如?個排序函數的單測實現是完全穩定的,它不應該跟著不同的排序算法的變化
3、怎么寫單元測試?
可能大多數的測試人員不會接觸到單元測試的編寫,因為按照我個人的看法,開發人員根據自己寫的代碼編寫單測用例是最合適不過的,也是最高效的。
雖然我們不需要實際去編寫單測用例,但是我們還是需要了解怎么寫單元測試。
單元測試的代碼結構一般包含三部分:分別是準備、調用與斷言
- 準備:準備部分的?的是準備好調?所需要的外部環境,如數據,Stub(樁代碼),Mock,臨時變量,調?請求,環境背景變量等等。
- 調用:調?部分則是實際調?需要測試?法,即函數或者流程本身。
- 斷言:斷?部分判斷調?部分的返回結果是否符合預期。
每個單元測試都應該能清晰地分出這三部分,當然有時調?斷?兩部分合在?起也是?較常見的。
4、玩轉單元測試
下面我們來聊聊單元測試編寫用例的相關知識,首先我們需要了解單元測試的三個重要部分,即驅動程序、樁程序、Mock
驅動程序:驅動程序(Driver)也稱作驅動模塊,用以模擬被測模塊的上級模塊,能夠調用被測模塊。在測試過程中,驅動模塊接收測試數據,調用被測模塊并把相關的數據傳送給被測模塊。
簡單說就是你負責測試的模塊沒有main()方法入口,所以需要寫一個帶main的方法來調用你的模塊或方法。這個就是驅動測試
樁程序:樁程序(Stub),也稱樁模塊,用以模擬被測模塊工作過程中所調用的下層模塊,即被測模塊本身調用的其他關聯函數。樁模塊由被測模塊調用,它們一般只進行很少的數據處理。
樁是指用來代替關聯代碼或者未實現的代碼,為了讓測試對象可以正常的執行,其實一般會硬編碼一些輸入和輸出,保證被測模塊能夠正常運行
Mock:Mock除了保證Stub的功能之外,還可深入的模擬對象之間的交互方式,如:調用了幾次、在某種情況下是否會拋出異常以及提供數據斷言
接下來我們通過一個實例來學習單元測試用例的編寫
# 待測試的方法
def calculator(type):# 調用樁代碼獲取數據num1 = __stub1()num2 = __stub2()# 調用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代碼 => 提供斷言數據
def __mock_check():mock_result = {}mock_result['add'] = 25mock_result['minus'] = 15mock_result['multiply'] = 100mock_result['divide'] = 4return mock_result# 驅動程序
if __name__=="__main__":print(calculator('add'))print(calculator('minus'))print(calculator('multiply'))print(calculator('divide'))
上面提供的是一個簡單的單元測試,包含了驅動程序、被測對象、樁程序以及Mock代碼
- 驅動程序__main__作為被測對象的上級模塊,運行時調用被測函數calculator
- 被測函數calculator被調用后,通過樁代碼__stub1、__stub2提供測試數據
- 被測函數calculator通過不同的入參匹配不同的場景,不同場景獲取的結果與Mock函數__mock_check進行比對斷言,校驗結果是否符合預期
被測函數成功返回如下:
my stub的值是20
my stub的值是5
20 + 5 = 25
25
被測函數失敗返回如下:
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]
AssertionError
最后感謝每一個認真閱讀我文章的人,禮尚往來總是要有的,雖然不是什么很值錢的東西,如果你用得到的話可以直接拿走:
這些資料,對于做【軟件測試】的朋友來說應該是最全面最完整的備戰倉庫,這個倉庫也陪伴我走過了最艱難的路程,希望也能幫助到你!凡事要趁早,特別是技術行業,一定要提升技術功底。