摘要:本文將進入單元測試的部分,這也是基礎知識中最后一個大塊。本文將重點講述和中的單元測試的生態環境。另外,在中指定要運行的單元測試用例的完整語法是。中使用模塊管理單元測試用例。每個項目的單元測試代碼結構可
本文將進入單元測試的部分,這也是基礎知識中最后一個大塊。本文將重點講述Python和OpenStack中的單元測試的生態環境。
單元測試的重要性github上有個人畫了一些不同語言的學習曲線圖:Learning Curves (for different programming languages),雖然有些惡搞的傾向,不過確實說明了問題。這里貼一下Python的部分:
這個圖說明了,會單元測試對于提高Python生產力的重要性,這主要是因為Python是個動態語言,很多問題都無法通過靜態編譯檢查來發現,因此單元測試就成了一個重要的確保質量的手段。OpenStack的核心項目都對單元測試有極高的要求,以保證項目的高質量。
單元測試工具Python的單元測試工具很多,為單元測試提供不同方面的功能。OpenStack的項目也基本把現在流行的單元測試工具都用全了。單元測試可以說是入門OpenStack開發的最難的部分,也是最后一公里。本章,我們就介紹一下在OpenStack中會用到的單元測試的工具。由于數量很多,不可能詳細介紹,因此主要做一些概念和用途上的介紹。
unittestunittest是Python的標準庫,提供了最基本的單元測試功能,包括單元測試運行器(簡稱runner)和單元測試框架。項目的單元測試代碼的測試類可以繼承unittest.TestCase類,這樣這個類就能夠被runner發現并且執行。同時,unittest.TestCase這個類還定義了setUp(),tearDown(),setUpClass()和tearDownClass()方法,是用來運行單元測試前的設置工作代碼和單元測試后的清理工作代碼,這個也是所有Python代碼遵守的規范,所以第三方的單元測試庫和框架也都遵循這個規范。
unittest庫也提供了一個runner,可以使用$ python -m unittest test_module的命令來執行某個模塊的單元測試。另外,在Python中指定要運行的單元測試用例的完整語法是:path.to.your.module:ClassOfYourTest.test_method。
unittest是學習Python單元測試最基本也最重要的一個庫,完整的說明請查看官方文檔:https://docs.python.org/2.7/library/unittest.html。
mockmock也是另一個重要的單元測試庫,在Python 2中是作為一個第三方庫被使用的,到Python 3時,就被納入了標準庫,可見這個庫的重要性。簡單的說,mock就是用來模擬對象的行為,這樣在進行單元測試的時候,可以指定任何對象的返回值,便于測試對外部接口有依賴的代碼。關于mock的使用,可以查看我之前寫的這篇文章Python Mock的入門
testtoolstesttools是個unittest的擴展框架,主要是在unittest的基礎上提供了更好的assert功能,使得寫單元測試更加方便。具體可以查看文檔:http://testtools.readthedocs.org/en/latest/。
fixturesfixture的意思是固定裝置,在Python的單元測試中,是指某段可以復用的單元測試setUp和tearDown代碼組合。一個fixture一般用來實現某個組件的setUp和tearDown邏輯,比如測試前要先創建好某些數據,測試后要刪掉這些數據,這些操作就可以封裝到一個fixture中。這樣不同的測試用例就不用重復寫這些代碼,只要使用fixture即可。fixtures模塊是一個第三方模塊,提供了一種簡單的創建fixture類和對象的機制,并且也提供了一些內置的fixture。具體的使用方法可以查看官方文檔:https://pypi.python.org/pypi/fixtures/。
testscenariostestscenarios模塊滿足了場景測試的需求。它的基本用法是在測試類中添加一個類屬性scenarios,該屬性是一個元組,定義了每一種場景下不同的變量的值。比如說你測試一段數據訪問代碼,你需要測試該代碼在使用不同的驅動時,比如MongoDB、SQL、File,是否都能正常工作。我們有三種辦法:
最笨的辦法是為不同的驅動把同一個測試用例編寫3遍。
比較好的辦法是,編寫一個統一的非測試用例方法,接收driver作為參數,執行測試邏輯,然后再分別編寫三個測試用例方法去調用這個非測試用例方法。
更好的辦法就是使用testscenarios模塊,定義好scenarios變量,然后實現一個測試用例方法。
testscenarios模塊在OpenStack Ceilometer中被大量使用。更多的信息可以查看文檔:https://pypi.python.org/pypi/testscenarios/
subunitsubunit是一個用于傳輸單元測試結果的流協議。一般來說,運行單元測試的時候是把單元測試的結果直接輸出到標準輸出,但是如果運行大量的測試用例,這些測試結果就很難被分析。因此就可以使用python-subunit模塊來運行測試用例,并且把測試用例通過subunit協議輸出,這樣測試結果就可以被分析工具聚合以及分析。python-subunit模塊自帶了一些工具用來解析subunit協議,比如你可以這樣運行測試用例:$ python -m subunit.run test_module | subunit2pyunit,subunit2pyunit命令會解析subunit協議,并且輸出到標準輸出。關于subunit的更多信息,請查看官方文檔:https://pypi.python.org/pypi/python-subunit/。
testrepositoryOpenStack中使用testrepository模塊管理單元測試用例。當一個項目中的測試用例很多時,如何更有效的處理單元測試用例的結果就變得很重要。testrepository的出現就是為了解決這個問題。testrepository使用python-subunit模塊來運行測試用例,然后分析subunit的輸出并對測試結果進行記錄(記錄到本地文件)。舉例來說,testrepository允許你做這樣的事情:
知道哪些用例運行時間最長
顯示運行失敗的用例
重新運行上次運行失敗的用例
testrepository的更多信息,請查看官方文檔:http://testrepository.readthedocs.org/en/latest/。
coveragecoverage是用來計算代碼運行時的覆蓋率的,也就是統計多少代碼被執行了。它可以和testrepository一起使用,用來統計單元測試的覆蓋率,在運行完單元測試之后,輸出覆蓋率報告。具體的使用方法可以查看官方文檔:http://coverage.readthedocs.org/en/latest/。
toxtox是用來管理和構建虛擬環境(virtualenv)的。對于一個項目,我們需要運行Python 2.7的單元測試,也需要運行Python 3.4的單元測試,還需要運行PEP8的代碼檢查。這些不同的任務需要依賴不同的庫,所以需要使用不同的虛擬環境。使用tox的時候,我們會在tox的配置文件tox.ini中指定不同任務的虛擬環境名稱,該任務在虛擬環境中需要安裝哪些包,以及該任務執行的時候需要運行哪些命令。更多信息,請查看官方文檔:https://testrun.org/tox/latest/
單元測試工具小結本章介紹了OpenStack中常用的單元測試工具的基本用途,希望大家對這些工具有個大概的認識。這里我們可以按照類別總結一下這些工具:
測試環境管理: tox
使用tox來管理測試運行的虛擬環境,并且調用testrepository來執行測試用例。
測試用例的運行和管理: testrepository, subunit, coverage
testrepository調用subunit來執行測試用例,對測試結果進行聚合和管理;調用coverage來執行代碼覆蓋率的計算。
測試用例的編寫: unittest, mock, testtools, fixtures, testscenarios
使用testtools作為所有測試用例的基類,同時應用mock, fixtures, testscenarios來更好的編寫測試用例。
在The Hacker"s Guide to Python(《Python高手之路》)一書中,也有專門的一章介紹了各種單元測試工具及其用法,讀者也可以參考一下。下一章,我們來分析Keystone項目的單元測試框架,可以讓你看到在OpenStack的實際項目中,這些工具是如何被使用的。
Keystone的單元測試框架現在,我們以Keystone項目為例,來看下真實項目中的單元測試是如何架構的。我們采用自頂向下的方式,先從最上層的部分介紹起。
使用tox進行測試環境管理大部分情況下,我們都是通過tox命令來執行單元測試的,并且傳遞環境名稱給tox命令:
? ~/openstack/env/p/keystone git:(master) ? $ tox -e py27
tox命令首先會讀取項目根目錄下的tox.ini文件,獲取相關的信息,然后根據配置構建virtualenv,保存在.tox/目錄下,以環境名稱命名:
? ~/openstack/env/p/keystone git:(master) ? $ ls .tox log pep8 py27
除了log目錄,其他的都是普通的virtualenv環境,你可以自己查看一下內容。我們來看下py27這個環境的相關配置(在tox.ini)中,我直接在內容上注釋一些配置的用途:
[tox] minversion = 1.6 skipsdist = True # envlist表示本文件中配置的環境都有哪些 envlist = py34,py27,pep8,docs,genconfig,releasenotes # testenv是默認配置,如果某個配置在環境專屬的section中沒有,就從這個section中讀取 [testenv] # usedevelop表示安裝virtualenv的時候,本項目自己的代碼采用開發模式安裝,也就是不會拷貝代碼到virtualenv目錄中,只是做個鏈接 usedevelop = True # install_command表示構建環境的時候要執行的命令,一般是使用pip安裝 install_command = pip install -U {opts} {packages} setenv = VIRTUAL_ENV={envdir} # deps指定構建環境的時候需要安裝的依賴包,這個就是作為pip命令的參數 # keystone這里使用的寫法比較特殊一點,第二行的.[ldap,memcache,mongodb]是兩個依賴,第一個點"."表示當前項目的依賴,也就是requirements.txt,第二個部分[ldap,memcache,mongodb]表示extra,是在setup.cfg文件中定義的一個段的名稱,該段下定義了額外的依賴,這些可以查看PEP0508 # 一般的項目這里會采用更簡單的方式來書寫,直接安裝兩個文件中的依賴: # -r{toxinidir}/requirements.txt # -r{toxinidir}/test-requirements.txt deps = -r{toxinidir}/test-requirements.txt .[ldap,memcache,mongodb] # commands表示構建好virtualenv之后要執行的命令,這里調用了tools/pretty_tox.sh來執行測試 commands = find keystone -type f -name "*.pyc" -delete bash tools/pretty_tox.sh "{posargs}" whitelist_externals = bash find passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY PBR_VERSION # 這個section是為py34環境定制某些配置的,沒有定制的配置,從[testenv]讀取 [testenv:py34] commands = find keystone -type f -name "*.pyc" -delete bash tools/pretty_tox_py3.sh
上面提到的PEP-0508是依賴格式的完整說明。setup.cfg的extra部分如下:
[extras] ldap = python-ldap>=2.4:python_version=="2.7" # PSF ldappool>=1.0:python_version=="2.7" # MPL memcache = python-memcached>=1.56 # PSF mongodb = pymongo!=3.1,>=3.0.2 # Apache-2.0 bandit = bandit>=0.17.3 # Apache-2.0使用testrepository管理測試的運行
上面我們看到tox.ini文件中的commands參數中執行的是tools/pretty_tox.sh命令。這個腳本的內容如下:
#!/usr/bin/env bash set -o pipefail TESTRARGS=$1 # testr和setuptools已經集成,所以可以通過setup.py testr命令來執行 # --testr-args表示傳遞給testr命令的參數,告訴testr要傳遞給subunit的參數 # subunit-trace是os-testr包中的命令(os-testr是OpenStack的一個項目),用來解析subunit的輸出的。 python setup.py testr --testr-args="--subunit $TESTRARGS" | subunit-trace -f retval=$? # NOTE(mtreinish) The pipe above would eat the slowest display from pbr"s testr # wrapper so just manually print the slowest tests. echo -e " Slowest Tests: " # 測試結束后,讓testr顯示出執行時間最長的那些測試用例 testr slowest exit $retval
tox就是從tools/pretty_tox.sh這個命令開始調用testr來執行單元測試的。testr本身的配置是放在項目根目錄下的.testr.conf文件:
[DEFAULT] test_command= ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystone/tests/unit} $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list group_regex=.*(test_cert_setup) # NOTE(morganfainberg): If single-worker mode is wanted (e.g. for live tests) # the environment variable ``TEST_RUN_CONCURRENCY`` should be set to ``1``. If # a non-default (1 worker per available core) concurrency is desired, set # environment variable ``TEST_RUN_CONCURRENCY`` to the desired number of # workers. test_run_concurrency=echo ${TEST_RUN_CONCURRENCY:-0}
這個文件中的配置項可以從testr官方文檔中找到。其中test_command命令表示要執行什么命令來運行測試用例,這里使用的是subunit.run,這個我們在上面提到過了。
到目前為止的流程就是:
tox建好virtualenv
tox調用testr
testr調用subunit來執行測試用例
每個OpenStack項目基本上也都是這樣。如果你自己在開發一個Python項目,你也可以參考這個架構。
單元測試用例的代碼架構下面我們來看一下Keystone的單元測試代碼是如何寫的,主要是看一下其層次結構。每個OpenStack項目的單元測試代碼結構可能都不一樣,不過你了解完Keystone的結構之后,看其他項目的就會比較快了。
我們以一個測試類為例來分析測試代碼的結構:keystone.tests.unit.test_v3_assignment:AssignmentTestCase。下面是這個類的繼承結構,同一級別的縮進表示多重繼承,增加縮進表示父類,這里刪掉了不必要的路徑前綴(從unit目錄開始),如下所示:
# 這個測試類是測RoleAssignment的API的 unit.test_v3_assignment.RoleAssignmentBaseTestCase -> unit.test_v3.AssignmentTestMixin 這個類包含了一下測試Assignment的工具函數 -> unit.test_v3.RestfulTestCase 這個類是進行V3 REST API測試的基類,實現了V3 API的請求發起和校驗 -> unit.core.SQLDriverOverride 用于修改各個配置的driver字段為sql -> unit.test_v3.AuthTestMixin 包含創建認證請求的輔助函數 -> unit.rest.RestfulTestCase 這個類是進行RESP API測試的基類,V2和V3的API測試都是以這個類為基類,這個類的setUp方法會初始化數據庫,創建好TestApp。 -> unit.TestCase 這個類是Keystone中所有單元測試類的基類,它主要初始化配置,以及初始化log -> unit.BaseTestCase 這個類主要是配置測試運行的基本環境,修改一些環境變量,比如HOME等。 -> oslotest.BaseTestCase 這個是在oslotest中定義的基類,原來所有的OpenStack項目的單元測試都繼承自這個基類。 不過,這個繼承在Keystone中已經被刪除了,Keystone自己在unit.BaseTestCase中做了差不多的事情。 這個是2016-02-17做的變更,具體的可以查看這個revision 262d0b66c3bcb82eadb663910ee21ded63e77a78。 -> testtools.TestCase 使用testtools作為測試框架 -> unittest.TestCase testtools本身是unittest的擴展
從上面的層次結構可以看出,OpenStack中的大項目,由于單元測試用例很多(Keystone現在有超過6200個單元測試用例),所以其單元測試架構也會比較復雜。要寫好單元測試,需要先了解一下整個測試代碼的架構。
總結本文我們了解了Python中的單元測試的概念和工具,并且通過Keystone項目了解了實際項目中的單元測試的架構,希望有助于各位讀者更好的掌握OpenStack項目的單元測試基礎。webdemo項目目前沒有單元測試的代碼,有興趣的讀者可以自己fork然后參考Keystone的架構為其增加完整的單元測試架構。
系列后記這個系列我打算就此結束,到目前為止一共寫了8篇文章,寫寫停停,前后寫了9個月。這里也做個小結。
一開始寫這個系列的文章是因為我自己在學習OpenStack開發的過程中遇到很多困難,很難找到所需的入門文章。所以打算寫點文章,既能作為自己的總結,也能為其他人提供些幫助。如果這些文章能幫到你,我就非常的開心。當然,這些文章的質量肯定有好有壞,歡迎大家提意見,如果有時間,我會繼續修改。
然后,我想說一下寫這類文章的難點,主要是要保證細節都是正確的,然后又不能太啰嗦。
細節都是正確的。舉個例子,大學的很多數據結構教材中的代碼,你直接貼到電腦上,然后編譯,大部分是編譯不通過的。這個會讓初學者非常沮喪。所以我希望能夠保證這些文章里的細節都是正確的,包括一些工具的配置,如果覺得有必要,我也會描述下配置的作用,以及要去哪里找更多的信息。如果這方面有遺漏,請和我說。
不能太啰嗦。這8篇文章里涉及的庫有好幾十個,每個庫如果都講仔細了,那就會讓文章顯得非常啰嗦。但是又不能直接讓讀者去看庫的官方文檔,所以權衡內容也是很麻煩的。如果各位有這方面的建議,也請和我說。
這個系列的文章是關于OpenStack的基礎知識,其實OpenStack開發還要涉及到很多其他的知識,比如消息隊列、非阻塞IO等,而且還要了解整個OpenStack的開發生態,包括Gerrit評審系統、Zuul持續集成、devstack開發環境、oslo項目等。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/37813.html
摘要:另外,項目在單元測試中使用的是的內存數據庫,這樣開發者運行單元測試的時候不需要安裝和配置復雜的數據庫,只要安裝好就可以了。而且,數據庫是保存在內存中的,會提高單元測試的速度。是實現層的基礎。項目一般會使用數據庫來運行單元測試。 OpenStack中的關系型數據庫應用 OpenStack中的數據庫應用主要是關系型數據庫,主要使用的是MySQL數據庫。當然也有一些NoSQL的應用,比如Ce...
摘要:在實際項目中,這么做肯定是不行的實際項目中不會使用內存數據庫,這種數據庫一般只是在單元測試中使用。接下來,我們將會了解中單元測試的相關知識。 在上一篇文章,我們介紹了SQLAlchemy的基本概念,也介紹了基本的使用流程。本文我們結合webdemo這個項目來介紹如何在項目中使用SQLAlchemy。另外,我們還會介紹數據庫版本管理的概念和實踐,這也是OpenStack每個項目都需要做的...
摘要:不幸的是,在軟件包管理十分混亂,至少歷史上十分混亂。的最大改進是將函數的參數單獨放到一個的文件中這些成為包的元數據。基于的版本號管理。的版本推導這里重點說明一下基于的版本號管理這個功能。開發版本號的形式如下。 為什么寫這個系列 OpenStack是目前我所知的最大最復雜的基于Python項目。整個OpenStack項目包含了數十個主要的子項目,每個子項目所用到的庫也不盡相同。因此,對于...
摘要:通過,也就是通過各個項目提供的來使用各個服務的功能。通過使用的方式是由各個服務自己實現的,比如負責計算的項目實現了計算相關的,負責認證的項目實現了認證和授權相關的。的服務都是使用的方式來部署的。 使用OpenStack服務的方式 OpenStack項目作為一個IaaS平臺,提供了三種使用方式: 通過Web界面,也就是通過Dashboard(面板)來使用平臺上的功能。 通過命令行,也就...
摘要:到這里,我們的服務的框架已經搭建完成,并且測試服務器也跑起來了。上面的代碼也就可以修改為再次運行我們的測試服務器,就可以返現返回值為格式了。我們先來完成利用來檢查返回值的代碼方法的第一個參數表示返回值的類型這樣就完成了的返回值檢查了。 上一篇文章說到,我們將以實例的形式來繼續講述這個API服務的開發知識,這里會使用Pecan和WSME兩個庫。 設計REST API 要開發REST AP...
閱讀 1574·2021-09-23 11:21
閱讀 2345·2021-09-07 10:13
閱讀 834·2021-09-02 10:19
閱讀 1125·2019-08-30 15:44
閱讀 1720·2019-08-30 13:18
閱讀 1913·2019-08-30 11:15
閱讀 1105·2019-08-29 17:17
閱讀 2017·2019-08-29 15:31