nose 是一個第三方單元測試框架,它完全相容 unittest
,並且號稱是一個更好用的測試框架。
那麼 nose
除了具備 unittest
的所有功能外,還具有哪些優勢呢?
用例的編寫方式除了編寫繼承於 unittest.TestCase 的測試類外,還可以編寫成沒有繼承的測試類。比如,寫成如下形式也會被 nose
視作一個測試類:
from nose.tools import raises
class TestStringMethods:
def test_upper(self):
assert 'foo'.upper() == 'FOO'
def test_isupper(self):
assert 'FOO'.isupper()
assert not 'Foo'.isupper()
@raises(TypeError)
def test_split(self):
s = 'hello world'
assert s.split() == ['hello', 'world']
# check that s.split fails when the separator is not a string
s.split(2)
複製程式碼
當然,測試類並沒有繼承 unittest.TestCase
,將不能使用其內建的各類 assertXXX
方法,進而導致用例出錯時無法獲得更加詳細的上下文資訊。
此外,nose
也支援定義函數來作爲測試,這給許多簡單的測試場景帶來很大的便利:
def test_upper():
assert 'foo'.upper() == 'FOO'
複製程式碼
unittest
所支援的用例發現和執行能力,nose
均支援。 nose
支援用例自動(遞回)發現:
test
的測試用例,但不包括以 _
開頭的用例
nosetests
命令-w
參數指定要自動發現的目錄, -m
參數指定用例檔案、目錄、函數、類的名稱模式(正則匹配)
nosetests -w project_directory "test_.+"
nose
也支援執行指定用例:
nosetests test.module
nosetests a.test:TestCase
nosetests another.test:TestCase.test_method
nosetests /path/to/test/file.py
unittest
所不支援的)
nosetests /path/to/test/file.py:TestCase
nosetests /path/to/test/file.py:TestCase.test_method
nosetests /path/to/test/file.py:test_function
nose
除了支援 unittest
所支援的定義測試前置和清理方式,還支援一種更爲簡單的定義方式:
def setup_func():
"set up test fixtures"
def teardown_func():
"tear down test fixtures"
@with_setup(setup_func, teardown_func)
def test():
"test ..."
複製程式碼
只需定義兩個函數用來表示前置和清理方法,通過 nose.tools.with_setup 裝飾器裝飾測試函數,nose
便會在執行測試用例前後分別執行所定義的前置和清理函數。
nose
除了支援 unittest
中的 TestCase.subTest
,還支援一種更爲強大的子測試編寫方式,也就是 測試生成器(Test generators)
,通過 yield
實現。
在下面 下麪的範例中,定義一個 test_evens
測試函數,裏面生成了 5 個子測試 check_even
:
def test_evens():
for i in range(0, 5):
yield check_even, i, i*3
def check_even(n, nn):
assert n % 2 == 0 or nn % 2 == 0
複製程式碼
此外,相較於 unittest.TestCase.subTest
多個子測試只能執行一次測試前置和清理,nose
的 測試生成器
可以支援每個子測試執行一次測試前置和清理,如:
def test_generator():
# ...
yield func, arg, arg # ...
@with_setup(setup_func, teardown_func)
def func(arg):
assert something_about(arg)
複製程式碼
nose
相較於 unittest
一個最大的優勢就是外掛體系,自帶了很多有用的外掛,也有豐富的第三方外掛。這樣就能做更多的事情。
其中,自帶外掛如下:
而第三方庫則多種多樣,如用來生成 HTML 格式測試報告的 nose-htmloutput 等,這裏不再一一列出。
得益於 nose
豐富的外掛生態,當 nose
本身不能夠完全滿足我們的測試需求時,可以通過安裝外掛,並在 nosetests
命令列指定該外掛所提供的特定參數即可非常容易的使用外掛。 相較於 unittest
,就能省去很多自己開發額外測試邏輯的精力。
nose2 是 nose 的繼任者。 它們的理念都是讓編寫和執行測試用例變得更容易。
它們有很多相同點,比如都相容 unittest
,支援使用函數作爲測試用例,支援子測試,擁有外掛體系。但也有很多不同點,下面 下麪列出一些主要的不同點:
nose
自行實現了模組載入功能,使用惰性方式載入測試模組,載入一個執行一個。nose2
則藉助內建的 import() 匯入模組,並且是先全部載入,再執行用例nose2
並不支援 nose
所支援的所有測試用例專案結構,比如如下用例檔案的結構在 nose2
中就不受支援:
.
`-- tests
|-- more_tests
| `-- test.py
`-- test.py
複製程式碼
nose
支援方法、類、模組和包級別的測試前置和清理函數nose2
則不支援包級別的測試前置和清理函數nose2
除了支援使用測試生成器來實現子測試外,還支援使用參數化測試(Parameterized tests)來實現子測試nose2
除了像 nose
一樣支援在測試函數和測試類(不繼承於 unittest.TestCase
)中支援參數化測試和測試生成器外,還支援在繼承於 unittest.TestCase
的測試類中使用nose
期望所有外掛的設定通過命令列參數進行設定nose2
則通過組態檔進行控制,以最小化命令列參數讓人讀得更舒服更多對比詳見 官方文件。
nose
和 nose2
在做到相容 unittest
上就足以看出它們的目標,那便是要吸引原來那些使用 unittest
的使用者來使用它們。它們確實做到了!
nose
和 nose2
在用例編寫、測試夾具、子測試上做出改進,已經能讓日常用例編寫工作變得更加容易和靈活。同時又引入外掛體系,進一步將單元測試框架的能力提升了一個大大的臺階,這讓很多在基礎測試功能之上的高階功能的實現和共用成爲了可能。也難怪有衆多開發者對它們情有獨鍾。