軟件(jiàn)開(kāi)發公司,本文(wén)将進入單元測試的(de)部分(fēn),這(zhè↔±)也(yě)是(shì)基礎知(zhī)識中較γ∞₹'後一(yī)個(gè)大(dà)塊。本文(wén)将重點講述 ±∞Python和(hé)OpenStack中的(de)單元測試的(☆δφ£de)生(shēng)态環境。
通(tōng)過demo學習(xí)Oα≠penStack開(kāi)發——單σ€✘元測試
單元測試的(de)重要(yào)性
單元測試工(gōng)具
unittest
mock
testtools
fixtures
testscenarios
subunit
testrepository
coverage
tox
單元測試工(gōng)具小(xiǎo)結
Keystone的(de)單元測試框架
使用(yòng)tox進行(xíng)測試環境管理(lǐ)
使用(yòng)testrepository管理≈•↓→(lǐ)測試的(de)運行(xíng)
單元測試用(yòng)例的(de)代碼架構
總結
系列後記
單元測試的(de)重要(yào)性
GitHub上(shàng)有(yǒu)個(gè) ↕φ 人(rén)畫(huà)了(le)一(yī)些(xiē)不(bùσ® )同語言的(de)學習(xí)曲線圖:Learning Curv≈ <es (for different progr€∏amming languages),雖然有(yǒu)些(xiē↕×)惡搞的(de)傾向,不(bù)過确實說(shuō)明(míng)了£✘(le)問(wèn)題。這(zhè)裡(lǐ)貼一(yī)下(←÷©γxià)Python的(de)部分(fēn):
這(zhè)個(gè)圖說(shuō)明(míng)了(←®le),會(huì)單元測試對(duì)于提高(gāo)Python∞ ≥生(shēng)産力的(de)重要(yà↑✔o)性,這(zhè)主要(yào)是(shì)因為(wδ$λ∑èi)Python是(shì)個(gè)動态語言,很(hěn™ )多(duō)問(wèn)題都(dōu)無法通(tōng)過靜(↔¶jìng)态編譯檢查來(lái)發現(xiàn),因此單元測試就≥ε(jiù)成了(le)一(yī)個(gè)重要(yào)的(de)确保質量的↑♥(de)手段。OpenStack的(de)核心項目都(dōu)對(dφφ™uì)單元測試有(yǒu)極高(gāo)的(d™γ< e)要(yào)求,以保證項目的(de)高(gā¶$¶εo)質量。
單元測試工(gōng)具
Python的(de)單元測試工(gōng)具很(hěn)多(duō),為 ₩(wèi)單元測試提供不(bù)同方面的(de)功能(néng)≈¥↕。OpenStack的(de)項目也(yě)基本把現(xiànγ>φ♠)在流行(xíng)的(de)單元測試工(gōng)具都(dōu)用"♠ (yòng)全了(le)。單元測試可(kě)以說(shuō)↑<π是(shì)入門(mén)OpenSta←•ck開(kāi)發的(de)較難的(de)部分(fēn),也(yě)是♥δ(shì)較後一(yī)公裡(lǐ)。本章(zhāng),我們就→γ∏φ(jiù)介紹一(yī)下(xià)在OpenStack中>±×≈會(huì)用(yòng)到(dào)的(de)單元測試的(de)工(g£±ōng)具。由于數(shù)量很(hěn)多(duō)λ±,不(bù)可(kě)能(néng)詳細介紹,因此主要(÷πyào)做(zuò)一(yī)些(xiē)概念和(hδ≈é)用(yòng)途上(shàng)的(de)介紹。
unittest
unittest是(shì)Python的(d•™e)标準庫,提供了(le)較基本的(de)單元測試功能(nαδéng),包括單元測試運行(xíng)器(qì)(簡稱ru∑±nner)和(hé)單元測試框架。項目的✔•π$(de)單元測試代碼的(de)測試類可(kě)以繼承unittest.€$TestCase類,這(zhè)樣這(zhè)個(gè)λ≤類就(jiù)能(néng)夠被runner發現≥←(xiàn)并且執行(xíng)。同時(shí),unittest.TestC≤©•ase這(zhè)個(gè)類還(hái)定義了(le)setUp(£©↕π),tearDown(),setUpClass(>π→)和(hé)tearDownClass()方法,是(sα≤βhì)用(yòng)來(lái)運行(xíng)單元測試前的(de)設置工(gΩα₹αōng)作(zuò)代碼和(hé)單元測試後的(de)清理(lβ♣←ǐ)工(gōng)作(zuò)代碼,這(zhè)個(gè)也(y≠→↕✔ě)是(shì)所有(yǒu)Python₽↑≤代碼遵守的(de)規範,所以第三方的(de ♥★φ)單元測試庫和(hé)框架也(yě)都(dōu)遵循這(z© ¶∑hè)個(gè)規範。
unittest庫也(yě)提供了(le)一(yī)個(gλè)runner,可(kě)以使用(yòng)$ python φ↑&¥-m unittest test_module的(dαα↑¶e)命令來(lái)執行(xíng)某個(gè)模塊$₹δ的(de)單元測試。另外(wài),在Python中指定要(yào)運行(xβ↕íng)的(de)單元測試用(yòng)例的(de)完整語法是(™≤shì):path.to.your.module:Cl☆±£assOfYourTest.test_method'→≠↔。
unittest是(shì)學習(xí)Python單↓★™δ元測試較基本也(yě)較重要(yào)的(de)★↕ π一(yī)個(gè)庫,完整的(de)說(shuō)明(mín¶∞®♥g)請(qǐng)查看(kàn)官方文(wén)檔。
mock
mock也(yě)是(shì)另一(yī)個(gè)重要(yào)的∑¥₽(de)單元測試庫,在Python 2中是(shì)作(zuò)為(wèi↕♦)一(yī)個(gè)第三方庫被使用(yòng)的(de),到(§"dào)Python 3時(shí),就(jiù)被納入了(le)标準≤☆←庫,可(kě)見(jiàn)這(zhè)個(gè)庫的(d↕↑λ←e)重要(yào)性。簡單的(de)說(shuō),mock就≤≈♥(jiù)是(shì)用(yòng)來(lái)模拟對(duì)象的(de)行'(xíng)為(wèi),這(zhè)樣在進行(xí€$σ ng)單元測試的(de)時(shí)候,可(kě)以指定任何對(d©≥uì)象的(de)返回值,便于測試對(duì)外(wài)部接口有(yǒu€÷ )依賴的(de)代碼。關于mock的(de)使用(yòng),可(kě§♥β)以查看(kàn)我之前寫的(de)這(zhè)篇文(wén)章(zhāngσ•)Python Mock的(de)入門(mén)。
testtools
testtools是(shì)個(gè)unittest的(de)擴展框 π₽β架,主要(yào)是(shì)在unittesε¶t的(de)基礎上(shàng)提供了(l≤'↕e)更好(hǎo)的(de)assert<λ功能(néng),使得(de)寫單元測試更加方<®≥₽便。具體(tǐ)可(kě)以查看(kàn)文(wén)檔。
fixtures
fixture的(de)意思是(sh☆¥ì)固定裝置,在Python的(de)單元測試中,是↔↕★(shì)指某段可(kě)以複用(yòng)的(de)單元測試setU•γp和(hé)tearDown代碼組合。一(yī)個(gè)fixture一↑₹>δ(yī)般用(yòng)來(lái)實現(xiàn)某個(gè)♦÷✘組件(jiàn)的(de)setUp和(hé)tearDown♣®邏輯,比如(rú)測試前要(yào)先創建好(hǎ≠↔o)某些(xiē)數(shù)據,測試後要(yào)删掉這(z ♣¶hè)些(xiē)數(shù)據,這(zhè)≤&些(xiē)操作(zuò)就(jiù)可(kě)以封ε裝到(dào)一(yī)個(gè)fix§ture中。這(zhè)樣不(bù)同的(de)測試用(yòng)例就(ji δù)不(bù)用(yòng)重複寫這(zhè)些(xiē"γ<λ)代碼,隻要(yào)使用(yòng)fixtu∑±★re即可(kě)。fixtures模塊是(shì)∏ ↓一(yī)個(gè)第三方模塊,提供了(le)一(yī)種簡單的(de)創 Ω 建fixture類和(hé)對(duì)象的(de)機(jī)制β (zhì),并且也(yě)提供了(le)一(<πσyī)些(xiē)內(nèi)置的(de)fixtur★ λe。具體(tǐ)的(de)使用(yòng)方法™₽可(kě)以查看(kàn)官方文(wén)檔。
testscenarios
testscenarios模塊滿足了(le)場(ch£&±±ǎng)景測試的(de)需求。它的(de)基本用(yòng)法是(shì)±±φ在測試類中添加一(yī)個(gè)類屬性scenarλ∞¥ios,該屬性是(shì)一(yī)個(gè)元組,定義了( εδle)每一(yī)種場(chǎng)景下(♥×₹±xià)不(bù)同的(de)變量的(de)值。比如(rú)¥ε✘說(shuō)你(nǐ)測試一(yī)段數(shù)¥據訪問(wèn)代碼,你(nǐ)需要(yào)®§€₹測試該代碼在使用(yòng)不(bù)同的(de)驅動時(shí),比如(r♣₹ú)MongoDB、SQL、File,是(shì)否都π↕(dōu)能(néng)正常工(gōng)作(zε§uò)。我們有(yǒu)三種辦法:
較笨的(de)辦法是(shì)為(wèi)不(bù)同的(de)驅動<♥>把同一(yī)個(gè)測試用(yòng)例編寫3遍。
比較好(hǎo)的(de)辦法是(shì),編寫一(yī)個(gè)統一(©"± yī)的(de)非測試用(yòng)例方法,接收driver作(&¥zuò)為(wèi)參數(shù),執行(xín>×g)測試邏輯,然後再分(fēn)别編寫三個(gè)測試ε&用(yòng)例方法去(qù)調用(yòn α♠™g)這(zhè)個(gè)非測試用(yòng)例方法。
更好(hǎo)的(de)辦法就(jiù)÷±是(shì)使用(yòng)testscenarios模塊,定義好(hǎoα")scenarios變量,然後實現(xiàn)一(yī)個(gè)測∏σ試用(yòng)例方法。
testscenarios模塊在OpenStack Ceε♣ilometer中被大(dà)量使用(yòng)。更多(duō)的(d♦<βe)信息可(kě)以查看(kàn)文(wén)檔。
subunit
subunit是(shì)一(yī)個(gè)用(yòng)于&☆"傳輸單元測試結果的(de)流協議(yì)。一(yī♥×$")般來(lái)說(shuō),運行(xíng®•≤©)單元測試的(de)時(shí)候是(shì)把單元ε€測試的(de)結果直接輸出到(dào)标準輸出,但(dàn)是(s★ hì)如(rú)果運行(xíng)大(dà)量的(de)測試用(yòng)™∏₩例,這(zhè)些(xiē)測試結果就(jiù)很(hěnδ )難被分(fēn)析。因此就(jiù)可(kě&×>γ)以使用(yòng)python-subunit模塊來(lái)運行(xí ®←ng)測試用(yòng)例,并且把測試用(y¶≠♠₹òng)例通(tōng)過subunit協議(yì)輸出,這(¥♥≤zhè)樣測試結果就(jiù)可(kě)<₩ φ以被分(fēn)析工(gōng)具聚合以及分(fēn)析。python-s←&'✘ubunit模塊自(zì)帶了(le)一'★'>(yī)些(xiē)工(gōng)具用(yòng)來(láπi)解析subunit協議(yì),比如(rú)你(nǐ)可(k ×ě)以這(zhè)樣運行(xíng)測試用(yòng)例:$ p&✘←ython -m subunit.run test_mo↓λdule | subunit2pyunit,s↓≈<ubunit2pyunit命令會(huì)解析subunit協議(yì≤←),并且輸出到(dào)标準輸出。關于s§δΩ≠ubunit的(de)更多(duō)信息,請(qǐng)查✔☆ 看(kàn)官方文(wén)檔。
testrepository
OpenStack中使用(yòng)testrepository模塊管理λ (lǐ)單元測試用(yòng)例。當一(yī)α₩↓↓個(gè)項目中的(de)測試用(yòng)例很(hě★≠±≥n)多(duō)時(shí),如(rú)何更有(yǒu)效&的(de)處理(lǐ)單元測試用(yòn₽g)例的(de)結果就(jiù)變得(de)很(hěn)重要(yào)。t≥₩©∞estrepository的(de)出現(xiàn)∑♥≠就(jiù)是(shì)為(wèi)了(le)解決這(zhσ∏£πè)個(gè)問(wèn)題。testrepo§εσsitory使用(yòng)python-subunit模塊來(lái)運行"♥₽↓(xíng)測試用(yòng)例,然後分(fēn•Ωε≈)析subunit的(de)輸出并對(duì)測試結₹$$果進行(xíng)記錄(記錄到(dào)本地♣£♠(dì)文(wén)件(jiàn))。舉例來(lái)說(shuō),testφ↑↕↓repository允許你(nǐ)做(zuò)這(zhè)↕≤"樣的(de)事(shì)情:
知(zhī)道(dào)哪些(xiē)用(yòng)例運™§↓行(xíng)時(shí)間(jiān)較長(cλ→↕háng)
顯示運行(xíng)失敗的(de)用(yòng)例
重新運行(xíng)上(shàng)次運行≠✘π(xíng)失敗的(de)用(yòng)例
testrepository的(de)更多(duō)信♦©息,請(qǐng)查看(kàn)官方文(wé♥∑±¥n)檔。
coverage
coverage是(shì)用(yòng)來(lái)計(jì)算(suà≥φn)代碼運行(xíng)時(shí)的(de)覆蓋率的(de),也(yě)就(♣↕jiù)是(shì)統計(jì)多(duō)少(shǎo)代碼被執行§£→(xíng)了(le)。它可(kě)以和(h↔♦♠é)testrepository一(yī)起使用(yònα←φg),用(yòng)來(lái)統計(jì)單元測試的(de♦£)覆蓋率,在運行(xíng)完單元測試之後,輸出覆蓋率報(bào) ××告。具體(tǐ)的(de)使用(yòng)方法↓可(kě)以查看(kàn)官方文(wén)檔α$®。
tox
tox是(shì)用(yòng)來(lái)管理(lǐ)和(hé)構建π≈↓虛拟環境(virtualenv)的(de)。對(duì)于±₩ε<一(yī)個(gè)項目,我們需要(yào)運行(↕$γxíng)Python 2.7的(de)單元測&®≠試,也(yě)需要(yào)運行(xíng)Python 3.4的'₹Ωφ(de)單元測試,還(hái)需要(yào)運行(xíng) ©¥PEP8的(de)代碼檢查。這(zhè)些(xiē)不(bù)同♥★±≠的(de)任務需要(yào)依賴不(bù)同的(de)庫,所以需要(γπyào)使用(yòng)不(bù)同的(¶♣→♣de)虛拟環境。使用(yòng)tox的(de)時(shí)候,我們會(≤γ®♥huì)在tox的(de)配置文(wén)件(jiαβàn)tox.ini中指定不(bù)同任務的↓¥♠¶(de)虛拟環境名稱,該任務在虛拟環境中需要(yào)安裝哪些(x↓σβ₩iē)包,以及該任務執行(xíng)的(de)時(✔σ£↔shí)候需要(yào)運行(xíng)哪些(xiē)命令。更多(☆±duō)信息,請(qǐng)查看(kàn)官方文βαγ£(wén)檔。
單元測試工(gōng)具小(xiǎo)結
本章(zhāng)介紹了(le)OpenStack中常用( α£★yòng)的(de)單元測試工(gōng)具的(de)基本用Ω✔&(yòng)途,希望大(dà)家(jiā)對(duì)這(π zhè)些(xiē)工(gōng)具有(yǒu)個(gèπΩ)大(dà)概的(de)認識。這(zhè)裡(lǐ)我們可(kě≤÷π)以按照(zhào)類别總結一(yī)下(xià)這(zhè)些(λ↑ xiē)工(gōng)具:
測試環境管理(lǐ): tox
使用(yòng)tox來(lái)管理(lǐ)測試運☆行(xíng)的(de)虛拟環境,并且調用(y€♣òng)testrepository來(lái)執行(xíng)測試用(yònλ ×™g)例。
測試用(yòng)例的(de)運行(xíng)和(hé)管理 ☆(lǐ): testrepository, subunit,>♣γ coverage
testrepository調用(yòng)subunit來(γδ→lái)執行(xíng)測試用(yòng)例,對(duì>≥$)測試結果進行(xíng)聚合和(hé)管理(l÷✘♦↑ǐ);調用(yòng)coverage來(lái)執行(xíng)代碼 £∑™覆蓋率的(de)計(jì)算(suàn)。
測試用(yòng)例的(de)編寫: unitt≈λest, mock, testtools, fixture$↓×↔s, testscenarios
使用(yòng)testtools作(zuò)為(wèi)所 ¥有(yǒu)測試用(yòng)例的(de)基類,同時(shíφ★$)應用(yòng)mock, fixtur÷→es, testscenarios來(lái)更好(hǎo)的(de)編寫測試¶≥≠用(yòng)例。
在The Hacker's Gu∏±ide to Python(《Python高(gāo)手之路(★∏$ lù)》)一(yī)書(shū)中,也(yě)有(yǒu)專門(m π±én)的(de)一(yī)章(zhāng)介紹了(le)₩γ♥各種單元測試工(gōng)具及其用(yòng)法,讀(dú)者也(yφě)可(kě)以參考一(yī)下(xià)。下(xià)一(yī)章•÷(zhāng),我們來(lái)分(fēn)析Keystone®♥項目的(de)單元測試框架,可(kě)以讓你₽♣λ(nǐ)看(kàn)到(dào)在OpenStack的(de)實←π≥際項目中,這(zhè)些(xiē)工(gōng)具是(shì)如(©↓rú)何被使用(yòng)的(de)。