1. 程式人生 > >Pytest系列(9) - 引數化@pytest.mark.parametrize

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

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

&n