軟件開發(fā)公司,本文將進(jìn)入單元測試的部分,這也是基礎(chǔ)知識(shí)中較后一個(gè)大塊。本文將重點(diǎn)講述Python和OpenStack中的單元測試的生態(tài)環(huán)境。
通過demo學(xué)習(xí)OpenStack開發(fā)——單元測試
單元測試的重要性
單元測試工具
unittest
mock
testtools
fixtures
testscenarios
subunit
testrepository
coverage
tox
單元測試工具小結(jié)
Keystone的單元測試框架
使用tox進(jìn)行測試環(huán)境管理
使用testrepository管理測試的運(yùn)行
單元測試用例的代碼架構(gòu)
總結(jié)
系列后記
單元測試的重要性
GitHub上有個(gè)人畫了一些不同語言的學(xué)習(xí)曲線圖:Learning Curves (for different programming languages),雖然有些惡搞的傾向,不過確實(shí)說明了問題。這里貼一下Python的部分:
這個(gè)圖說明了,會(huì)單元測試對于提高Python生產(chǎn)力的重要性,這主要是因?yàn)镻ython是個(gè)動(dòng)態(tài)語言,很多問題都無法通過靜態(tài)編譯檢查來發(fā)現(xiàn),因此單元測試就成了一個(gè)重要的確保質(zhì)量的手段。OpenStack的核心項(xiàng)目都對單元測試有極高的要求,以保證項(xiàng)目的高質(zhì)量。
單元測試工具
Python的單元測試工具很多,為單元測試提供不同方面的功能。OpenStack的項(xiàng)目也基本把現(xiàn)在流行的單元測試工具都用全了。單元測試可以說是入門OpenStack開發(fā)的較難的部分,也是較后一公里。本章,我們就介紹一下在OpenStack中會(huì)用到的單元測試的工具。由于數(shù)量很多,不可能詳細(xì)介紹,因此主要做一些概念和用途上的介紹。
unittest
unittest是Python的標(biāo)準(zhǔn)庫,提供了較基本的單元測試功能,包括單元測試運(yùn)行器(簡稱runner)和單元測試框架。項(xiàng)目的單元測試代碼的測試類可以繼承unittest.TestCase類,這樣這個(gè)類就能夠被runner發(fā)現(xiàn)并且執(zhí)行。同時(shí),unittest.TestCase這個(gè)類還定義了setUp(),tearDown(),setUpClass()和tearDownClass()方法,是用來運(yùn)行單元測試前的設(shè)置工作代碼和單元測試后的清理工作代碼,這個(gè)也是所有Python代碼遵守的規(guī)范,所以第三方的單元測試庫和框架也都遵循這個(gè)規(guī)范。
unittest庫也提供了一個(gè)runner,可以使用$ python -m unittest test_module的命令來執(zhí)行某個(gè)模塊的單元測試。另外,在Python中指定要運(yùn)行的單元測試用例的完整語法是:path.to.your.module:ClassOfYourTest.test_method。
unittest是學(xué)習(xí)Python單元測試較基本也較重要的一個(gè)庫,完整的說明請查看官方文檔。
mock
mock也是另一個(gè)重要的單元測試庫,在Python 2中是作為一個(gè)第三方庫被使用的,到Python 3時(shí),就被納入了標(biāo)準(zhǔn)庫,可見這個(gè)庫的重要性。簡單的說,mock就是用來模擬對象的行為,這樣在進(jìn)行單元測試的時(shí)候,可以指定任何對象的返回值,便于測試對外部接口有依賴的代碼。關(guān)于mock的使用,可以查看我之前寫的這篇文章Python Mock的入門。
testtools
testtools是個(gè)unittest的擴(kuò)展框架,主要是在unittest的基礎(chǔ)上提供了更好的assert功能,使得寫單元測試更加方便。具體可以查看文檔。
fixtures
fixture的意思是固定裝置,在Python的單元測試中,是指某段可以復(fù)用的單元測試setUp和tearDown代碼組合。一個(gè)fixture一般用來實(shí)現(xiàn)某個(gè)組件的setUp和tearDown邏輯,比如測試前要先創(chuàng)建好某些數(shù)據(jù),測試后要?jiǎng)h掉這些數(shù)據(jù),這些操作就可以封裝到一個(gè)fixture中。這樣不同的測試用例就不用重復(fù)寫這些代碼,只要使用fixture即可。fixtures模塊是一個(gè)第三方模塊,提供了一種簡單的創(chuàng)建fixture類和對象的機(jī)制,并且也提供了一些內(nèi)置的fixture。具體的使用方法可以查看官方文檔。
testscenarios
testscenarios模塊滿足了場景測試的需求。它的基本用法是在測試類中添加一個(gè)類屬性scenarios,該屬性是一個(gè)元組,定義了每一種場景下不同的變量的值。比如說你測試一段數(shù)據(jù)訪問代碼,你需要測試該代碼在使用不同的驅(qū)動(dòng)時(shí),比如MongoDB、SQL、File,是否都能正常工作。我們有三種辦法:
較笨的辦法是為不同的驅(qū)動(dòng)把同一個(gè)測試用例編寫3遍。
比較好的辦法是,編寫一個(gè)統(tǒng)一的非測試用例方法,接收driver作為參數(shù),執(zhí)行測試邏輯,然后再分別編寫三個(gè)測試用例方法去調(diào)用這個(gè)非測試用例方法。
更好的辦法就是使用testscenarios模塊,定義好scenarios變量,然后實(shí)現(xiàn)一個(gè)測試用例方法。
testscenarios模塊在OpenStack Ceilometer中被大量使用。更多的信息可以查看文檔。
subunit
subunit是一個(gè)用于傳輸單元測試結(jié)果的流協(xié)議。一般來說,運(yùn)行單元測試的時(shí)候是把單元測試的結(jié)果直接輸出到標(biāo)準(zhǔn)輸出,但是如果運(yùn)行大量的測試用例,這些測試結(jié)果就很難被分析。因此就可以使用python-subunit模塊來運(yùn)行測試用例,并且把測試用例通過subunit協(xié)議輸出,這樣測試結(jié)果就可以被分析工具聚合以及分析。python-subunit模塊自帶了一些工具用來解析subunit協(xié)議,比如你可以這樣運(yùn)行測試用例:$ python -m subunit.run test_module | subunit2pyunit,subunit2pyunit命令會(huì)解析subunit協(xié)議,并且輸出到標(biāo)準(zhǔn)輸出。關(guān)于subunit的更多信息,請查看官方文檔。
testrepository
OpenStack中使用testrepository模塊管理單元測試用例。當(dāng)一個(gè)項(xiàng)目中的測試用例很多時(shí),如何更有效的處理單元測試用例的結(jié)果就變得很重要。testrepository的出現(xiàn)就是為了解決這個(gè)問題。testrepository使用python-subunit模塊來運(yùn)行測試用例,然后分析subunit的輸出并對測試結(jié)果進(jìn)行記錄(記錄到本地文件)。舉例來說,testrepository允許你做這樣的事情:
知道哪些用例運(yùn)行時(shí)間較長
顯示運(yùn)行失敗的用例
重新運(yùn)行上次運(yùn)行失敗的用例
testrepository的更多信息,請查看官方文檔。
coverage
coverage是用來計(jì)算代碼運(yùn)行時(shí)的覆蓋率的,也就是統(tǒng)計(jì)多少代碼被執(zhí)行了。它可以和testrepository一起使用,用來統(tǒng)計(jì)單元測試的覆蓋率,在運(yùn)行完單元測試之后,輸出覆蓋率報(bào)告。具體的使用方法可以查看官方文檔。
tox
tox是用來管理和構(gòu)建虛擬環(huán)境(virtualenv)的。對于一個(gè)項(xiàng)目,我們需要運(yùn)行Python 2.7的單元測試,也需要運(yùn)行Python 3.4的單元測試,還需要運(yùn)行PEP8的代碼檢查。這些不同的任務(wù)需要依賴不同的庫,所以需要使用不同的虛擬環(huán)境。使用tox的時(shí)候,我們會(huì)在tox的配置文件tox.ini中指定不同任務(wù)的虛擬環(huán)境名稱,該任務(wù)在虛擬環(huán)境中需要安裝哪些包,以及該任務(wù)執(zhí)行的時(shí)候需要運(yùn)行哪些命令。更多信息,請查看官方文檔。
單元測試工具小結(jié)
本章介紹了OpenStack中常用的單元測試工具的基本用途,希望大家對這些工具有個(gè)大概的認(rèn)識(shí)。這里我們可以按照類別總結(jié)一下這些工具:
測試環(huán)境管理: tox
使用tox來管理測試運(yùn)行的虛擬環(huán)境,并且調(diào)用testrepository來執(zhí)行測試用例。
測試用例的運(yùn)行和管理: testrepository, subunit, coverage
testrepository調(diào)用subunit來執(zhí)行測試用例,對測試結(jié)果進(jìn)行聚合和管理;調(diào)用coverage來執(zhí)行代碼覆蓋率的計(jì)算。
測試用例的編寫: unittest, mock, testtools, fixtures, testscenarios
使用testtools作為所有測試用例的基類,同時(shí)應(yīng)用mock, fixtures, testscenarios來更好的編寫測試用例。
在The Hacker's Guide to Python(《Python高手之路》)一書中,也有專門的一章介紹了各種單元測試工具及其用法,讀者也可以參考一下。下一章,我們來分析Keystone項(xiàng)目的單元測試框架,可以讓你看到在OpenStack的實(shí)際項(xiàng)目中,這些工具是如何被使用的。