1. 程式人生 > >Pytest進階之引數化

Pytest進階之引數化

前言

unittest單元測試框架使用DDT進行資料驅動測試,那麼身為功能更加強大且更加靈活的Pytest框架怎麼可能沒有資料驅動的概念呢?其實Pytest是使用@pytest.mark.parametrize裝飾器來實現資料驅動測試的,那麼今天我們就簡單來說說在它是如何進行資料驅動測試的

單個引數

"""
------------------------------------
@Time : 2019/7/25 19:18
@Auth : linux超
@File : test_parametrize.py
@IDE  : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ   : [email protected]
@GROUP: 878565760
------------------------------------
"""
import pytest

data = [1, 2]


@pytest.mark.parametrize('a', data)
def test_parametrize(a):
    print('\n被載入測試資料為\n{}'.format(a))


if __name__ == '__main__':
    pytest.main(['-s'])

輸出

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\CnblogCode\pytest_parametrize, inifile:
plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
collected 2 items

test_parametrize.py 
被載入測試資料為
1
.
被載入測試資料為
2
.

========================== 2 passed in 0.16 seconds ===========================

Process finished with exit code 0

說明

如果測試用例只需要一個引數時,我們存放資料的列表無序巢狀序列,@pytest.mark.parametrize('a', data)裝飾器的第一個引數也只需要一個變數接收列表中的每個元素,第二個引數傳遞儲存資料的列表,那麼測試用例需要使用同名的字串接收測試資料(例項中的a)且列表有多少個元素就會生成並執行多少個測試用例

一組資料

"""
------------------------------------
@Time : 2019/7/25 19:18
@Auth : linux超
@File : test_parametrize.py
@IDE  : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ   : [email protected]
@GROUP: 878565760
------------------------------------
"""
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):  # 一個引數接收一個數據
    print('\n測試資料為\n{},{},{}'.format(a, b, expect))
    actual = a + b
    assert actual == expect


@pytest.mark.parametrize('value', data)
def test_parametrize_2(value):  # 一個引數接收一組資料
    print('\n測試資料為\n{}'.format(value))
    actual = value[0] + value[1]
    assert actual == value[2]


if __name__ == '__main__':
    pytest.main(['-s'])

輸出

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\CnblogCode\pytest_parametrize, inifile:
plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
collected 4 items

test_parametrize.py 
測試資料為
1,2,3
.
測試資料為
4,5,9
.
測試資料為
[1, 2, 3]
.
測試資料為
[4, 5, 9]
.

========================== 4 passed in 0.17 seconds ===========================

Process finished with exit code 0

說明

當測試用例需要多個引數時,需要使用巢狀序列(巢狀元組&巢狀列表)的列表來存放測試資料

裝飾器@pytest.mark.parametrize()可以使用單個變數接收資料,也可以使用多個變數接收,同樣,測試用例函式也需要與其保持一致

當使用單個變數接收時,測試資料傳遞到測試函式內部時為列表中的每一個元素或者小列表,需要使用索引的方式取得每個資料

當使用多個變數接收資料時,那麼每個變數分別接收小列表或元組中的每個元素

列表巢狀多少個多組小列表或元組,測生成多少條測試用例

圖解對應關係

組合資料

"""
------------------------------------
@Time : 2019/7/25 19:18
@Auth : linux超
@File : test_parametrize.py
@IDE  : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ   : [email protected]
@GROUP: 878565760
------------------------------------
"""
import pytest

data_1 = [1, 2]  
data_2 = [3, 4]  


@pytest.mark.parametrize('a', data_1)
@pytest.mark.parametrize('b', data_2)
def test_parametrize_1(a, b):
    print('\n測試資料為\n{},{}'.format(a, b))


if __name__ == '__main__':
    pytest.main(['-s'])

輸出

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\CnblogCode\pytest_parametrize, inifile:
plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
collected 4 items

test_parametrize.py 
測試資料為
1,3
.
測試資料為
2,3
.
測試資料為
1,4
.
測試資料為
2,4
.

========================== 4 passed in 0.24 seconds ===========================

Process finished with exit code 0

說明

通過測試結果,我們發現執行了4條測試用例。不難分析原因是第一組資料的每個資料分別和第二組資料的每個資料結合的結果

標記用例

可以直接標記測試用例,引數化裝飾器也可以識別(標記用例失敗或跳過)

標記為無條件跳過(標記為失敗為xfail,自己嘗試)

"""
------------------------------------
@Time : 2019/7/25 19:18
@Auth : linux超
@File : test_parametrize.py
@IDE  : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ   : [email protected]
@GROUP: 878565760
------------------------------------
"""
import pytest

data_1 = [
    [1, 2, 3],
    pytest.param(3, 4, 8, marks=pytest.mark.skip)
]


def add(a, b):
    return a + b


@pytest.mark.parametrize('a, b, expect', data_1)
def test_parametrize_1(a, b, expect):
    print('\n測試資料為\n{},{}'.format(a, b))
    assert add(a, b) == expect


if __name__ == '__main__':
    pytest.main(['-vs'])

輸出

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0 -- C:\Programs\Python\Python37-32\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.7.2', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'pytest': '4.3.1', 'py': '1.8.0', 'pluggy': '0.9.0'}, 'Plugins': {'rerunfailures': '7.0', 'metadata': '1.8.0', 'html': '1.20.0'}, 'JAVA_HOME': 'D:\\JDK'}
rootdir: E:\CnblogCode\pytest_parametrize, inifile:
plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
collecting ... collected 2 items

test_parametrize.py::test_parametrize_1[1-2-3] 
測試資料為
1,2
PASSED
test_parametrize.py::test_parametrize_1[3-4-8] SKIPPED

===================== 1 passed, 1 skipped in 0.17 seconds =====================

Process finished with exit code 0

說明

輸出結果顯示收集到2個用例,一個通過,一個被跳過,當我們不想執行某組測試資料時,我們可以標記skip或skipif;當我們預期某組資料會執行失敗時,我們可以標記為xfail等

總結

Pytest中實現資料驅動就是如此了

需要注意幾點

1. 裝飾器的第一個引數是一個列表形式的字串引數"a, b, c" 不能寫成"a", "b", "c"

2.測試資料需儲存在序列型別的變數中,當然也可以使用序列巢狀字典型別

補充例項

"""
------------------------------------
@Time : 2019/7/25 19:18
@Auth : linux超
@File : test_parametrize.py
@IDE  : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ   : [email protected]
@GROUP: 878565760
------------------------------------
"""
import pytest

data_1 = (
    {
        'user': 1,
        'pwd': 2
     },
    {
        'user': 3,
        'pwd': 4
    }
)


@pytest.mark.parametrize('dic', data_1)
def test_parametrize_1(dic):
    print('\n測試資料為\n{}'.format(dic))


if __name__ == '__main__':
    pytest.main(['-s'])

輸出

============================= test session starts =============================
platform win32 -- Python 3.7.2, pytest-4.3.1, py-1.8.0, pluggy-0.9.0
rootdir: E:\CnblogCode\pytest_parametrize, inifile:
plugins: rerunfailures-7.0, metadata-1.8.0, html-1.20.0
collected 2 items

test_parametrize.py 
測試資料為
{'user': 1, 'pwd': 2}
.
測試資料為
{'user': 3, 'pwd': 4}
.

========================== 2 passed in 0.20 seconds ===========================

Process finished with exit code 0