一、背景
一般進(jìn)行接口測試時,每個接口的傳參都不止一種情況,一般會考慮正向、逆向等多種組合,所以在測試一個接口時,通常會編寫多條case,而這些除了傳參不同外,并沒有什么區(qū)別。這個時候就可以利用ddt來管理測試數(shù)據(jù),提高代碼復(fù)用率。
二、ddt安裝
ddt是python的第三方庫,安裝非常簡單:
pip install ddt
ddt官方文檔地址:https://pypi.org/project/ddt/
三、ddt模塊組成
1、ddt模塊包含類的裝飾器ddt和兩個方法裝飾器data
ddt.ddt:裝飾類,也就是繼承TestCase的類。
ddt.data:裝飾測試方法,參數(shù)是一系列的值。
-
ddt.file_data:裝飾測試方法,參數(shù)是文件名。文件可以是json或者yaml類型。
注意,如果文件是以“.yml”或者".yaml"結(jié)尾,ddt會作為yaml類型處理,其他文件都會作為json文件處理。
如果文件是列表,列表的值會作為測試用例參數(shù),同時,會作為測試用例方法名后綴顯示。
如果文件是字典,字典的key會作為測試用例方法的后綴顯示,字典的value會作為測試用例參數(shù)。
ddt.unpack:傳遞的是復(fù)雜的數(shù)據(jù)結(jié)構(gòu)時使用,比如使用列表或者元組,添加unpack后,ddt會自動把元組或者列表對應(yīng)到多個參數(shù)上。
2、測試用例方法名生成規(guī)則
使用ddt后,會產(chǎn)生一個新的測試用例方法名,即定義的測試用例方法名,比如:def test_one(),這里就是test_one。
data:如果傳遞過來的數(shù)據(jù)存在__ name__ 屬性,則這里就是該數(shù)據(jù)的__ name__ 值。如果未定義__ name__ 屬性,ddt會盡量將傳遞過來的值轉(zhuǎn)化為python標(biāo)識符,作為data顯示。比如:(1,3)就轉(zhuǎn)為1_3。需要注意的是,如果數(shù)據(jù)是字典,則這里就是字典的key。
四、示例
1、使用data傳參數(shù)給測試用例
from ddt import ddt,data,file_data,unpack
import unittest
@ddt
class MyTestDdt(unittest.TestCase):
def setUp(self):
print('start')
@data(2,4)#使用data傳參數(shù)給測試用例
def test_one(self,value):
print(f'the @data number is :{value}')
def tearDown(self):
print('end')
if __name__ == '__main__':
unittest.main(verbosity=2)
結(jié)果:
start
test_one_1_2 (__main__.MyTestDdt) ... ok
the @data number is :2
end
start
the @data number is :4
test_one_2_4 (__main__.MyTestDdt) ... ok
end
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
可以看出data分別傳參數(shù)2和4給測試用例,然后測試用例執(zhí)行了兩遍。另外,注意此時打印出的測試用例名稱已經(jīng)不同,比如:test_one_1_2和test_one_2_4,最后的2和4,分別是傳遞進(jìn)去的參數(shù)。
2、使用unpack分解list或者tuple
from ddt import ddt,data,file_data,unpack
import unittest
@ddt
class MyTestDdt(unittest.TestCase):
def setUp(self):
print('start')
@data((1,2),(4,5)) #元組
@unpack #分解
def test_one(self,value1,value2):
print(f'the @data number is :{value1,value2}')
def tearDown(self):
print('end')
if __name__ == '__main__':
unittest.main(verbosity=2)
結(jié)果:
start
the @data number is :(1, 2)
end
test_one_1__1__2_ (__main__.MyTestDdt) ... ok
start
the @data number is :(4, 5)
test_one_2__4__5_ (__main__.MyTestDdt) ... ok
end
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
可以看出data分別傳元組參數(shù)(1,2)和(4,5)給測試用例,然后測試用例執(zhí)行了兩遍。另外,注意此時打印出的測試用例名稱已經(jīng)不同,比如:test_one_1__ 1__ 2_和test_one_2__ 4__5_ ,最后的1,2和4,5,分別是傳遞進(jìn)去的參數(shù)。
3、用unpack分解字典
from ddt import ddt,data,file_data,unpack
import unittest
@ddt
class MyTestDdt(unittest.TestCase):
def setUp(self):
print('start')
@data({'value1':1,'value2':2},{'value1':3,'value2':4}) #字典
@unpack
def test_one(self,value1,value2):
print(f'the @data number is :{value1,value2}')
def tearDown(self):
print('end')
if __name__ == '__main__':
unittest.main(verbosity=2)
結(jié)果:
test_one_1 (__main__.MyTestDdt) ... ok
start
test_one_2 (__main__.MyTestDdt) ... ok
the @data number is :(1, 2)
----------------------------------------------------------------------
end
Ran 2 tests in 0.000s
start
the @data number is :(3, 4)
OK
end
4、自動化測試實(shí)戰(zhàn)
這里我們登錄新浪郵箱,并利用數(shù)據(jù)驅(qū)動的方式帶參進(jìn)行測試
import unittest
from ddt import ddt,data,unpack
from selenium import webdriver
def testdata():
'''測試數(shù)據(jù)'''
return [('', '', '請輸入郵箱名'), ('', '123456', '請輸入郵箱名'),
('123456', '', '您輸入的郵箱名格式不正確')]
@ddt
class MyMailLogin(unittest.TestCase):
def setUp(self):
self.url = 'https://mail.sina.com.cn/'
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get(self.url)
self.driver.implicitly_wait(30)
@data(*testdata()) #這里加*后會將返回數(shù)據(jù)分為一個個的元組
@unpack
def test_login(self,username,password,result):
'''測試郵箱登錄'''
self.driver.find_element_by_id('freename').clear()
self.driver.find_element_by_id('freename').send_keys(username)
self.driver.find_element_by_id('freepassword').clear()
self.driver.find_element_by_id('freepassword').send_keys(password)
self.driver.find_element_by_link_text('登錄').click()
freeError = self.driver.find_element_by_xpath('//div[@class="freeError"]//span').text
self.assertEqual(freeError,result)
def tearDown(self):
self.driver.quit()
if __name__ == '__main__':
unittest.main(verbosity=2)
結(jié)果:
test_login_1___________請輸入郵箱名__ (__main__.MyMailLogin)
測試郵箱登錄 ... ok
test_login_2_______123456____請輸入郵箱名__ (__main__.MyMailLogin)
測試郵箱登錄 ... ok
test_login_3___123456________您輸入的郵箱名格式不正確__ (__main__.MyMailLogin)
測試郵箱登錄 ... ok
需要注意@data( * testdata()) 這里加*后會將返回數(shù)據(jù)分為一個個的元組,否則unpack無法分解數(shù)據(jù),就會報錯。比如:
def testdata():
return (('', '', '請輸入郵箱名'), ('', '123456', '請輸入郵箱名'),
('123456', '', '您輸入的郵箱名格式不正確'))
print(*testdata()) #三個元組
print(testdata()) #一個元組
結(jié)果:
('', '', '請輸入郵箱名') ('', '123456', '請輸入郵箱名') ('123456', '', '您輸入的郵箱名格式不正確')
(('', '', '請輸入郵箱名'), ('', '123456', '請輸入郵箱名'), ('123456', '', '您輸入的郵箱名格式不正確'))