書籍來源:房荔枝 梁麗麗《pytest架構與自動化測試應用》
一邊學習一邊整理老師的課程内容及實驗筆記,并與大家分享,侵權即删,謝謝支援!
附上彙總貼:pytest架構進階自學系列 | 彙總_熱愛程式設計的通信人的部落格-CSDN部落格
在大型測試中,可能需要在本地覆寫項目級别的fixture,以增加可讀性和可維護性。也就是說可以通過在不同層級中重寫fixture改變fixture中原始的内容。思路是重寫同名(檔案或函數)的方法。使用時優先調用重寫後的fixture。
在檔案夾(conftest.py)層級重寫fixture
下一層的conftest.py中的fixtures可以覆寫和通路上一級的fixture,實作過程:
- 在不同層次建立檔案夾
建立tests檔案夾,以及子檔案夾subfolder。在tests檔案夾下面建立conftest.py檔案和test_something.py兩個檔案,在subfolder下同樣建立這兩個檔案。
- 各個檔案的代碼
在tests檔案夾下的conftest.py檔案的fixture中建立username方法。
import pytest
@pytest.fixture
def username():
return 'username'
在tests檔案夾下的test_something.py檔案中建立test_username方法,通過斷言判斷傳入的是否為username方法所傳回的username字元串。
def test_username(username):
assert username == 'username'
在subfolder檔案夾下的conftest.py檔案的fixture中建立的username方法中調用username,也就是通過這個參數調用上一級conftest.py中username的fixture。通過同名的方法重寫上一級的同名fixture方法。
import pytest
@pytest.fixture
def username(username):
return 'overridden-' + username
在subfolder檔案夾下test_something.py檔案的test_username測試方法中調用username,這時調用本地的方法,也就是subfolder檔案夾下的conftest.py檔案的username方法中重寫上一級的usename方法,并通過斷言測試是否是本地重寫的結果。
def test_username(username):
assert username == 'overridden-username'
執行結果如下:
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 11:53 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests
============================= 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_something.py::test_username PASSED [ 50%]
subfolder\test_something.py::test_username PASSED [100%]
============================== 2 passed in 0.02s ==============================
Process finished with exit code 0
子檔案夾(subfolder)中conftest.py檔案的fixture覆寫了上層檔案夾中同名的fixture。
子檔案夾(subfolder)中conftest.py檔案的fixture可以輕松地通路上層檔案夾中同名的fixture。
在子產品層級重寫fixture
在conftest.py及自己同一檔案下的fixture具有相同名字,由在同一檔案中的fixture函數重寫了conftest.py中的fixture函數。也就是說子產品(檔案中)中的fixture覆寫了conftest.py中同名的fixture。子產品(檔案)中的fixture可以輕松地通路conftest.py中同名的fixture。
代碼如下:
// test/test_something.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-' + username
def test_username(username):
assert username == 'overridden-username'
// test/test_something_else.py
import pytest
@pytest.fixture
def username(username):
return 'overridden-else-' + username
def test_username(username):
assert username == 'overridden-else-username'
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:02 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests
============================= 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 3 items
test_something.py::test_username PASSED [ 33%]
test_something_else.py::test_username PASSED [ 66%]
subfolder\test_something.py::test_username PASSED [100%]
============================== 3 passed in 0.04s ==============================
Process finished with exit code 0
在用例參數中重寫fixture
常用的使用場景:fixture通常作為測試資料的初始化,而參數化是調用這些資料實作一個測試方法使用不同資料執行多次的效果。在fixture與參數parametrize組合在一起時,在fixture中讀到的原始值可以被用例的參數parametrize所覆寫,這可展現資料層級的靈活性。
代碼如下:
// test/conftest.py
import pytest
@pytest.fixture
def username():
return 'username'
@pytest.fixture
def other_username(username):
return 'other-' + username
// test/test_something.py
import pytest
@pytest.mark.parametrize('username', ['directly-overridden-username'])
def test_username(username):
assert username == 'directly-overridden-username'
@pytest.mark.parametrize('username', ['directly-overridden-username-other'])
def test_username_other(username, other_username):
assert other_username == 'other-directly-overridden-username-other'
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:09 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests
============================= 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_something.py::test_username[directly-overridden-username] PASSED [ 25%]
test_something.py::test_username_other[directly-overridden-username-other] PASSED [ 50%]
test_something_else.py::test_username PASSED [ 75%]
subfolder\test_something.py::test_username PASSED [100%]
============================== 4 passed in 0.03s ==============================
Process finished with exit code 0
fixture的值被用例的參數所覆寫,盡管用例test_username_other沒有使用username,但是other_username使用了username,是以也同樣受到了影響。
參數化的fixture可重寫非參數化的fixture,反之亦然
參數化的fixture和非參數化的fixture同樣可以互相覆寫。其實就是在使用fixture的檔案中建立同名的fixture方法重寫上一級conftest.py檔案中的同名方法。無論重寫前的方法帶參數,還是重寫後的方法帶參數都是可以的。也就是可以實作原來執行多次的方法通過重寫為非參數化的fixture而變成隻執行一次。同樣可以實作原來隻執行一次的方法通過重寫為參數化的fixture而變成執行多次的參數化fixture。
代碼如下:
import pytest
@pytest.fixture
def username():
return 'username'
@pytest.fixture
def other_username(username):
return 'other-' + username
@pytest.fixture(params=['one', 'two', 'three'])
def parametrized_username(request):
return request.param
@pytest.fixture
def non_parametrized_username(request):
return 'username'
在test_something1.py檔案中,建立與conftest.py檔案中同名的parametrized_username方法,重寫為隻傳回一個值的非參數化方法。建立與conftest.py檔案中同名的non_parametrized_username方法,添加參數及傳回值,重寫為參數化的方法。
import pytest
@pytest.fixture
def parametrized_username():
return 'overridden-username'
@pytest.fixture(params=['one', 'two', 'three'])
def non_parametrized_username(request):
return request.param
def test_username(parametrized_username):
assert parametrized_username == 'overridden-username'
def test_parametrized_username(non_parametrized_username):
assert non_parametrized_username in ['one', 'two', 'three']
在test_something_else1.py方法中不需要重寫,正常調用conftest.py檔案中的fixture。
def test_username(parametrized_username):
assert parametrized_username in ['one','two','three']
def test_username1(non_parametrized_username):
assert non_parametrized_username == 'username'
D:\SynologyDrive\CodeLearning\WIN\pytest-book\venv\Scripts\python.exe "C:\Program Files\JetBrains\PyCharm Community Edition 2022.1.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py" --path D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests
Testing started at 12:19 ...
Launching pytest with arguments D:/SynologyDrive/CodeLearning/WIN/pytest-book/src/chapter-3/tests in D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-3\tests
============================= 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 12 items
test_something.py::test_username[directly-overridden-username] PASSED [ 8%]
test_something.py::test_username_other[directly-overridden-username-other] PASSED [ 16%]
test_something1.py::test_username PASSED [ 25%]
test_something1.py::test_parametrized_username[one] PASSED [ 33%]
test_something1.py::test_parametrized_username[two] PASSED [ 41%]
test_something1.py::test_parametrized_username[three] PASSED [ 50%]
test_something_else.py::test_username PASSED [ 58%]
test_something_else1.py::test_username[one] PASSED [ 66%]
test_something_else1.py::test_username[two] PASSED [ 75%]
test_something_else1.py::test_username[three] PASSED [ 83%]
test_something_else1.py::test_username1 PASSED [ 91%]
subfolder\test_something.py::test_username PASSED [100%]
============================= 12 passed in 0.07s ==============================
Process finished with exit code 0