一、為什么使用nose?
- 編寫測試更容易。nose可以自動識別繼承於unittest.TestCase的測試單元,並執行測試,而且,nose也可以測試非繼承於unittest.TestCase的測試單元。nose提供了豐富的API便於編寫測試代碼。
- 執行測試更容易。 只要遵循一些簡單的規則去組織你的類庫和測試代碼,nose是可以自動識別單元測試的。執行測試是非常耗資源的,但是,一段第一個測試模塊被加載后,nose就開始執行測試。
- 建立測試環境更容易。
- 做你想做的事情更容易。 nose擁有很多內置的插件幫助進行暑輸出抓取、錯誤查找、代碼覆蓋、文檔測試(doctest)等等。同樣,如果你不喜歡這些內置插件提供的功能或者這些插件不能滿足你的項目結構,你可以自定義開發插件來完成你想要做的事情。
二、基本使用
安裝:pip install nose
腳本命令:
nosetests [options] [(optional) test files or directories]
除了使用命令行這種方式之外,還可以在根目錄下放置配置文件,配置文件的類型為.noserc或nose.cfg文件。配置文件都是標准的ini內容格式。例如:
[nosetests] verbosity=3 with-doctest=1
三、擴展使用
nose自動收集單元測試,收集它當前工作目錄下的源代碼文件、目錄以及包。任何的源代碼文件、目錄或者包只要匹配正則表達式,他們就會被自動收集。包的測試收集按照樹的層級級別一級一級進行,因此package.tests、package.sub.tests、package.sub.sub2.tests將會被收集。
匹配成功的包、任何python的源文件都會當做測試用例。
3.1 選擇測試用例
將需要測試的名稱傳遞給nose的命令行。格式如下:
nosetests only_test_this.py
測試的名稱可以是腳本文件的名稱或者模塊的名稱,也可以使用colon表達式表達的測試名稱。路徑可以是相對的路徑也可以是絕對的路徑。如下所示:
nosetests test.module
nosetests another.test:TestCase.test_method
nosetests a.test:TestCase
nosetests /path/to/test/file.py:test_function
同樣可以使用-w開關來切換當前的工作路徑,從而改變nose查找測試用例的根路徑。用法如下:
nosetests -w /path/to/tests
更多關於自定義測試用例的收集與加載方式,可以使用插件的方式做到。
3.2 配置
除了3.1通過腳本命令傳遞參數的方式外,你還可以在根目錄下通過設置setup.cfg或者.noserc或者nose.cfg等配置文件達到同樣的目的。例如:
[nosetests] verbosity=3 with-doctest=1
所有查找到的配置文件將會被加載,而且配置項的值會合並。如果想覆蓋標准的配置文件,使用-c選項。
3.3 使用插件
使用pip安裝所需要的插件,然后通過nosetests命令行配置插件。執行如下命令驗證所安裝的插件,
nosetests –plugins
在命令行中添加
-v或者-vv選項可以顯示每一個插件的更多信息。 如果通過nose.main()或者nose.run()執行測試,可以將要使用的插件關鍵字參數的列表傳遞進去。
3.4 配置選項
-V,—version
輸出nose的版本
-p,—plugins
輸出可獲取的插件列表。
-v=DEFUALT,—verbose=DEFAULT
使用更多的verbose
--verbosity=VERBOSITY
設置verbosity;--verbosity=2與-v設置一致
-q,—quiet=DEFAULT
使用更少的verbose
-c=FILES,—config=FILES
設置配置文件。可以設置很多次,然后將所有的配置文件合並。
-w=WHERE,--where=WHERE
設置查找的根目錄。
-py3where=WHERE
顧名思義,針對python3.x以上設置查找路徑。
-m=REGEX,--match=REGEX,—testmatch=REGEX
設置用於自動化收集用例的正則表達式。
--tests=NAMES
執行這些測試。
--debug-log=FILE
設置調試的日志文件路徑。
--logging-config=FILE,—log-config=FILE
設置日志文件的配置文件。
-I=REGEX,—ignore-files=REGEX
設置自動收集測試用例時忽略的正則表達式。
-e=REGEX,—exclude=REGEX
排除要執行的測試用例的正則表達式
-i=REGEX,—include=REGEX
包含要執行的測試用例的正則表達式
-x,—stop
執行測試發生錯誤后,停止執行測試。
--noexe
不查找可以執行文件。
-a=ATTR,--attr=ATTR
只執行包含ATTR屬性的測試用例。
-A=EXPR,—eval-attr=EXPR
只執行屬性與EXPR匹配的測試用例。
-s,—nocapture
不抓取標准輸出(stdout)
--nologcapture
禁止使用日志插件
--logging-format=FORMAT
打印語句的自定義格式
--logging-datefmt=FORMAT
日志的日期時間格式
--logging-filter=FILTER
日志語句的過濾器。
--logging-clear-handlers
清除日志的其他handlers
--logging-level=DEFUALT
設置日志的等級
--with-coverage
開啟coverage插件
--cover-package=PACKAGE
限定coverage所在包
--cover-erase
在執行之前 清除上次coverage統計結果
--cover-testes
在coverage報告中包含測試模塊
--cover-html
產生html的coverage報告
--cover-html-dir=DIR
設置存儲html的目錄
--cover-xml
產生xml的coverage報告
--cover-xml-file=FILE
設置存儲coverage報告的xml文件
--cover-config-file=DEFUALT
設置coverage的配置文件
-pdb
當測試失敗或產生錯誤是進入調試模式
--pdb-failures
當測試失敗時進入調試模式
--pdb-errors
當測試產生錯誤時進入調試模式
--with-doctest
開啟doctest插件
--doctest-tests
在測試模塊中查詢doctests
--with-profile
開啟profile插件
--profile-sort=SORT
設置profiler 輸出排序
--profile-stats-file=FILE
設置統計所在的文件地址
--with-id
開啟TestId插件
--processes=NUM
開始測試處理器的個數
--processes-timeout=SECONDS
設置超時時間。
--with-xuint
開始Xunit插件
--xuint-file=FILE
設置XUnit報告所在的xml文件
--all-modules
開啟AllModules插件
--collect-only
開啟只收集測試功能。只收集測試用例及輸出測試名字,而不執行測試
四、編寫測試用例
4.1 項目組織結構
由於nose是自動收集測試用例的,只有nose執行的測試目錄下的源代碼文件、包名、子目錄名跟正則表達式匹配成功后,才能被收集。而且代碼是樹級層次顯示的話,nose會逐級向下查找子目錄下的匹配的測試用例。
匹配的正則表達式默認值為:((?:^|[\\b_\\.-])[Tt]est.所以最好是以Test開頭,或者test開頭。當然也可以修改默認的匹配的正則表達式。
所以,推薦的項目結構為:
為項目單獨建一個test包,里面按項目模塊分子包,最后以及為 “test_”開頭的測試用例源文件。
4.2 測試結果
4.3測試代碼
test_mymath.py中的代碼如下:
# -*- coding: utf-8 -*- __author__ = 'Administrator' from nose.tools import assert_equal from nose.tools import with_setup import unittest import mymath.math as mmath def setUp(): print("============test math module setup==============") def teardown(): print("============test math module teardown==============") def test_math_add(): result=mmath.add(4, 5) print("================test_math_add============") assert_equal(10, result) class test_math3(): def setUp(self): print("============test math class setup==============") def teardown(self): print("============test math class teardown==============") def test_math_square(self): print("=============== test_math_square================ ") assert_equal(9, mmath.square(3)) def test_math_sub(self): print("=============== test_math_sub================ ") assert_equal(1, mmath.sub(3, 2)) class test_math2(unittest.TestCase): def test_math_multipy(self): print("=============== test_math_multipy================ ") assert_equal(8, mmath.multiply(2, 4))
test_logicOper.py 中的代碼如下:
# -*- coding: utf-8 -*- __author__ = 'Administrator' from nose.tools import assert_equal from logicOperator.localOperator import * def test_logicOper_isGreaterThan(): print("=================test_logicOper_isGreaterThan============") result=isGreaterThan(4,3) assert_equal(True,result)
4.4 測試分析
(1)測試用例的收集
由於nose是按照正則表達式自動收集匹配的測試用例。我們這里收集了5個測試用例。分別了
- test_mymath.py模塊里的test_math_add函數。
- test_mymath.py模塊里的test_math3類下面的test_math_square、test_math_sub兩個函數。
- test_mymath.py模塊里的test_math2類下面的test_math_multipy函數。
- test_logicOper.py模塊里的test_logicOper_isGreaterThan函數。
(2)測試的運行順序。
從下圖打印輸出的結果可以看出。收集的測試用例的執行順序test_logicOper_isGreaterThan—>test_mymath(模塊).setup—>test_math2(類).test_math_multipy—>test_math3(類).setup—>test_math3(類).test_math_square—>
test_math3(類).teardown—>test_math3(類).setup—>test_math3(類).test_math_sub—>test_math3(類).teardown—>test_mymath(模塊).test_math_add—>test_mymath(模塊).teardown.
大體可以得出如下結論:
1)測試的順序總體上按照包—>模塊—>類的順序進行;
2) 然后按照測試用例名稱的升序排序進行,比如test_math_multipy比test_math_square先執行;
3)當測試模塊中既包含測試函數,又包含測試類時,都一定是先執行setup(如果定義了),模塊測試執行完畢后執行teardown(如果定義了)。而且模塊的setup、setdown只執行一次。
4)測試類中的每個測試方法執行前先執行setup(如果定義了),執行完畢后執行teardown(如果定義了)。而且每個測試方法的執行過程都是如此,新的方法重新按setup—>執行方法—>teardown的順序執行。
(3)關於setup 、teardown
package、module、class都可以設置setup、teardown。
1)package的setup 、teardown的設置
放在__init__.py文件中,在整個測試的運行期間只運行一次。
setup函數的取名可以是 setup, setup_package, setUp, setUpPackage中的一個。
teardown 函數取名可以是teardown, teardown_package, tearDown or tearDownPackage中的一個。
2) module的setup 、teardown的設置
在整個測試的運行期間只運行一次。
setup函數的取名可以是 setup, setup_module, setUp or setUpModule中的一個。
teardown 函數取名可以是teardown_module, or tearDownModule中的一個。
3)class的setup 、teardown的設置
每個測試方法執行時都會調用。
setup函數的取名可以是setup_class, setupClass, setUpClass, setupAll ,setUpAll中的一個。
teardown 函數取名可以是teardown_class, teardownClass, tearDownClass, teardownAll ,tearDownAll中的一個。
測試類可以繼承unittest.TestCase ,也可以不繼承,nose都能識別。
4)測試方法的setup、teardown
可以通過with_setup裝飾器進行設置,比如
總之,nose的口號是:nose extends unittest to make testing easier(測試更簡單).