Python基礎教程之pytest參數(shù)化詳解
前言
上篇博文介紹過,pytest是目前比較成熟功能齊全的測試框架,使用率肯定也不斷攀升。在實際
工作中,許多測試用例都是類似的重復,一個個寫最后代碼會顯得很冗余。這里,我們來了解一下
@pytest.mark.parametrize裝飾器,可以很好的解決上述問題。
源代碼分析
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):
""" Add new invocations to the underlying test function using the list
of argvalues for the given argnames. Parametrization is performed
during the collection phase. If you need to setup expensive resources
see about setting indirect to do it rather at test setup time. # 使用給定argnames的argValue列表向基礎測試函數(shù)添加新的調用,在收集階段執(zhí)行參數(shù)化。
:arg argnames: a comma-separated string denoting one or more argument
names, or a list/tuple of argument strings. # 參數(shù)名:使用逗號分隔的字符串,列表或元祖,表示一個或多個參數(shù)名
:arg argvalues: The list of argvalues determines how often a
test is invoked with different argument values. If only one
argname was specified argvalues is a list of values. If N
argnames were specified, argvalues must be a list of N-tuples,
where each tuple-element specifies a value for its respective
argname. # 參數(shù)值:只有一個argnames,argvalues則是值列表。有N個argnames時,每個元祖對應一組argnames,所有元祖組合成一個列表
:arg indirect: The list of argnames or boolean. A list of arguments'
names (self,subset of argnames). If True the list contains all names from
the argnames. Each argvalue corresponding to an argname in this list will
be passed as request.param to its respective argname fixture
function so that it can perform more expensive setups during the
setup phase of a test rather than at collection time.
:arg ids: list of string ids, or a callable.
If strings, each is corresponding to the argvalues so that they are
part of the test id. If None is given as id of specific test, the
automatically generated id for that argument will be used.
If callable, it should take one argument (self,a single argvalue) and return
a string or return None. If None, the automatically generated id for that
argument will be used.
If no ids are provided they will be generated automatically from
the argvalues. # ids:字符串列表,可以理解成標題,與用例個數(shù)保持一致
:arg scope: if specified it denotes the scope of the parameters.
The scope is used for grouping tests by parameter instances.
It will also override any fixture-function defined scope, allowing
to set a dynamic scope using test context or configuration.
# 如果指定,則表示參數(shù)的范圍。作用域用于按參數(shù)實例對測試進行分組。
它還將覆蓋任何fixture函數(shù)定義的范圍,允許使用測試上下文或配置設置動態(tài)范圍。
"""argnames
釋義:參數(shù)名稱
格式:字符串"arg1,arg2,arg3"
aegvalues
釋義:參數(shù)值列表
格式:必須是列表,如[val1,val2,val3]
單個參數(shù),里面是值的列表,如@pytest.mark.parametrize("name",["Jack","Locus","Bill"])
多個參數(shù),需要用元祖來存放值,一個元祖對應一組參數(shù)的值,如@pytest.mark.parametrize("user,age",[("user1",15),("user2",24),("user3",25)])
ids
釋義:可以理解為用例的id
格式:字符串列表,如["case1","case2","case3"]
indirect
釋義:當indirect=True時,若傳入的argnames是fixture函數(shù)名,此時fixture函數(shù)名將成為一個可執(zhí)行的函數(shù),
argvalues作為fixture的參數(shù),執(zhí)行fixture函數(shù),最終結果再存入 request.param;當indirect=False時,fixture
函數(shù)只作為一個參數(shù)名給測試收集階段調用。
備注:這里可以將the setup phase(測試設置階段)理解為配置 conftest.py 階段,將the collection phase(
測試收集階段)理解為用例執(zhí)行階段。
裝飾測試類
import pytest
data = [
(2,2,4),
(3,4,12)
]
def add(a,b):
return a * b
@pytest.mark.parametrize('a,b,expect',data)
class TestParametrize(object):
def test_parametrize_1(self,a,b,expect):
print('\n測試函數(shù)1測試數(shù)據(jù)為\n{}-{}'.format(a,b))
assert add(a,b) == expect
def test_parametrize_2(self,a,b,expect):
print('\n測試函數(shù)2測試數(shù)據(jù)為\n{}-{}'.format(a,b))
assert add(a,b) == expect
if __name__ == "__main__":
pytest.main(["-s","test_07.py"])============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: D:\AutoCode plugins: html-3.1.1, metadata-1.11.0 collecting ... collected 4 items test_07.py::TestParametrize::test_parametrize_1[2-2-4] 測試函數(shù)1測試數(shù)據(jù)為 2-2 PASSED test_07.py::TestParametrize::test_parametrize_1[3-4-12] 測試函數(shù)1測試數(shù)據(jù)為 3-4 PASSED test_07.py::TestParametrize::test_parametrize_2[2-2-4] 測試函數(shù)2測試數(shù)據(jù)為 2-2 PASSED test_07.py::TestParametrize::test_parametrize_2[3-4-12] 測試函數(shù)2測試數(shù)據(jù)為 3-4 PASSED ============================== 4 passed in 0.12s ============================== Process finished with exit code 0
由以上代碼可以看到,當裝飾器裝飾測試類時,定義的數(shù)據(jù)集合會被傳遞給類的所有方法。
裝飾測試函數(shù)
單個數(shù)據(jù)
import pytest
data = ["Rose","white"]
@pytest.mark.parametrize("name",data)
def test_parametrize(name):
print('\n列表中的名字為\n{}'.format(name))
if __name__ == "__main__":
pytest.main(["-s","test_07.py"])============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: D:\AutoCode plugins: html-3.1.1, metadata-1.11.0 collected 2 items test_07.py 列表中的名字為 Rose . 列表中的名字為 white . ============================== 2 passed in 0.09s ============================== Process finished with exit code 0
當測試用例只需要一個參數(shù)時,我們存放數(shù)據(jù)的列表無序嵌套序列,@pytest.mark.parametrize("name", data)
裝飾器的第一個參數(shù)也只需要一個變量接收列表中的每個元素,第二個參數(shù)傳遞存儲數(shù)據(jù)的列表,那么測試用
例需要使用同名的字符串接收測試數(shù)據(jù)(實例中的name)且列表有多少個元素就會生成并執(zhí)行多少個測試用例。
一組數(shù)據(jù)
import pytest
data = [
[1, 2, 3],
[4, 5, 9]
] # 列表嵌套列表
# data_tuple = [
# (1, 2, 3),
# (4, 5, 9)
# ] # 列表嵌套元組
@pytest.mark.parametrize('a, b, expect', data)
def test_parametrize_1(a, b, expect): # 一個參數(shù)接收一個數(shù)據(jù)
print('\n測試數(shù)據(jù)為\n{},{},{}'.format(a, b, expect))
actual = a + b
assert actual == expect
@pytest.mark.parametrize('value', data)
def test_parametrize_2(value): # 一個參數(shù)接收一組數(shù)據(jù)
print('\n測試數(shù)據(jù)為\n{}'.format(value))
actual = value[0] + value[1]
assert actual == value[2]
if __name__ == "__main__":
pytest.main(["-s","test_07.py"])============================= test session starts ============================= platform win32 -- Python 3.8.0, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 rootdir: D:\AutoCode plugins: html-3.1.1, metadata-1.11.0 collected 4 items test_07.py 測試數(shù)據(jù)為 1,2,3 . 測試數(shù)據(jù)為 4,5,9 . 測試數(shù)據(jù)為 [1, 2, 3] . 測試數(shù)據(jù)為 [4, 5, 9] . ============================== 4 passed in 0.09s ============================== Process finished with exit code 0
當測試用例需要多個數(shù)據(jù)時,我們可以使用嵌套序列(嵌套元組&嵌套列表)的列表來存放測試數(shù)據(jù)。
裝飾器@pytest.mark.parametrize()可以使用單個變量接收數(shù)據(jù),也可以使用多個變量接收,同樣,測
試用例函數(shù)也需要與其保持一致。
當使用單個變量接收時,測試數(shù)據(jù)傳遞到測試函數(shù)內部時為列表中的每一個元素或者小列表,需
要使用索引的方式取得每個數(shù)據(jù)。
當使用多個變量接收數(shù)據(jù)時,那么每個變量分別接收小列表或元組中的每個元素列表嵌套多少個多
組小列表或元組,測生成多少條測試用例。
組合數(shù)據(jù)
import pytest
data_1 = [1,2,3]
data_2 = ['a','b']
@pytest.mark.parametrize('a',data_1)
@pytest.mark.parametrize('b',data_2)
def test_parametrize_1(a,b):
print(f'笛卡爾積測試結果為:{a},')
if __name__ == '__main__':
pytest.main(["-vs","test_06.py"])
通過測試結果,我們不難分析,一個測試函數(shù)還可以同時被多個參數(shù)化裝飾器裝飾,那么多個
裝飾器中的數(shù)據(jù)會進行交叉組合的方式傳遞給測試函數(shù),進而生成n * n個測試用例。
標記用例
import pytest
@pytest.mark.parametrize("test_input,expected",[
("3+5",8),
("2+4",6),
pytest.param("6 * 9",42,marks=pytest.mark.xfail),
pytest.param("6 * 6",42,marks=pytest.mark.skip)
])
def test_mark(test_input,expected):
assert eval(test_input) == expected
if __name__ == '__main__':
pytest.main(["-vs","test_06.py"])
輸出結果顯示收集到4個用例,兩個通過,一個被跳過,一個標記失敗,當我們不想執(zhí)行某組測試
數(shù)據(jù)時,我們可以標記skip或skipif;當我們預期某組數(shù)據(jù)會執(zhí)行失敗時,我們可以標記為xfail等。
嵌套字典
import pytest
data = (
{
'user': "name1",
'pwd': 123
},
{
'user': "name2",
'pwd': 456
}
)
@pytest.mark.parametrize('dic',data)
def test_parametrize(dic):
print('\n測試數(shù)據(jù)為\n{}'.format(dic))
if __name__ == '__main__':
pytest.main(["-vs","test_06.py"])
增加測試結果可讀性
參數(shù)化裝飾器有一個額外的參數(shù)ids,可以標識每一個測試用例,自定義測試數(shù)據(jù)結果的顯示,
為了增加可讀性,我們可以標記每一個測試用例使用的測試數(shù)據(jù)是什么,適當?shù)脑黾右恍┱f明。
在使用前你需要知道,ids參數(shù)應該是一個字符串列表,必須和數(shù)據(jù)對象列表的長度保持一致。
import pytest
data_1 = [
(1, 2, 3),
(4, 5, 9)
]
ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in data_1]
def add(a, b):
return a + b
@pytest.mark.parametrize('a, b, expect', data_1, ids=ids)
class TestParametrize(object):
def test_parametrize_1(self, a, b, expect):
print('\n測試函數(shù)1測試數(shù)據(jù)為\n{}-{}'.format(a, b))
assert add(a, b) == expect
def test_parametrize_2(self, a, b, expect):
print('\n測試函數(shù)2數(shù)據(jù)為\n{}-{}'.format(a, b))
assert add(a, b) == expect
if __name__ == '__main__':
pytest.main(["-v","test_06.py"])不加ids參數(shù)的返回結果

加ids參數(shù)的返回結果

我們可以看到帶ids參數(shù)的返回結果中的用例都被一個列表明確的標記了,而且通過這種標記
可以更加直觀的看出來,每個測試用例使用的數(shù)據(jù)名稱及測試內容。
總結
到此這篇關于Python基礎教程之pytest參數(shù)化詳解的文章就介紹到這了,更多相關Python pytest參數(shù)化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- pytest實戰(zhàn)技巧之參數(shù)化基本用法和多種方式
- Python中pytest的參數(shù)化實例解析
- pytest使用@pytest.mark.parametrize()實現(xiàn)參數(shù)化的示例代碼
- pytest?fixtures函數(shù)及測試函數(shù)的參數(shù)化解讀
- pytest使用parametrize將參數(shù)化變量傳遞到fixture
- pytest實現(xiàn)測試用例參數(shù)化
- Pytest單元測試框架如何實現(xiàn)參數(shù)化
- Pytest參數(shù)化parametrize使用代碼實例
- pytest參數(shù)化:@pytest.mark.parametrize詳解
相關文章
解讀pandas交叉表與透視表pd.crosstab()和pd.pivot_table()函數(shù)
這篇文章主要介紹了pandas交叉表與透視表pd.crosstab()和pd.pivot_table()函數(shù)的用法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-09-09
Python socket實現(xiàn)的簡單通信功能示例
這篇文章主要介紹了Python socket實現(xiàn)的簡單通信功能,結合實例形式分析了Python socket通信的相關概念、原理、客戶端與服務器端實現(xiàn)技巧以及socketserver模塊多并發(fā)簡單實現(xiàn)方法,需要的朋友可以參考下2018-08-08
使用Python進行網絡數(shù)據(jù)可視化的多種方法與技巧
可視化是理解和解釋大量數(shù)據(jù)的強大工具之一,而Python作為一種流行的編程語言,提供了豐富的庫和工具來進行網絡數(shù)據(jù)可視化,本文將介紹一些使用Python進行網絡數(shù)據(jù)可視化的方法與技巧,并提供相應的代碼實例,需要的朋友可以參考下2024-05-05
Python虛擬環(huán)境的創(chuàng)建和使用詳解
這篇文章主要給大家介紹了關于Python虛擬環(huán)境的創(chuàng)建和使用的相關資料,文中通過圖文介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-09-09
python 數(shù)據(jù)提取及拆分的實現(xiàn)代碼
這篇文章主要介紹了python 數(shù)據(jù)提取及拆分的實現(xiàn)代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-08-08

