書籍來源:房荔枝 梁麗麗《pytest架構與自動化測試應用》
一邊學習一邊整理老師的課程内容及實驗筆記,并與大家分享,侵權即删,謝謝支援!
附上彙總貼:pytest架構進階自學系列 | 彙總_熱愛程式設計的通信人的部落格-CSDN部落格
最多允許失敗的測試用例數
當達到最大上限時,退出執行。如未配置,則沒有上限。
指令pytest -x遇到第一個失敗時,退出執行。
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> pytest -x
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 32 items
test_assert_1.py F
============================================================================================================== FAILURES ===============================================================================================================
______________________________________________________________________________________________________ test_long_str_comparison _______________________________________________________________________________________________________
def test_long_str_comparison():
str3 = 'abcdef'
str4 = 'adcdef'
> assert str3 == str4
E AssertionError: assert 'abcdef' == 'adcdef'
E - adcdef
E ? ^
E + abcdef
E ? ^
test_assert_1.py:4: AssertionError
========================================================================================================== warnings summary ===========================================================================================================
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289: PytestDeprecationWarning: TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.
See https://docs.pytest.org/en/latest/deprecations.html#terminalreporter-writer for more information.
"TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.\n"
-- Docs: https://docs.pytest.org/en/latest/warnings.html
======================================================================================================= short test summary info =======================================================================================================
FAILED test_assert_1.py::test_long_str_comparison - AssertionError: assert 'abcdef' == 'adcdef'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
==================================================================================================== 1 failed, 1 warning in 10.42s ====================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2>
指令pytest --maxfail=2遇到第2個失敗時,退出執行。同理,指令pytest --maxfail=3遇到第3個失敗時退出執行。
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2> pytest -x
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 32 items
test_assert_1.py F
============================================================================================================== FAILURES ===============================================================================================================
______________________________________________________________________________________________________ test_long_str_comparison _______________________________________________________________________________________________________
def test_long_str_comparison():
str3 = 'abcdef'
str4 = 'adcdef'
> assert str3 == str4
E AssertionError: assert 'abcdef' == 'adcdef'
E - adcdef
E ? ^
E + abcdef
E ? ^
test_assert_1.py:4: AssertionError
========================================================================================================== warnings summary ===========================================================================================================
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289
c:\users\guoliang\appdata\local\programs\python\python37\lib\site-packages\_pytest\terminal.py:289: PytestDeprecationWarning: TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.
See https://docs.pytest.org/en/latest/deprecations.html#terminalreporter-writer for more information.
"TerminalReporter.writer attribute is deprecated, use TerminalReporter._tw instead at your own risk.\n"
-- Docs: https://docs.pytest.org/en/latest/warnings.html
======================================================================================================= short test summary info =======================================================================================================
FAILED test_assert_1.py::test_long_str_comparison - AssertionError: assert 'abcdef' == 'adcdef'
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
==================================================================================================== 1 failed, 1 warning in 10.42s ====================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-2>
失敗運作管理的原理
用例運作失敗後,通常希望再次執行失敗的用例,看是環境問題還是腳本問題,是以測試方法運作失敗需被記錄。
這部分内容與第12章緩存目錄設定配置内容相一緻。cacheprovider插件将執行狀态寫入緩存檔案夾,pytest會将本輪測試的執行狀态寫入.pytest_cache檔案夾,這個行為是由自帶的cacheprovider插件實作的。
pytest預設将測試執行的狀态寫入根目錄中的.pytest_cache檔案夾,也可以通過在pytest.ini中配置cache_dir選項來自定義緩存的目錄,它可以是相對路徑,也可以是絕對路徑,相對路徑指的是相對于pytest.ini檔案所在的目錄。
例如,我們想把第12章執行的狀态的緩存和源碼放在一起,該如何實作呢?實作步驟如下。
在src/chapter12/pytest.ini中添加如下配置:
[pytest]
cache_dir = .pytest-cache
這樣,即使在項目的根目錄下執行src/chapter12/中的用例,也隻會在pytest_book/src/chapter12/.pytest_cache中生成緩存,而不是pytest_book/.pytest_cache中。
(1)在chapter12中複制chapter-2中的test_assert_2.py并改名為test_assert_12.py,需要将内容進行适當修改。
(2)在src路徑下執行pytest src/chapter12。
(3)執行狀态未寫在根目錄下,而是寫在測試檔案所在的目錄中(.pytest_cache)。
執行結果如圖所示。
cacheprovider插件實作失敗管理的準備:
(1)在chapter12下建立pytest.ini檔案,代碼如下:
[pytest]
cache_dir = .pytest-cache
(2)在chapter12下建立test_failed.py檔案,代碼如下:
import pytest
@pytest.mark.parametrize('num', [1,2])
def test_failed(num):
assert num == 1
(3)在chapter12下建立test_pass.py檔案,代碼如下:
def test_pass():
assert 1
(4)如果大家是從前到後進行實踐,則需要删除test_assert_12.py和.pytest_cache。
(5)再在根目錄下執行pytest src/chapter12。
(6)chapter12下會自動建立緩存檔案夾及檔案.pytest_cache。
執行結果如下,可以看到一共收集到3個測試用例,其中有一個失敗,另外兩個成功,并且兩個執行成功的用例分屬不同的測試子產品。
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 3 items
chapter-12\test_failed.py .F [ 66%]
chapter-12\test_pass.py . [100%]
============================================================================================================== FAILURES ===============================================================================================================
___________________________________________________________________________________________________________ test_failed[2] ____________________________________________________________________________________________________________
num = 2
@pytest.mark.parametrize('num', [1,2])
def test_failed(num):
> assert num == 1
E assert 2 == 1
chapter-12\test_failed.py:5: AssertionError
======================================================================================================= short test summary info =======================================================================================================
FAILED chapter-12\test_failed.py::test_failed[2] - assert 2 == 1
===================================================================================================== 1 failed, 2 passed in 0.30s =====================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
同時,pytest也在src/chapter12/目錄下生成緩存檔案夾(.pytest_cache)。
具體介紹一下cacheprovider插件的功能。
--lf,--last-failed:隻執行上一輪失敗的用例。
緩存中的lastfailed檔案記錄了上次失敗的用例ID,可以通過--cache-show指令檢視它的内容。
--cache-show指令是cacheprovider提供的新功能,它不會導緻任何用例的執行。
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\ -q --cache-show 'lastfailed'
cachedir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12\.pytest-cache
---------------------------------------------------------------------------------------------------- cache values for 'lastfailed' ----------------------------------------------------------------------------------------------------
cache\lastfailed contains:
{'test_failed.py::test_failed[2]': True}
no tests ran in 0.00s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
可以看到,它記錄了一個用例,此用例為上次失敗的測試用例的ID:test_failed.py::test_failed[2]。
下次執行,當使用--lf選項時,pytest在收集階段隻會選擇這個失敗的用例,而忽略其他的用例。指令pytest --lf --collect-only src/chapter12/中的collect-only選項隻收集用例而不執行。
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --lf --collect-only .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 1 item
<Module test_failed.py>
<Function test_failed[2]>
run-last-failure: rerun previous 1 failure (skipped 1 file)
======================================================================================================== no tests ran in 0.02s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
仔細觀察一下上面的回顯,collecting...<Module test_failed.py>隻收集到test_fail.py檔案中<Function test_failed[2]>,表示第二個執行用例失敗了,需要重新執行(跳過5個檔案)。1deselected(沒有選擇),此處的“沒有選擇”是<Module test_failed.py>中執行通過的第一個用例。跳過5個檔案包括pytest.ini和test_pass.py在内的5個檔案。
實際上,--lf複寫了用例收集階段的兩個鈎子方法:pytest_ignore_collect(path,config)和pytest_collection_modifyitems(session,config,items)。
--ff,--failed-first:先執行上一輪失敗的用例,再執行其他的用例。
先通過實踐看一看這個指令的效果,再去分析它的實作,指令如下:
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --collect-only -s --ff .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 3 items
<Module test_failed.py>
<Function test_failed[2]>
<Function test_failed[1]>
<Module test_pass.py>
<Function test_pass>
run-last-failure: rerun previous 1 failure first
======================================================================================================== no tests ran in 0.02s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
可以看到一共收集到3個測試用例,和正常所收集到的測試用例的順序相比,上一輪失敗的test_failed.py::test_failed[2]用例在最前面,将優先執行。
實際上,-ff隻複寫了鈎子方法:pytest_collection_modifyitems(session,config,items),它可以過濾或者重新排序所收集到的用例。
--nf,--new-first:先執行新加的或修改的用例,再執行其他的用例。
緩存中的nodeids檔案記錄了上一輪執行的所有用例,指令如下:
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest .\chapter-12\ --cache-show 'nodeids'
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
cachedir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12\.pytest-cache
----------------------------------------------------------------------------------------------------- cache values for 'nodeids' ------------------------------------------------------------------------------------------------------
cache\nodeids contains:
['test_failed.py::test_failed[1]',
'test_failed.py::test_failed[2]',
'test_pass.py::test_pass']
======================================================================================================== no tests ran in 0.01s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
從執行結果可以看到上一輪共執行了3個測試用例。
現在可以在test_pass.py中新加一個用例,并修改一下test_failed.py檔案中的用例(但是不添加新用例)。
代碼如下:
def test_pass():
assert 1
def test_new_pass():
assert 1
再來執行一下收集指令,指令如下:
執行結果如下:
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --collect-only -s --nf .\chapter-12\
========================================================================================================= test session starts =========================================================================================================
platform win32 -- Python 3.7.7, pytest-5.4.1, py-1.11.0, pluggy-0.13.1
cachedir: .pytest-cache
rootdir: D:\SynologyDrive\CodeLearning\WIN\pytest-book\src\chapter-12, inifile: pytest.ini
plugins: allure-pytest-2.13.2
collected 4 items
<Module test_pass.py>
<Function test_new_pass>
<Function test_pass>
<Module test_failed.py>
<Function test_failed[1]>
<Function test_failed[2]>
======================================================================================================== no tests ran in 0.48s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
可以看到,新加的用例排在最前面,其次修改過的測試用例緊接其後,最後才是舊的用例,這個行為在源碼中有所展現。
--cache-clear:先清除所有緩存,再執行用例。
如果上一輪沒有失敗的用例,則需要先清除緩存,再執行test_pass.py子產品(它的用例都是能測試成功的)。
執行及結果如下:
======================================================================================================== no tests ran in 0.48s ========================================================================================================
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src> pytest --cache-clear -q -s .\chapter-12\test_pass.py
..
2 passed in 0.01s
PS D:\SynologyDrive\CodeLearning\WIN\pytest-book\src>
其結果是不是少了點什麼呢?對!因為沒有失敗的用例,是以不會生成lastfailed檔案,那麼這個時候再使用--lf和--ff會發生什麼呢?我們來試試。
注意:如果我們觀察得足夠仔細,就會發現現在的緩存目錄和之前相比不僅少了lastfailed檔案,還少了CACHEDIR.TAG、.gitignore和README.md這3個檔案。這是一個Bug,現在pytest的版本是5.2.1,預計會在之後的版本得到修複。