Pytest系列(9) - 引數化@pytest.mark.parametrize
如果你還想從頭學起Pytest,可以看看這個系列的文章哦!
https://www.cnblogs.com/poloyy/category/1690628.html
前言
pytest允許在多個級別啟用測試引數化:
- pytest.fixture() 允許fixture有引數化功能(後面講解)
- @pytest.mark.parametrize 允許在測試函式或類中定義多組引數和fixtures
- pytest_generate_tests 允許定義自定義引數化方案或擴充套件(拓展)
引數化場景
只有測試資料和期望結果不一樣,但操作步驟是一樣的測試用例可以用上引數化;
可以看看下面的栗子
未引數化的程式碼
def test_1(): assert 3 + 5 == 9 def test_2(): assert 2 + 4 == 6 def test_3(): assert 6 * 9 == 42
可以看到,三個用例都是加法然後斷言某個值,重複寫三個類似的用例有點冗餘
利用引數化優化之後的程式碼
@pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+4", 6), ("6*9", 42)]) def test_eval(test_input, expected): print(f"測試資料{test_input},期望結果{expected}") assert eval(test_input) == expected
執行結果
可以看到,只有一條用例,但是利用引數化輸入三組不同的測試資料和期望結果,最終執行的測試用例數=3,可以節省很多程式碼
實際Web UI自動化中的開發場景,比如是一個登入框
- 你肯定需要測試賬號空、密碼空、賬號密碼都為空、賬號不存在、密碼錯誤、賬號密碼正確等情況
- 這些用例的區別就在於輸入的測試資料和對應的互動結果
- 所以我們可以只寫一條登入測試用例,然後把多組測試資料和期望結果引數化,節省很多程式碼量
原始碼分析
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):
argnames
原始碼解析:a comma-separated string denoting one or more argument names, or a list/tuple of argument strings.
含義:引數名字
格式:字串"arg1,arg2,arg3"【需要用逗號分隔】
備註:原始碼中寫了可以是引數字串的list或者tuple,但博主實操過是不行的,不知道是不是寫的有問題,大家可以看看評論下
示例
@pytest.mark.parametrize(["name", "pwd"], [("yy1", "123"), ("yy2", "123")]) # 錯的 @pytest.mark.parametrize(("name", "pwd"), [("yy1", "123"), ("yy2", "123")]) # 錯的 @pytest.mark.parametrize("name,pwd", [("yy1", "123"), ("yy2", "123")])
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.【如果有多個引數,則用元組來存每一組值】
含義:引數值列表
格式:必須是列表,如:[ val1,val2,val3 ]
如果只有一個引數,裡面則是值的列表如:@pytest.mark.parametrize("username", ["yy", "yy2", "yy3"])
如果有多個引數例,則需要用元組來存放值,一個元組對應一組引數的值,如:@pytest.mark.parametrize("name,pwd", [("yy1", "123"), ("yy2", "123"), ("yy3", "123")])
備註:雖然原始碼說需要list包含tuple,但我試了下,tuple包含list,list包含list也是可以的........
ids
含義:用例的ID
格式:傳一個字串列表
作用:可以標識每一個測試用例,自定義測試資料結果的顯示,為了增加可讀性
強調:ids的長度需要與測試資料列表的長度一致
indirect
作用:如果設定成True,則把傳進來的引數當函式執行,而不是一個引數(下一篇博文即講解)
講完原始碼,對方法有更深入的瞭解了,我們就講講常用的場景
裝飾測試類
@pytest.mark.parametrize('a, b, expect', data_1) class TestParametrize: def test_parametrize_1(self, a, b, expect): print('\n測試函式11111 測試資料為\n{}-{}'.format(a, b)) assert a + b == expect def test_parametrize_2(self, a, b, expect): print('\n測試函式22222 測試資料為\n{}-{}'.format(a, b)) assert a + b == expect
執行結果
重點
當裝飾器 @pytest.mark.parametrize 裝飾測試類時,會將資料集合傳遞給類的所有測試用例方法
“笛卡爾積”,多個引數化裝飾器
# 笛卡爾積,組合資料 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},{b}')
執行結果
重點知識
- 一個函式或一個類可以裝飾多個 @pytest.mark.parametrize
- 這種方式,最終生成的用例數是n*m,比如上面的程式碼就是:引數a的資料有3個,引數b的資料有2個,所以最終的用例數有3*2=6條
- 當引數化裝飾器有很多個的時候,用例數都等於n*n*n*n*....
引數化 ,傳入字典資料
# 字典 data_1 = ( { 'user': 1, 'pwd': 2 }, { 'user': 3, 'pwd': 4 } ) @pytest.mark.parametrize('dic', data_1) def test_parametrize_1(dic): print(f'測試資料為\n{dic}') print(f'user:{dic["user"]},pwd{dic["pwd"]}')
沒啥特別的,只是資料型別是常見的dict而已
執行結果
09parametrize.py::test_parametrize_1[dic0] PASSED [ 50%]測試資料為 {'user': 1, 'pwd': 2} user:1,pwd2 09parametrize.py::test_parametrize_1[dic1] PASSED [100%]測試資料為 {'user': 3, 'pwd': 4} user:3,pwd4
引數化,標記資料
# 標記引數化 @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
執行結果
引數化,增加可讀性
# 增加可讀性 data_1 = [ (1, 2, 3), (4, 5, 9) ] # ids ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in data_1] @pytest.mark.parametrize('a, b, expect', data_1, ids=ids) class TestParametrize(object): def test_parametrize_1(self, a, b, expect): print('測試函式1測試資料為{}-{}'.format(a, b)) assert a + b == expect def test_parametrize_2(self, a, b, expect): print('測試函式2資料為{}-{}'.format(a, b)) assert a + b == expect
執行結果
知識點
多少組資料,就要有多少個id,然後組成一個id的列表
作用:主要是為了更加清晰看到用例的含義
&n