工作後忽然發現,對於一個開發者,自己的代碼一定要做好充分的單元測試才能提交代碼。
單元測試可以有效地測試某個程序模塊的行爲,是未來重構代碼的信心保證。
單元測試的測試用例要覆蓋常用的輸入組合、邊界條件和異常。
單元測試代碼要非常簡單,如果測試代碼太複雜,那麼測試代碼本身就可能有bug。
單元測試通過了並不意味着程序就沒有bug了,但是不通過程序肯定有bug。
其他的不多說,直接看一個測試:
我們來編寫一個Dict類,這個類的行爲和dict一致,但是可以通過屬性來訪問,用起來就像下面這樣:
>>> d = Dict(a=1, b=2)
>>> d['a']
1
>>> d.a
1
mydict.py的實現代碼和測試代碼如下:
class Dict(dict):
def __init__(self, **kw):
super(Dict, self).__init__(**kw)
def __getattr__(self, key):
try:
return self[key]
except KeyError:
raise AttributeError(r"'Dict' object has no attribute '%s' " % key)
def __setattr__(self, key, value):
self[key] = value
if __name__ == "__main__":
import unittest
class TestDict(unittest.TestCase):
"""
Unit test case for class Dict
"""
def setUp(self):
print 'setUp...'
def tearDown(self):
print 'tearDown...'
def test_init(self):
d = Dict(a=1, b='test')
self.assertEquals(d.a, 1)
self.assertEquals(d.b, 'test')
self.assertTrue(isinstance(d, dict))
def test_key(self):
d = Dict()
d['key'] = 'value'
self.assertEquals(d.key, 'value')
def test_attr(self):
d = Dict()
d.key = 'value'
self.assertTrue('key' in d)
self.assertEquals(d['key'], 'value')
def test_keyerror(self):
d = Dict()
with self.assertRaises(KeyError):
value = d['empty']
def test_attrerror(self):
d = Dict()
with self.assertRaises(AttributeError):
value = d.empty
unittest.main()
有的一些地方,把測試用例代碼和被測試的代碼分開寫,個人覺得不好管理。
編寫單元測試時,我們需要編寫一個測試類,從unittest.TestCase繼承。
以test開頭的方法就是測試方法,不以test開頭的方法不被認爲是測試方法,測試的時候不會被執行。
對每一類測試都需要編寫一個test_xxx()方法。由於unittest.TestCase提供了很多內置的條件判斷,我們只需要調用這些方法就可以斷言輸出是否是我們所期望的。最常用的斷言就是assertEquals()。
另一種重要的斷言就是期待拋出指定類型的Error,比如通過d[‘empty’]訪問不存在的key時,斷言會拋出KeyError。
通過在類最後調用unittest.main()
就可以執行測試用例代碼。
可以在單元測試中編寫兩個特殊的setUp()和tearDown()方法。這兩個方法會分別在每調用一個測試方法的前後分別被執行。
setUp()和tearDown()方法有什麼用呢?設想你的測試需要啓動一個數據庫,這時,就可以在setUp()方法中連接數據庫,在tearDown()方法中關閉數據庫,這樣,不必在每個測試方法中重複相同的代碼。