天天看點

Pytest學習筆記3——參數化

目錄

  前言

  Params參數化(單個)

  Params參數化(多個)

  裝飾器@pytest.mark.parametrize參數化(單個)

  裝飾器@pytest.mark.parametrize參數化(多個)

  多個fixture與@pytest.mark.parametrize組合

  總結

  前言

  在講pytest與unittest的差別文章中,我們知道其中一個差別就是參數化,unittest架構使用的第三方庫ddt來參數化的,而pytest架構就直接使用裝飾器@pytest.mark.parametrize來對測試用例進行傳參。這個是針對測試方法來參數化,還有一種是針對前置處理函數來傳參。但往往這兩種是可以結合使用。

  Params參數化(單個)

  前面講fixture函數時,它有個參數params用來傳遞參數,并且與request結合使用,先看單個:

import pytest

seq = [1, 2, 3]


@pytest.fixture(params=seq)
def test_data(request):
    print("參數")
    return request.param


class TestData:
    def test_1(self, test_data):
        print("用例", test_data)


if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

fixture_test03.py::TestData::test_1[1] 參數
PASSED                            [ 33%]用例 1

fixture_test03.py::TestData::test_1[2] 參數
PASSED                            [ 66%]用例 2

fixture_test03.py::TestData::test_1[3] 參數
PASSED                            [100%]用例 3


============================== 3 passed in 0.05s ==============================
           

  

  Params參數化(多個)

  清單裡有多個dict資料,request會自動化循環讀取每個索引下的值,從0開始,看下面例子:

import pytest

seq = [{'a':1,'b':2},{'c':3,'d':4}]


@pytest.fixture(params=seq)
def test_data(request):
    print("參數:%s"%request.param)
    return request.param


class TestData:
    def test_1(self, test_data):
        print("用例", test_data)




if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

============================== 2 passed in 0.04s ==============================

Process finished with exit code 0
參數:{'a': 1, 'b': 2}
PASSED                   [ 50%]用例 {'a': 1, 'b': 2}
參數:{'c': 3, 'd': 4}
PASSED                   [100%]用例 {'c': 3, 'd': 4}
           

  

  注意:params需要與request一起使用。

  裝飾器@pytest.mark.parametrize參數化(單個)

  我們做接口測試時,編寫測試用例需要輸入一組資料,然後執行程式,得到輸出資料,經過斷言将實際結果與預期結果進行比較,進而得到這條用例執行的結果。但是輸入的資料肯定不是一兩個,這個時候需要參數化,比如登入的接口,我們可以用測試賬号1登入,也可用賬号2,賬号3...進行登入,如果每一個參數寫一條測試用例肯定是不行的,是以引入@pytest.mark.parametrize()裝飾器進行參數化,這就是背景。

  格式:@pytest.mark.parametrize("參數名稱","參數清單"),第一個是參數的名稱,第二個是參數清單(list),也就是參數的值。

  如:@pytest.mark.parametrize("x",[1, 2, 3])

  如:@pytest.mark.parametrize('請求方式,接口位址,傳參,預期結果',[('get','www.baidu.com','{"page":1}','{"code":0,"msg":"成功"})',('post','www.baidu.com','{"page":2}','{"code":0,"msg":"成功"}')])

  1、第一個參數是字元串,多個參數中間用逗号隔開

  2、第二個參數是list,多組資料用元祖類型;傳三個或更多參數也是這樣傳。list的每個元素都是一個元組,元組裡的每個元素和按參數順序一一對應

  3、傳一個參數 @pytest.mark.parametrize('參數名',list) 進行參數化

  4、傳兩個參數@pytest.mark.parametrize('參數名1,參數名2',[(參數1_data[0], 參數2_data[0]),(參數1_data[1], 參數2_data[1])]) 進行參數化

seq = [1, 2, 3]

def get_data(x):
    print(x)
    pass


@pytest.mark.parametrize("x",seq)
def test_data(x):
    a = get_data(x)
    print(a)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                                   [ 33%]1
None
PASSED                                   [ 66%]2
None
PASSED                                   [100%]3
None
           

  

  備注:第一個函數輸出的是參數值,類中的函數列印的是外面那個函數的傳回值,因為沒有return,預設傳回是None。

  與request結合使用

  如果裝飾器@pytest.mark.parametrize與request結合使用,如果測試方法寫在類中,則@pytest.mark.parametrize的參數名稱要與@pytest.fixture函數名稱保持一緻。并且要添加indirect=True參數,目的是把ss_data當做函數去執行,而不是參數。

  如:

  

import pytest
seq = [1,2,3]
@pytest.fixture()
def ss_data(request):
    print("參數:%s"%request.param)
    return request.param



class TestData:
    @pytest.mark.parametrize("ss_data",seq,indirect=True)
    def test_1(self,ss_data):
        print("用例", ss_data)

if __name__ == '__main__':
    pytest.main()
           

  

  

  運作結果:

  

collecting ... collected 3 items

fixture_test03.py::TestData::test_1[1] 
fixture_test03.py::TestData::test_1[2] 
fixture_test03.py::TestData::test_1[3] 

============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
參數:1
PASSED                            [ 33%]用例 1
參數:2
PASSED                            [ 66%]用例 2
參數:3
PASSED                            [100%]用例 3
           

  

  注意1:如果将@pytest.mark.parametrize參數名稱改成x的執行,就會報錯如:

Pytest學習筆記3——參數化

  注意2:如果不使用fixture裝飾器函數,也不使用外部函數,也是可以的,例子如下:

import pytest
seq = [1,2,3]

class TestData:
    @pytest.mark.parametrize("x",seq,indirect=False)
    def test_1(self,x):
        print("用例", x)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

============================== 3 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                            [ 33%]用例 1
PASSED                            [ 66%]用例 2
PASSED                            [100%]用例 3
           

  可以看出,裝飾器@pytest.mark.parametrize參數傳遞的是參數名稱了,而不是函數了。根據開關indirect自由控制,預設是False.

  裝飾器@pytest.mark.parametrize參數化(多個)

   多個參數和單個參數寫法差不多,隻不過多個參數中間用逗号隔開,清單中用元組來分組,舉個例子(不帶類的測試方法和沒有使用request參數):

import pytest
seq = [(1,2),(3,4)]

def get_data(x,y):
    print(x)
    print(y)
    pass


@pytest.mark.parametrize("x,y",seq)
def test_data(x,y):
    get_data(x,y)
    # print(a)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

============================== 2 passed in 0.04s ==============================

Process finished with exit code 0
PASSED                                 [ 50%]1
2
PASSED                                 [100%]3
4
           

  這就是把參數清單list裡面的元組中兩個值,看作一對參數(x,y)。

  與request結合使用

  前面介紹過單個使用的場景,現在是多個參數的時候,如何使用呢?

  其實差不多,但是需要注意一些問題,先看個例子:

import pytest
seq = [(1,2),(3,4)]

@pytest.fixture()
def get_data(request):
    x = request.param[0]
    y = request.param[1]
    print(x,111)
    print(y,222)
    # print(request.param)
    pass

# indirect=True聲明x是個函數
@pytest.mark.parametrize("get_data",seq)
def test_data(get_data):
    print(get_data)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

plugins: allure-pytest-2.8.6, rerunfailures-5.0
collecting ... collected 2 items

fixture_005.py::test_data[get_data0] PASSED                              [ 50%](1, 2)

fixture_005.py::test_data[get_data1] PASSED                              [100%](3, 4)


============================== 2 passed in 0.02s ==============================

Process finished with exit code 0
           

  我們可以看出來fixture裝飾器函數根本沒有執行,這是為什麼呢?

  因為使用@pytest.mark.parametrize裝飾器參數化時,預設是以參數而不是函數,這裡的@pytest.mark.parametrize("get_data",seq)中get_data是參數名稱,不是函數,如果要聲明為函數,需要添加:indirect=True。

  我們将其改之,再運作:

import pytest
seq = [(1,2),(3,4)]

@pytest.fixture()
def get_data(request):
    x = request.param[0]
    y = request.param[1]
    print(x,111)
    print(y,222)
    # print(request.param)
    pass

# indirect=True聲明x是個函數
@pytest.mark.parametrize("get_data",seq,indirect=True)
def test_data(get_data):
    print(get_data)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

fixture_005.py::test_data[get_data0] 1 111
2 222
PASSED                              [ 50%]None

fixture_005.py::test_data[get_data1] 3 111
4 222
PASSED                              [100%]None


============================== 2 passed in 0.02s ==============================

Process finished with exit code 0
           

  

  多個fixture與@pytest.mark.parametrize組合

  用例前面可以有多個條件,參數化裝飾器也可以疊加,使用parametrize裝飾器疊加時,用例組合是2個參數個數相乘

  

import pytest

seq1 = [1,2,3]
seq2 = [4,5,6]

@pytest.fixture()
def get_seq1(request):
    seq1 = request.param
    print("seq1:",seq1)
    return seq1

@pytest.fixture()
def get_seq2(request):
    seq2 = request.param
    print("seq2:", seq2)
    return seq2

@pytest.mark.parametrize("get_seq1",seq1,indirect=True)
@pytest.mark.parametrize("get_seq2",seq2,indirect=True)
def test_1(get_seq1,get_seq2):
    print(get_seq1,11)
    print(get_seq2,22)

if __name__ == '__main__':
    pytest.main()
           

  

  運作結果:

collecting ... collected 9 items

fixture_test04.py::test_1[4-1] 
fixture_test04.py::test_1[4-2] 
fixture_test04.py::test_1[4-3] 
fixture_test04.py::test_1[5-1] 
fixture_test04.py::test_1[5-2] 
fixture_test04.py::test_1[5-3] 
fixture_test04.py::test_1[6-1] 
fixture_test04.py::test_1[6-2] 
fixture_test04.py::test_1[6-3] 

============================== 9 passed in 0.07s ==============================

Process finished with exit code 0
seq1: 1
seq2: 4
PASSED                                    [ 11%]1 11
4 22
seq1: 2
seq2: 4
PASSED                                    [ 22%]2 11
4 22
seq1: 3
seq2: 4
PASSED                                    [ 33%]3 11
4 22
seq1: 1
seq2: 5
PASSED                                    [ 44%]1 11
5 22
seq1: 2
seq2: 5
PASSED                                    [ 55%]2 11
5 22
seq1: 3
seq2: 5
PASSED                                    [ 66%]3 11
5 22
seq1: 1
seq2: 6
PASSED                                    [ 77%]1 11
6 22
seq1: 2
seq2: 6
PASSED                                    [ 88%]2 11
6 22
seq1: 3
seq2: 6
PASSED                                    [100%]3 11
6 22
           

  

  如果使用類,也是一樣的,如圖:

Pytest學習筆記3——參數化

   seq1和seq2參數都是3個,是以總的用例數就是9個。

  單獨使用@pytest.mark.parametrize參數組合

Pytest學習筆記3——參數化

  總結

  pytest與unittest的差別之一參數化已經講完,希望可以幫助你學習pytest架構。

  如果對你有幫助或喜歡自動化測試開發的朋友,可以加入右下方QQ交流群學習與探索,更多幹貨與你分享。