書籍來源:房荔枝 梁麗麗《pytest架構與自動化測試應用》
一邊學習一邊整理老師的課程内容及實驗筆記,并與大家分享,侵權即删,謝謝支援!
附上彙總貼:pytest架構進階自學系列 | 彙總_熱愛程式設計的通信人的部落格-CSDN部落格
fixture(scope="function",params=None,autouse=False,ids=None,name=None),params是參數,預設可以不選。
如果需要在一系列測試用例的執行中,每輪執行都使用同一個fixture,但是有不同的依賴場景,則可以考慮對fixture進行參數化,這種方式适用于對多場景的功能子產品進行詳盡測試。
可以通過指定params關鍵字參數建立兩個fixture執行個體,每個執行個體供一輪測試使用,所有的測試用例執行兩遍,在fixture的聲明函數中,可以使用request.param擷取目前使用的入參。
測試方法使用兩個簡單測試資料
每次執行應使用不同資料,一次應使用一個。可以通過fixture自帶的params準備不同的資料。下面是一個測試方法使用2個簡單測試資料。
代碼如下:
import pytest
@pytest.fixture(params=['apple', 'banana'])
def fruit(request):
return request.param
def test_fruit(fruit):
print("\n筆者今天吃{}".format(fruit))
assert True
def test_cook_fruit(fruit):
print("筆者今天做{}派。".format(fruit))
assert True
執行結果如下所示:
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.py
Testing started at 14:11 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3
============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 4 items
test_fixture_params.py::test_fruit[apple] PASSED [ 25%]
筆者今天吃apple
test_fixture_params.py::test_fruit[banana] PASSED [ 50%]
筆者今天吃banana
test_fixture_params.py::test_cook_fruit[apple] PASSED [ 75%]筆者今天做apple派。
test_fixture_params.py::test_cook_fruit[banana] PASSED [100%]筆者今天做banana派。
============================== 4 passed in 0.04s ==============================
Process finished with exit code 0
二(多)個測試方法共用兩個簡單測試資料
在代碼中增加下述代碼,實作多個測試使用一組不同資料:
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.py
Testing started at 14:11 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3
============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 4 items
test_fixture_params.py::test_fruit[apple] PASSED [ 25%]
筆者今天吃apple
test_fixture_params.py::test_fruit[banana] PASSED [ 50%]
筆者今天吃banana
test_fixture_params.py::test_cook_fruit[apple] PASSED [ 75%]筆者今天做apple派。
test_fixture_params.py::test_cook_fruit[banana] PASSED [100%]筆者今天做banana派。
============================== 4 passed in 0.04s ==============================
Process finished with exit code 0
有效測試資料與預期失敗xfail的測試資料
在測試某些功能時,如果步驟一緻,則可以使用資料驅動方式執行測試,也就是說多組資料使用一個測試方法。通常正确有效的資料分得一個測試方法,因為錯誤的步驟通常簡單,而正确的步驟會多些,必須分開驗證,但當步驟相同而資料不同時,預期失敗和預期正确的資料可以在一個測試方法中實作。這樣就隻有一組或幾組資料會引起預期的失敗,但不能在測試方法中标記預期失敗,而應該在通過參數傳遞的測試資料中使用pytest.param标記預期失敗。
代碼如下:
import pytest
@pytest.fixture(params=[('3+5', 8), pytest.param(('6*9', 42), marks=pytest.mark.xfail, ids='failed')])
def data_set(request):
return request.param
def test_data(data_set):
assert eval(data_set[0]) == data_set[1]
在data_set方法中使用request傳遞fixture中的參數,使用request.param解析每個參數。在方法上面加上pytest.fixture裝飾器,通過參數傳遞不同的測試資料。一組是正确的,3+5和8比對,另一組将6*9和42比對,并且在test_data中通過data_set的依賴注入的方式傳入資料,通過eval方法将表達式,例如3+5從字元串轉換成可執行的算式,計算的結果與傳遞參數的第二列data_set[1]資料比對是否相等。
最重要的是第二組資料預期結果不正确,通過marks标記成失敗pytest.mark.xfail,并用ids顯示出failed。
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_param_marks.py
Testing started at 14:19 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_param_marks.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3
============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 2 items
test_fixture_param_marks.py::test_data[data_set0]
test_fixture_param_marks.py::test_data[failed]
======================== 1 passed, 1 xfailed in 0.08s =========================
Process finished with exit code 0
PASSED [ 50%]XFAIL [100%]
data_set = ('6*9', 42)
def test_data(data_set):
> assert eval(data_set[0]) == data_set[1]
E assert 54 == 42
E +54
E -42
test_fixture_param_marks.py:8: AssertionError
params與ids的應用
對于複雜類型的測試資料通常加上id或name來表明資料的含義,并标記測試要點。測試資料除了字元串以外,還可以是表達式,以及元組、字典、類等類型。使用ids關鍵字參數,自定義測試ID。
代碼如下:
import pytest
@pytest.fixture(params=[0, 'a'], ids=['number', 'charactor'])
def a(request):
return request.param
def test_a(a):
print(a)
pass
def idfn(fixture_value):
if fixture_value == 0:
return "eggs"
elif fixture_value == 1:
return False
elif fixture_value == 2:
return None
else:
return fixture_value
@pytest.fixture(params=[0,1,2,3], ids=idfn)
def b(request):
return request.param
def test_b(b):
print(b)
pass
class C:
pass
@pytest.fixture(params=[(1,2), {'d':1}, C()])
def c(request):
return request.param
def test_c(c):
print(c)
pass
ids=idfn,idfn是前面使用的方法,在fixture中将params的每個資料傳入idfn,ids的值就是其傳回值。當params=0時,傳回值eggs;當params=1時,傳回值False;當params=2時,傳回值None,ids顯示params的值;當params=3時,傳回值直接顯示為3。
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:/Program Files/JetBrains/PyCharm Community Edition 2022.3.2/plugins/python-ce/helpers/pycharm/_jb_pytest_runner.py" --path D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params_ids.py
Testing started at 14:24 ...
Launching pytest with arguments D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\test_fixture_params_ids.py in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3
============================= test session starts =============================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
collecting ... collected 9 items
test_fixture_params_ids.py::test_a[number] PASSED [ 11%]0
test_fixture_params_ids.py::test_a[charactor] PASSED [ 22%]a
test_fixture_params_ids.py::test_b[eggs] PASSED [ 33%]0
test_fixture_params_ids.py::test_b[False] PASSED [ 44%]1
test_fixture_params_ids.py::test_b[2] PASSED [ 55%]2
test_fixture_params_ids.py::test_b[3] PASSED [ 66%]3
test_fixture_params_ids.py::test_c[c0] PASSED [ 77%](1, 2)
test_fixture_params_ids.py::test_c[c1] PASSED [ 88%]{'d': 1}
test_fixture_params_ids.py::test_c[c2] PASSED [100%]<test_fixture_params_ids.C object at 0x0000023D0F1A5388>
============================== 9 passed in 0.09s ==============================
Process finished with exit code 0
從執行結果可以看出:ids可以接收一個函數,用于生成測試ID。當測試ID指定為None時,使用的是params原先對應的值。
注意:當測試params中包含元組、字典或者對象時,測試ID使用的是fixture函數名+param的下标。
如果使用CLI終端執行,則結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3> pytest -s -v .\test_fixture_params_ids.py
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1 -- c:\users\guoliang\appdata\local\programs\python\python37\python.exe
cachedir: .pytest_cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book
plugins: allure-pytest-2.13.2
collected 9 items
test_fixture_params_ids.py::test_a[number] 0
PASSED
test_fixture_params_ids.py::test_a[charactor] a
PASSED
test_fixture_params_ids.py::test_b[eggs] 0
PASSED
test_fixture_params_ids.py::test_b[False] 1
PASSED
test_fixture_params_ids.py::test_b[2] 2
PASSED
test_fixture_params_ids.py::test_b[3] 3
PASSED
test_fixture_params_ids.py::test_c[c0] (1, 2)
PASSED
test_fixture_params_ids.py::test_c[c1] {'d': 1}
PASSED
test_fixture_params_ids.py::test_c[c2] <test_fixture_params_ids.C object at 0x0000022B6155BF48>
PASSED
========================================================================================================== 9 passed in 0.03s ==========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3>
params綜合執行個體
這個測試用例使用不同的SMTP伺服器,共執行了3次。在參數化的fixture中,pytest為每個fixture執行個體自動指定一個測試ID。
import pytest
import smtplib
@pytest.fixture(scope='module', params=['smtp.163.com', 'smtp.126.com', 'mail.python.org'])
def smtp_connection_params(request):
server = request.param
with smtplib.SMTP(server, 587, timeout=5) as smtp_connection:
yield smtp_connection
def test_parames(smtp_connection_params):
response, _ = smtp_connection_params.ehlo()
assert response == 250
可以看到執行顯示的ID是test_parames[smtp.163.com]、test_parames[smtp.126.com]、test_parames[mail.python.org]。
圖3-10 param的綜合執行個體
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3> pytest -q -s --collect-only .\test_request.py
src/chapter-3/test_request.py::test_parames[smtp.163.com]
src/chapter-3/test_request.py::test_parames[smtp.126.com]
src/chapter-3/test_request.py::test_parames[mail.python.org]
no tests ran in 0.01s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3>