Python 各類測試框架簡介(二):unittest

unittest 與 doctest 同樣也是 Python 發行版自帶的包。若是你據說過 PyUnit(OSC 開源項目頁面中就有 PyUnit 的頁面),那麼這倆實際上是同一個東西——PyUnit 是 unittest 的曾用名,由於 PyUnit 最先也是來源於 Kent 和 Erich 的 JUnit(xUnit 測試框架系列的 Java 版本) <br /> ##unittest 概覽

上一篇介紹的 doctest 無論是看起來仍是用起來都顯得十分簡單,能夠與源碼寫在一塊兒,比較適合用做驗證性的功能測試。而本篇的 unittest 從名字上看,它是一個單元測試框架;從官方文檔的字數上看,它的能力應該比 doctest 強一些。html

使用 unittest 的標準流程爲:python

  1. 從 unittest.TestCase 派生一個子類
  2. 在類中定義各類以 「test_」 打頭的方法
  3. 經過 unittest.main() 函數來啓動測試

unittest 的一個頗有用的特性是 TestCase 的 setUp()tearDown() 方法,它們提供了爲測試進行準備和掃尾工做的功能,聽起來就像上下文管理器同樣。這種功能很適合用在測試對象須要複雜執行環境的狀況下。 <br /> ##舉個例子

這裏依舊使用上篇中那個極簡的例子:unnecessary_math.py 文件中有一個 multiply() 函數,功能與 * 操做符徹底同樣。框架

test_um_test.py:函數

lang:python
import unittest
from unnecessary_math import multiply

class TestUM(unittest.TestCase):
	def setUp(self):
		pass
	def test_number_3_4(self):
		self.assertEqual(multiply(3,4),12)
	def test_string_a_3(self):
		self.assertEqual(multiply('a',3),'aaa')

if __name__ == '__main__':
	unittest.main()

這個例子裏,咱們使用了 assertEqual() 方法。unittest 中還有不少相似的 assert 方法,好比 NotEqualIs(Not)NoneTrue(False)Is(Not)Instance 等針對變量值的校驗方法;另外還有一些如 assertRaises()assertRaisesRegex() 等針對異常、警告和 log 的檢查方法;以及如 assertAlmostEqual() 等一些奇怪的方法。單元測試

較詳細的 assert 方法能夠參考 unittest 的文檔頁面測試

##啓動測試

上例中的結尾處,咱們定義了一個對 unittest.main() 的調用,所以這個腳本是能夠直接運行的:命令行

$ python test_um_test.py
..
--------------------------------------
Ran 2 tests in 0.01s

OK

一樣 -v 參數是可選的,也能夠在 unittest.main() 函數裏直接指定:verbosity=1。 <br /> ##Test Discovery

這個分段標題我暫時沒想到好的翻譯方法,就先不翻了。翻譯

Test Discovery 的做用是:假設你的項目文件夾裏面四散分佈着不少個測試文件。當你作迴歸測試的時候,一個一個地執行這些測試文件就太麻煩了。TestLoader.discover() 提供了一個能夠在項目目錄下自動搜索並運行測試文件的功能,並能夠直接從命令行調用:code

$ cd project_directory
$ python -m unittest discover

discover 可用的參數有 4 個(-v -s -p -t),其中 -s-t 都與路徑有關,如上例中提早 cd 到項目路徑的話這倆參數均可以無視;-v 喜聞樂見;-p--pattern 的縮寫,可用於匹配某一類文件名。 <br /> ##測試環境

當類裏面定義了 setUp() 方法的時候,測試程序會在執行每條測試項前先調用此方法;一樣地,在所有測試項執行完畢後,tearDown() 方法也會被調用。驗證以下:htm

lang:python
import unittest

class simple_test(unittest.TestCase):
	def setUp(self):
    	self.foo = list(range(10))

	def test_1st(self):
    	self.assertEqual(self.foo.pop(),9)

	def test_2nd(self):
    	self.assertEqual(self.foo.pop(),9)

if __name__ == '__main__':
	unittest.main()

注意這裏兩次測試均對同一個實例屬性 self.foo 進行了 pop() 調用,但測試結果均爲 pass,即說明,test_1sttest_2nd 在調用前都分別調用了一次 setUp()

那若是咱們想全程只調用一次 setUp/tearDown 該怎麼辦呢?就是用 setUpClass()tearDownClass() 類方法啦。注意使用這兩個方法的時候必定要用 @classmethod 裝飾器裝飾起來:

lang:python
import unittest

class simple_test(unittest.TestCase):
	@classmethod
	def setUpClass(self):
    	self.foo = list(range(10))

	def test_1st(self):
    	self.assertEqual(self.foo.pop(),9)

	def test_2nd(self):
    	self.assertEqual(self.foo.pop(),8)

if __name__ == '__main__':
	unittest.main()

這個例子裏咱們使用了一個類級別的 setUpClass() 類方法,並修改了第二次 pop() 調用的預期返回值。運行結果顯示依然是所有經過,即說明此次在所有測試項被調用前只調用了一次 setUpClass()

再往上一級,咱們但願在整個文件級別上只調用一次 setUp/tearDown,這時候就要用 setUpModule()tearDownModule() 這兩個函數了,注意是函數,與 TestCase 類同級:

lang:python
import unittest

def setUpModule():
	pass

class simple_test(inittest.TestCase):
	...

通常 assert*() 方法若是拋出了未被捕獲的異常,那麼這條測試用例會被記爲 fail,測試繼續進行。但若是異常發生在 setUp() 裏,就會認爲測試程序自身存在錯誤,後面的測試用例和 tearDown() 都不會再執行。即,tearDown() 僅在 setUp() 成功執行的狀況下才會執行,並必定會被執行。

最後,這兩個方法的默認實現都是什麼都不作(只有一句 pass),因此覆蓋的時候直接寫新內容就能夠了,沒必要再調用父類的此方法。

相關文章
相關標籤/搜索