1、概覽
單元測試是用來對乙個模組、乙個函式或者乙個類來進行正確性檢驗的測試工作。
比如對函式
abs()
,我們可以編寫出以下幾個測試用例:
輸入正數,比如1、
1.2、
0.99
,期待返回值與輸入相同;
輸入負數,比如-1、
-1.2
、-0.99
,期待返回值與輸入相反;輸入0
,期待返回0;
輸入非數值型別,比如
none、
、{},期待丟擲
typeerror
。 把上面的測試用例放到乙個測試模組裡,就是乙個完整的單元測試。
單元測試的意義:
1.1、編寫乙個測試單元
編寫乙個
dict
類,這個類的行為和
dict
一致,但是可以通過屬性來訪問。
#mydict.py
class dict(dict):
def __init__(self, **kw):
# 初始化例項,可以傳入任意個關鍵字引數,即鍵值對
super().__init__(**kw)
#super()
無引數,是按
mro表,呼叫父類的方法。這裡是將
**kw
交給父類
dict
初始化
def __getattr__(self, key):
#dict
沒有設定初始屬性,所以
dict()
每使用乙個屬性,會用到
__getattr__
方法 try:
return self[key]
# 如果有該屬性,正常執行
except keyerror:
raise attributeerror(r"'dict' object has no attribute '%s'" % key)
# 無該屬性,丟擲錯誤
def __setattr__(self, key, value):
# 新增鍵值對。即新增屬性
self[key] = value
編寫單元測試
#mydict_test.py
import unittest
from mydict import dict
# 繼承的父類是unittest.testcase
# 它提供了很多內建的條件判斷,我們只需要呼叫這些方法就可以斷言輸出是否是我們所期望的
class testdict(unittest.testcase):
def test_init(self):
# 測試
dict
能否正常建立例項,並獲取到例項的屬性
d = dict(a=1, b='test')
self.assertequal(d.a, 1)#斷言
d.a
的返回結果與
1相等。相等才能繼續執行
self.assertequal(d.b, 'test')
self.asserttrue(isinstance(d, dict))
def test_key(self):
# dict()
能否正確新增屬性
d = dict()
d['key'] = 'value'
self.assertequal(d.key, 'value')
def test_attr(self):
# dict()
能否正確獲取屬性的
value
d = dict()
d.key = 'value'
self.asserttrue('key' in d)
self.assertequal(d['key'], 'value')
def test_keyerror(self):
# 錯誤測試
d = dict()
with self.assertraises(keyerror):
# 獲取不存在的屬性的
value
值時,期待報錯
value = d['empty']
def test_attrerror(self):
# 錯誤測試,同上,獲取屬性
value
值得方法不同,丟擲的錯誤不同
d = dict()
with self.assertraises(attributeerror):
# 獲取不存在的屬性的
value
值時,期待報錯
value = d.empty
總結:
with self.assertraises(keyerror):
value = d['empty']
執行單元測試
執行方式一:
在mydict_test.py的最後加上兩行**,這樣可以把mydict_test.py當做正常的python指令碼執行
if __name__ == '__main__':
unittest.main()
$ python mydict_test.py
執行方式二:
在命令列通過引數-m unittest直接執行單元測試,這樣可以一次批量執行很多單元測試
$ python -m unittest mydict_test
1.2、setup
與teardown
setup()和teardown()方法。會分別在每呼叫乙個測試方法的前後分別被執行
用法: 如果你的測試需要啟動乙個資料庫,就可以在setup()方法中連線資料庫,在teardown()方法中關閉資料庫,這樣,不必在每個測試方法中重複相同的**:
class testdict(unittest.testcase):
def setup(self):
print('setup...')
def teardown(self):
print('teardown...')2、
super()
函式 我們在編寫dict類時。用到了super(),並用其呼叫了父類dict的方法。在此,我們詳解supper()。
super()
的功能就是呼叫父類函式的方法,並且保證每個父類函式只呼叫一次(如果每個類都使用super)
2.1、super()
的入門與使用
在類的繼承中,如果重定義某個方法,該方法會覆蓋父類的同名方法,但有時,我們希望能同時實現父類的功能,這時,我們可以用super()呼叫父類的方法。
class animal(object):
# 定義了乙個
animal
類 def __init__(self, name):
self.name = name
def greet(self):
# 定義了乙個
greet()
方法 print 'hello, i am %s.' % self.name
class dog(animal):
#定義了乙個
dog類,父類是
animal
def greet(self):
# 也定以了乙個
greet()
方法,但這個方法是呼叫
animal
的方法 super(dog, self).greet() #將
dog建立的例項名,按
mro
表的順序,傳給
dog的下乙個父類,呼叫該父類的方法
print 'wangwang...'
# 呼叫結果
>>> dog = dog('dog')
>>> dog.greet()
hello, i am dog.
# 父類方法
wangwang..
# 子類方法
2.2、mro
列表 雖然
super
()呼叫父類的方法,但卻和父類沒有實質性的關聯。它的呼叫順序是根據
mro表來的
對於你定義的每乙個類,python 會計算出乙個方法解析順序(method resolution order, mro)列表,它代表了類繼承的順序
>>> dog.mro()#檢視
dog類的
mro表
[, , ]
>>> c.mro()
# base是[a
、b]的父類,[a、
b]是c的父類
[__main__.c, __main__.a, __main__.b, __main__.base, object]
mro 列表的順序通過乙個 c3 線性化演算法來實現的。總的來說,乙個類的 mro 列表就是合併所有父類的 mro 列表,並遵循以下三條原則:
2.3、super
工作原理
super工作原理如下:
def super(cls, inst):
# cls
錶類,inst
是cls
建立的例項。獲 cls 在 inst 的 mro 列表中的下乙個類。
mro = inst.__class__.mro()
# 獲取
inst
的mro
表 return mro[mro.index(cls) + 1]
#返回表中當前
cls的下標,並
+1,即返回當前
cls的下乙個父類
python: 你不知道的 super
(
python學習筆記 day8(3)
def 函式名 引數列表 函式體return 表示式 在沒有引數時,要保留 在return時,會根據表示式返回乙個值給呼叫方,如果不帶返回值,則相當於返回 none 通過函式名呼叫函式,也要注意在呼叫函式時引數的問題。在python中,型別屬於物件,變數沒有型別 在傳入引數時,不同的引數型別會產生不...
Python學習筆記 8 3 函式 返回值
例1 def db connect ip,port 3306 print ip,port res db connect 118.24.3.40 3307 如果函式中沒有return,print res 會返回none。例2 def my2 for i in range 50 return i pri...
Python學習筆記 12 10章 XML
1 概覽 xml雖然比json複雜,在web中應用也不如以前多了,不過仍有很多地方在用,所以,有必要了解如何操作xml。1 dom vs sax 操作xml有兩種方法 dom和sax。dom會把整個xml讀入記憶體,解析為樹,因此占用記憶體大,解析慢,優點是可以任意遍歷樹的節點。sax是流模式,邊讀...