Pytest自動(dòng)化測(cè)試-簡易入門教程


一、簡介
pytest是動(dòng)態(tài)編程語言Python專用的測(cè)試框架,它具有易于上手、功能強(qiáng)大、可擴(kuò)展性好、兼容性強(qiáng)、效率高、第三方插件豐富等特點(diǎn)。
功能特征
完整的文檔,包括安裝,教程和PDF文檔
簡單而又詳細(xì)的斷言模式(使用純assert語句)
自動(dòng)發(fā)現(xiàn)測(cè)試模塊和功能(以test為標(biāo)識(shí))
可以運(yùn)行unittest和nose框架的測(cè)試用例
靈活的固件,用于管理小型或參數(shù)化的長期測(cè)試資源
豐富的插件架構(gòu),擁有三百多個(gè)外部插件和豐富的社區(qū)
編寫規(guī)則
測(cè)試文件以test_開頭(以_test結(jié)尾也可以)
測(cè)試類以Test開頭,并且不能帶有 init 方法
測(cè)試函數(shù)以test_開頭
斷言使用基本的assert即可
自動(dòng)發(fā)現(xiàn)規(guī)則:
如果未指定任何參數(shù),則從testpaths(如果已配置)或當(dāng)前目錄開始收集。
另外,命令行參數(shù)可以在目錄、文件名或節(jié)點(diǎn)ID的任何組合中使用。
在這些目錄中,搜索包含 test_*.py 或 *_test.py 的測(cè)試文件。
從這些文件中,收集以test前綴的測(cè)試方法,或者在Test前綴的測(cè)試類(無__init__方法)中的以test前綴的測(cè)試方法。
官方文檔:https://docs.pytest.org/en/latest/contents.html
二、安裝
打開bash命令行,運(yùn)行以下命令:
pip install?-U pytest檢查是否安裝了正確的版本:
$?pytest --version
pytest 6.1.2三、示例
創(chuàng)建一個(gè)簡單的測(cè)試函數(shù):
# test_sample.py
# 被測(cè)功能
def?func(x):
????return?x + 1
# 測(cè)試成功
def?test_pass():
????assert?func(3) == 4
# 測(cè)試失敗
def?test_fail():
????assert?func(3) == 5現(xiàn)在開始執(zhí)行測(cè)試功能:
E:\workspace-py\Pytest>pytest
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items
test_sample.py .F [100%]
=============================================================================== FAILURES ================================================================================
_______________________________________________________________________________ test_fail _______________________________________________________________________________
????def?test_fail():
> assert?func(3) == 5
E assert?4?== 5
E + where 4?= func(3)
test_sample.py:16: AssertionError
======================================================================== short test summary info ========================================================================
FAILED test_sample.py::test_fail - assert?4?== 5
====================================================================== 1?failed, 1?passed in?0.16s ======================================================================這里未指定測(cè)試用例,pytest將依據(jù)自動(dòng)發(fā)現(xiàn)規(guī)則檢索并執(zhí)行測(cè)試,等同于 pytest ./test_sample.py
pytest 使用 . 標(biāo)識(shí)測(cè)試成功(PASSED)
pytest 使用 F 標(biāo)識(shí)測(cè)試失敗(FAILED)
可以使用 -v 選項(xiàng),顯示測(cè)試的詳細(xì)信息
可以使用 -h 查看 pytest 的所有選項(xiàng)
四、標(biāo)記
默認(rèn)情況下,pytest 會(huì)遞歸查找當(dāng)前目錄下所有以 test 開始或結(jié)尾的 Python 腳本,并執(zhí)行文件內(nèi)的所有以 test 開始或結(jié)束的函數(shù)和方法。
1、如果你想指定運(yùn)行測(cè)試用例,可以通過 :: 顯式標(biāo)記(文件名:: 類名::方法名)。
E:\workspace-py\Pytest>pytest test_sample.py::test_pass
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 1?item
test_sample.py . [100%]
=========================================================================== 1?passed in?0.05s ===========================================================================2、如果你想選擇一些測(cè)試用例,可以使用 -k 模糊匹配。
E:\workspace-py\Pytest>pytest -k pass?test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items / 1?deselected / 1?selected
test_sample.py . [100%]
==================================================================== 1?passed, 1?deselected in?0.02s ====================================================================3、如果你想跳過個(gè)別測(cè)試用例,可以使用 pytest.mark.skip(),或者 pytest.mark.skipif(條件表達(dá)式)。
# 測(cè)試失敗
@pytest.mark.skip()
def?test_fail():
????assert?func(3) == 5E:\workspace-py\Pytest>pytest -v test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0?-- c:\python37\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.7.3', 'Platform': 'Windows-7-6.1.7601-SP1', 'Packages': {'pytest': '6.0.2', 'py': '1.9.0', 'pluggy': '0.13.0'}, 'Plugins': {'allure-pytest': '2.8.
18', 'cov': '2.10.1', 'html': '2.1.1', 'metadata': '1.8.0', 'rerunfailures': '9.1', 'xdist': '2.1.0'}}
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items
test_sample.py::test_pass PASSED [ 50%]
test_sample.py::test_fail SKIPPED [100%]
===================================================================== 1?passed, 1?skipped in?0.07s ======================================================================4、如果你想捕捉一些異常,可以使用pytest.raises()。
# test_raises.py
def?test_raises():
????with?pytest.raises(TypeError) as?e:
????????connect('localhost', '6379')
????exec_msg = e.value.args[0]
????assert?exec_msg == 'port type must be int'5、如果你事先知道測(cè)試函數(shù)會(huì)執(zhí)行失敗,但又不想直接跳過,而是希望顯示的提示,可以使用pytest.mark.xfail()。
# 測(cè)試失敗
@pytest.mark.xfail()
def?test_fail():
????assert?func(3) == 56、如果你想對(duì)某個(gè)測(cè)試點(diǎn)進(jìn)行多組數(shù)據(jù)測(cè)試,可以使用 pytest.mark.parametrize(argnames, argvalues) 參數(shù)化測(cè)試,即每組參數(shù)都獨(dú)立執(zhí)行一次測(cè)試。
注意:以往我們可以把這些參數(shù)寫在測(cè)試函數(shù)內(nèi)部進(jìn)行遍歷,但是當(dāng)某組參數(shù)導(dǎo)致斷言失敗,測(cè)試則就終止了。
# 測(cè)試成功
@pytest.mark.parametrize('data', [1, 2, 3])
def?test_pass(data):
????assert?func(data) == 4E:\workspace-py\Pytest>pytest -k pass?test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 4?items / 1?deselected / 3?selected
test_sample.py FF. [100%]
=============================================================================== FAILURES ================================================================================
_____________________________________________________________________________ test_pass[1] ______________________________________________________________________________
data = 1
[email protected]('data', [1, 2, 3])
????def?test_pass(data):
> assert?func(data) == 4
E assert?2?== 4
E + where 2?= func(1)
test_sample.py:11: AssertionError
_____________________________________________________________________________ test_pass[2] ______________________________________________________________________________
data = 2
[email protected]('data', [1, 2, 3])
????def?test_pass(data):
> assert?func(data) == 4
E assert?3?== 4
E + where 3?= func(2)
test_sample.py:11: AssertionError
======================================================================== short test summary info ========================================================================
FAILED test_sample.py::test_pass[1] - assert?2?== 4
FAILED test_sample.py::test_pass[2] - assert?3?== 4
=============================================================== 2?failed, 1?passed, 1?deselected in?0.17s ===============================================================五、固件
固件(Fixture)是一些函數(shù),pytest 會(huì)在執(zhí)行測(cè)試函數(shù)之前(或之后)加載運(yùn)行它們。
我們可以利用固件做任何事情,其中最常見的可能就是數(shù)據(jù)庫的初始連接和最后關(guān)閉操作。
1、Pytest使用pytest.fixture()定義固件,為了在實(shí)際工程中可以更大程度上復(fù)用,我們更多的是使用文件conftest.py集中管理固件(pytest會(huì)自動(dòng)調(diào)用)。
# conftest.py
import?pytest
@pytest.fixture()
def?data():
????return?3# 測(cè)試成功
def?test_pass(data):
????assert?func(data) == 4E:\workspace-py\Pytest>pytest -k pass?test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items / 1?deselected / 1?selected
test_sample.py . [100%]
==================================================================== 1?passed, 1?deselected in?0.05s ====================================================================2、Pytest 使用 yield 關(guān)鍵詞將固件分為兩部分,yield 之前的代碼屬于預(yù)處理,會(huì)在測(cè)試前執(zhí)行;yield 之后的代碼屬于后處理,將在測(cè)試完成后執(zhí)行。
# conftest.py
import?pytest
@pytest.fixture()
def?db():
????print('opened')
????yield
????print('closed')# 測(cè)試成功
def?test_pass(db):
????assert?func(3) == 4E:\workspace-py\Pytest>pytest -s -k pass?test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items / 1?deselected / 1?selected
test_sample.py opened
.closed
==================================================================== 1?passed, 1?deselected in?0.02s ====================================================================3、為了更精細(xì)化控制固件,pytest使用作用域來進(jìn)行指定固件的使用范圍。
在定義固件時(shí),通過 scope 參數(shù)聲明作用域,可選項(xiàng)有:
function: 函數(shù)級(jí),每個(gè)測(cè)試函數(shù)都會(huì)執(zhí)行一次固件(默認(rèn)值);
class: 類級(jí)別,每個(gè)測(cè)試類執(zhí)行一次,所有方法都可以使用;
module: 模塊級(jí),每個(gè)模塊執(zhí)行一次,模塊內(nèi)函數(shù)和方法都可使用;
session: 會(huì)話級(jí),一次測(cè)試只執(zhí)行一次,所有被找到的函數(shù)和方法都可用。
# conftest.py
import?pytest
@pytest.fixture(scope='function', autouse=True)
def?func_scope():
????pass
@pytest.fixture(scope='module', autouse=True)
def?mod_scope():
????pass
@pytest.fixture(scope='session')
def?sess_scope():
????pass
@pytest.fixture(scope='class')
def?class_scope():
????pass# 測(cè)試成功
? @pytest.mark.usefixtures('sess_scope')
? def?test_pass(class_scope):
? ? ? assert?func(3) == 4E:\workspace-py\Pytest>pytest --setup-show -k pass?test_sample.py
========================================================================== test session starts ==========================================================================
platform win32 -- Python 3.7.3, pytest-6.0.2, py-1.9.0, pluggy-0.13.0
rootdir: E:\workspace-py\Pytest
plugins: allure-pytest-2.8.18, cov-2.10.1, html-2.1.1, metadata-1.8.0, rerunfailures-9.1, xdist-2.1.0
collected 2?items / 1?deselected / 1?selected
test_sample.py
SETUP S sess_scope
????SETUP M mod_scope
??????SETUP C class_scope
????????SETUP F func_scope
????????test_sample.py::test_pass (fixtures used: class_scope, func_scope, mod_scope, sess_scope).
????????TEARDOWN F func_scope
??????TEARDOWN C class_scope
????TEARDOWN M mod_scope
TEARDOWN S sess_scope
==================================================================== 1?passed, 1?deselected in?0.02s ====================================================================我們可以把固件作為入?yún)ⅲ€可以使用@pytest.mark.usefixtures('class_scope'),或者指定autouse參數(shù)讓固件自動(dòng)執(zhí)行。
并且還可以指定params參數(shù)來實(shí)現(xiàn)固件的參數(shù)化,以及指定name參數(shù)來修改固件名。
可以使用 -s 選項(xiàng),顯示print打印信息
可以使用 --setuo-show 選項(xiàng),顯示詳細(xì)的固件信息
4、內(nèi)置固件:
tmpdir & tmpdir_factory:用于臨時(shí)文件和目錄管理,默認(rèn)會(huì)在測(cè)試結(jié)束時(shí)刪除。
pytestconfig:用于讀取命令行參數(shù)和配置文件
capsys:用于捕獲 stdout 和 stderr 的內(nèi)容,并臨時(shí)關(guān)閉系統(tǒng)輸出。
monkeypath:用于運(yùn)行時(shí)動(dòng)態(tài)修改類或模塊。
recwarn:用于捕獲程序中 warnings 產(chǎn)生的警告。
?Pytest學(xué)習(xí)手冊(cè):https://learning-pytest.readthedocs.io/zh/latest/index.html

往期推薦



以上三位小伙伴,快來聯(lián)系小編領(lǐng)取小小紅包一份哦!小編微信:Mayyy530

