unittest:一個通用的測試框架
doctest:一個更簡單的模塊,是為檢查文檔而設計的,同時非常適合用來編寫單元測試。
1.doctest
交互式會話是一種很有用的文檔,可將其放在文檔字符串中。
例如:編寫一個計算平方的函數,並在其文檔字符串中添加一個示例;
def square(x): ... 計算平方並返回結果 >>>square(2) 4 >>>aquare(3) 9 ... return x*x
如上,在文檔字符串中添加了一些文字,假設函數square是在模塊my_math中定義,就可在模塊末尾添加如下代碼:
if name =='_main_' import doctest,my_math doctest.testmod(my_math)
添加的代碼不多,只是導入模塊doctest 和模塊my_math本身,再運行模塊doctest中的函數testmod(表示對模塊進行測試)
$python my_math.py
$
看起來什么都沒發生,但是這是好事。函數doctest.testmod讀取模塊中的所有文檔字符串,查找看起來像是從交互式解釋器中摘取的示例,再檢查這些示例是否反映了實際情況。
注意;如果這里編寫的是真實函數,應該根據前面指定的規則先編寫文檔字符串,再使用doctest運行腳本看看測試是否會失敗,染添加剛好讓測試得以通過的代碼,接下來確保實現是正確的。
為了獲得更多的輸出,可在運行腳本時指定開關-v(verbose,意為詳盡)
$python my_math.py -v
生成如下輸出:
Running my_math._doc_ 0 of 0 examples failed in my_math._doc_ Running my_math.square._doc_ Trying:square(2) Expecting:4 ok Trying:square(3) Expecting:9 ok 0 of 2 examples failed in my_math.square._doc_ 1 items had no tests: test 1 items passed all tests: 2 tests in my_math.square 2 tests in 2 items. 2 passed and 0 failed. Test passed
函數testmod檢查模塊的文檔字符串和函數的文檔字符串。
有測試數據,就可以放心修改代碼了。
Failure in example:square(3) from line #s of my_math.square Expected:9 Got:27 1items had failures: 1 of 2 in my_math.square ***Test Failed*** 1 failures
捕捉到了bug,並清楚地指出錯誤出什么什么地方,就可以修復這個錯誤了
注意:不要盲目的信任測試,而且務必要測試足夠多的情形。例如square(2)的測試沒有捕捉到bug,因為x == 2時, x ** 2 和 x ** x 等價
2.unittest
雖然doctest使用起來很容易,但unittest(基於流行的java測試框架unit)更靈活、更強大;unittest的學習門檻比較高,但是它可以以結構化方式編寫龐大而詳盡的測試集
注意:標准庫包含另外兩個有趣的單元測試工具:pytest(pytest.org)和nose(nose.readthed ocs.io)
案例:需要編寫一個名為 my_math的模塊,其中包含一個計算乘積的函數product。
首先先使用模塊unittest中的TestCase類編寫一個測試(存儲在文件test_y_math.py中)
import unittest,my_math class ProductTestCase(unittest.TestCase): def test_intergers(self): for x in range(-10,10): for y in range(-10,10): p = my_math.product(x,y) self.assertEqual(p,x*y, 'Integer multiplication faied') def test_floats(self): for x in range(-10,10): for y in range(-10,10): x = x / 10 y = y / 10 p = my_math.product(x,y) self.assertEqual(p, x*y, 'Float multiolication failed') if __name__=='_main_':unittest.main()
函數unittest.main負責替你運行測試:實例化所有的TestCase子類,並運行所有名稱以test開頭的方法。
注意:如果你定義了方法setup和teardown,它們將分別在每個測試方法之前和之后執行。可以使用這些方法執行適用於所有測試的初始化代碼和清理代碼,這些代碼稱為 測試夾具(test fixture)
當然,運行這個測試腳本將引發異常,指出模塊my_math不存在。諸如assertEqual等方法檢查指定的條件,以判斷指定的測試是成功還是失敗。TestCase類嗨包含很多與之類似的方法,例如assertTrue、assertIsNone 和 assertAlmostEqual.
模塊unittest區分錯誤和失敗。錯誤指的是引發了異常,而失敗是調用failUnless等方法的結果
可下來就需要編寫框架代碼,消除錯誤,只留下失敗。
待補充~