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自動化中的開發場景,比如是一個登錄框

  1. 你肯定需要測試賬號空、密碼空、賬號密碼都為空、賬號不存在、密碼錯誤、賬號密碼正確等情況
  2. 這些用例的區別就在於輸入的測試數據和對應的交互結果
  3. 所以我們可以只寫一條登錄測試用例,然后把多組測試數據和期望結果參數化,節省很多代碼量

 

源碼分析

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的列表

作用:主要是為了更加清晰看到用例的含義

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM