1. 原文及參考資料
原文鏈接:http://docs.python.org/2/library/unittest.html#
參考文檔:
http://pyunit.sourceforge.net/pyunit_cn.html
http://www.oschina.net/question/12_27127
2. PyUnit介紹
PyUnit是Python 2.1版本新增功能。
(如果你已經熟悉了測試的基本概念,你可以直接跳到the list of assert methods.)
Python單元測試框架,又叫PyUnit。是JUnit的Python實現,是由Kent Beck和Erich Gamma共同開發的。同樣,JUnit是Kent的Smalltalk測試框架的Java實現。PyUnit和JUnit都是各自怨言的標准測試框架。
PyUnit模塊支持自動化測試,通用的setup和shutdown的代碼,測試用例整合為測試集,還有獨立的測試報告框架。PyUnit提供的類能夠很容易的使以上特性應用於測試。PyUnit是借由以下概念支持單元測試的:
測試固件
測試固件是指運行測試前的准備工作和運行測試后的清理工作。例如,創建臨時或代理數據庫、目錄,或者啟動服務進程。
測試用例
測試用例是最小的測試單元,檢查特定的輸入會產生預期的結果。PyUnit提供一個測試用例幾類TestCase,繼承基類可以創建新的測試用例。
測試集
測試集是測試用例的集合,同時也可以是其他測試集的結合,或者是測試用例和測試集的混合集合。用於批量執行測試用例。
執行器
執行器用來執行測試用例,並且把測試結果呈現給用戶。執行器可以使用圖形界面,文本界面,甚至特殊值來顯示測試結果。
測試用例和測試固件通過TestCase和FunctionTestCase兩個類來實現的。TestCase用來創建新的測試用例,而FunctionTestCase是用來把已有測試用例整合為PyUnit結構用例的(譯者注:項目原來已經有測試用例了,后來想改用PyUnit測試框架,這時候就要用到FunctionTestCase了)。使用TestCase類創建新測試用例,需要覆蓋setUp()和tearDown()方法,他們分別用來初始化固件和清理固件。而要使用FunctionTestCase類為已有函數創建測繪用例,需要符合以下條件:我們不關心已有函數的測試結果,只關心正確的測試流程固件初始化->執行測試步驟->測試固件清理。每個TestCase只能執行一個測試方法,所以最好每個測試用例有單獨的測試固件(譯者注:我任務這一條不用嚴格執行,多個用例使用相同的測試固件時我一般會寫到一個TestCase里)。
TestSuite類實現測試套件功能,可以整合單獨的測試用例或者其他測試套件。執行測試套件,測試套件中所有的測試用例和子測試套件都會被執行。
執行器提供一個方法run(),該方法接受TestCase或者TestSuite對象最為參數,並且返回TestResult結果對象。PyUnit提供一個使用TextTestRunner執行器的例子,該例子匯報默認的標准錯誤流測試結果。想要更改其他環境的執行器(例如圖形界面環境)並不需要派生自特定的類。
另請參閱:
Module doctest
Another test-support module with a very different flavor.
unittest2: A backport of new unittest features for Python 2.4-2.6
Many new features were added to unittest in Python 2.7, including test discovery. unittest2 allows you to use these features with earlier versions of Python.
Simple Smalltalk Testing: With Patterns
Kent Beck’s original paper on testing frameworks using the pattern shared by unittest.
Third-party unittest frameworks with a lighter-weight syntax for writing tests. For example, assert func(10) == 42.
The Python Testing Tools Taxonomy
An extensive list of Python testing tools including functional testing frameworks and mock object libraries.
Testing in Python Mailing List
A special-interest-group for discussion of testing, and testing tools, in Python.
3. 基本例子
PyUnit模塊提供了大量的工具來構造和運行測試,本部分的例子可以滿足大部分用戶的需求。
以下腳本是測試random模塊的3個函數的例子:
import random import unittest class TestSequenceFunctions(unittest.TestCase): def setUp(self): self.seq = range(10) def test_shuffle(self): # make sure the shuffled sequence does not lose any elements random.shuffle(self.seq) self.seq.sort() self.assertEqual(self.seq, range(10)) # should raise an exception for an immutable sequence self.assertRaises(TypeError, random.shuffle, (1,2,3)) def test_choice(self): element = random.choice(self.seq) self.assertTrue(element in self.seq) def test_sample(self): with self.assertRaises(ValueError): random.sample(self.seq, 20) for element in random.sample(self.seq, 5): self.assertTrue(element in self.seq) if __name__ == '__main__': unittest.main()
通過繼承unittest.TestCase類來創建測試用例,測試用例中3個獨立的測試函數以"test"為開頭命名。通過使用這種命名方式,執行器可以知道哪些方法是測試方法。
需要注意的是,3個測試方法分別調用assertEqual()函數來檢查預期結果;調用assertTrue()函數來判斷條件;調用assertRaises()函數來驗證是否觸發了預期的異常。這3個方法作為斷言語句判斷用例執行正確性,以便於執行器收集測試結果並產生測試報告。
如果定義了setUp()方法,每個測試用例執行前都會執行setUp();同樣的,如果定義了tearDown()方法,每個測試用例執行完后都會執行tearDown()方法。在上面的例子中,setUp()方法用來為每個用例創建一個新序列。
例子最后一段介紹了一種簡單調用測試用例的方法—unittest.main()。它為用例提供了命令行界面運行,腳本運行完成后會輸出如下內容
... ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK
(譯者注:連續的3個點"..."表示3個測試用例都運行通過,如果運行失敗顯示"F",例如".FF"表示后2個用例運行失敗)
有許多更易管理,輸出信息更簡潔,並且不在命令行運行的方法來替代unittest.main()方法運行測試用例。例如以下方法,替換例子的最后一行unittest.main():
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)
改進后的腳本運行后輸出如下:
test_choice (__main__.TestSequenceFunctions) ... ok test_sample (__main__.TestSequenceFunctions) ... ok test_shuffle (__main__.TestSequenceFunctions) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.110s OK
上面的例子展示了unittest模塊的基本用法,掌握它們足夠我們應對日常的測試需求了。本文剩余部分將對unittest所有特性逐一探索。
Copyright © 2014 Xavier Wang. All rights reserved.