Pytest安裝與配置
和Unittest一樣,Pytest是另一個Python語言的單元測試框架,與Unittest相比它的測試用例更加容易編寫、運行方式更加靈活、報錯信息更加清晰、斷言寫法更簡潔并且它可以運行有unittest和nose編寫的測試用例。
Pytest 安裝
啟動命令行,在命令行中使用pip工具安裝pytest,如圖所示。
C:\Users\Administrator>pip install -U pytest
Collecting pytestUsing cached pytest-5.4.1-py3-none-any.whl (246 kB)
Requirement already satisfied, skipping upgrade: pluggy<1.0,>=0.12 in c:\program files\python38\lib\site-packages (from pytest) (0.13.1)
Requirement already satisfied, skipping upgrade: atomicwrites>=1.0; sys_platform == "win32" in c:\program files\python38\lib\site-packages (from pytest) (1.3.0)
Requirement already satisfied, skipping upgrade: colorama; sys_platform == "win32" in c:\program files\python38\lib\site-packages (from pytest) (0.4.3)
Requirement already satisfied, skipping upgrade: wcwidth in c:\program files\python38\lib\site-packages (from pytest) (0.1.8)
Requirement already satisfied, skipping upgrade: packaging in c:\program files\python38\lib\site-packages (from pytest) (20.3)
Requirement already satisfied, skipping upgrade: attrs>=17.4.0 in c:\program files\python38\lib\site-packages (from pytest) (19.3.0)
Requirement already satisfied, skipping upgrade: more-itertools>=4.0.0 in c:\program files\python38\lib\site-packages (from pytest) (8.2.0)
Requirement already satisfied, skipping upgrade: py>=1.5.0 in c:\program files\python38\lib\site-packages (from pytest) (1.8.1)
Requirement already satisfied, skipping upgrade: six in c:\program files\python38\lib\site-packages (from packaging->pytest) (1.14.0)
Requirement already satisfied, skipping upgrade: pyparsing>=2.0.2 in c:\program files\python38\lib\site-packages (from packaging->pytest) (2.4.6)
Installing collected packages: pytest
Successfully installed pytest-5.4.1
代碼示例
新建一個python文件,并寫入如下代碼:
def test_equal():assert(1,2,3)==(1,2,3)
然后在命令行運行該文件,執行命令為 pytest xxx.py,執行結果如圖
C:\Users\Administrator>pytest C:\Users\Administrator\Desktop\123.py
===================================== test session starts ==================================================
platform win32 -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: C:\Users\Administrator
collected 1 itemDesktop\123.py . [100%]====================================== 1 passed in 0.09s ==================================================
如果想看到詳細的執行結果,可以給執行命令加上參數 -v或者–verbose,即pytest -v xxx.py,執行結果如圖
C:\Users\Administrator>pytest -v C:\Users\Administrator\Desktop\123.py
======================================= test session starts =================================================
platform win32 -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- c:\program files\python38\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Administrator
collected 1 itemDesktop/123.py::test_equal PASSED [100%]============================================ 1 passed in 0.04s ===============================================
我們在看一個執行失敗的例子,再新建一個py文件,寫入如下代碼:
def test_equal():assert(1,2,3)==(3,2,1)
然后執行該文件,pytest -v xxx.py,執行結果如圖
C:\Users\Administrator>pytest -v C:\Users\Administrator\Desktop\123.py
=========================================== test session starts ==============================================
platform win32 -- Python 3.8.1, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- c:\program files\python38\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\Administrator
collected 1 itemDesktop/123.py::test_equal FAILED [100%]============================================= FAILURES =======================================================
____________________________________________ test_equal ______________________________________________________def test_equal():
> assert(1,2,3)==(3,2,1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Full diff:
E - (3, 2, 1)
E ? ^ ^
E + (1, 2, 3)
E ? ^ ^Desktop\123.py:2: AssertionError
====================================== short test summary info ===============================================
FAILED Desktop/123.py::test_equal - assert (1, 2, 3) == (3, 2, 1)
============================================= 1 failed in 0.20s ==============================================
雖然斷言結果是失敗,但我們從執行結果中能夠很清晰的看到為什么,pytest使用脫字符(^)表明結果中不同的地方
配置Pycharm
卸載Pytest
C:\Users\Administrator>pip uninstall pytest
Found existing installation: pytest 5.4.1
Uninstalling pytest-5.4.1:Would remove:c:\program files\python38\lib\site-packages\_pytest\*c:\program files\python38\lib\site-packages\pytest-5.4.1.dist-info\*c:\program files\python38\lib\site-packages\pytest\*c:\program files\python38\scripts\py.test.exec:\program files\python38\scripts\pytest.exe
Proceed (y/n)? ySuccessfully uninstalled pytest-5.4.1C:\Users\Administrator>
常用命令行參數
Pytest執行規則
- 在命令行使用pytest執行測試,完整的pytest命令需要在pytest后加選項和文件名或者路徑
- 如果不提供這些選項或參數,pytest會在當前目錄及其子目錄下尋找測試文件,然后運行搜索到的測試代碼
- 如果提供了一個或者多個文件名、目錄,pytest會逐一查找并運行所有測試,為了搜索到所有的測試代碼,pytest會遞歸遍歷每個目錄及其子目錄,但也只是執行以test_開頭或者_test開頭的測試函數
pytest搜索測試文件和測試用例的過程稱為測試搜索,只要遵循如下幾條原則便能夠被它搜索到
- 測試文件應命名為test_(something).py或者(something)_test.py
- 測試函數、測試類方法應命名為test_(something)
- 測試類應命名為Test(something)
測試代碼
假如有如下待測代碼,將其保存在py文件中,文件名為tobetest.py
import pytest# 功能
def add(a, b):return a + b# 測試相等
@allure.step
def test_add():assert add(3, 4) == 7# 測試不相等
@allure.step
def test_add2():assert add(17, 22) != 50# 測試大于
@allure.step
def test_add3():assert add(17, 22) <= 50# 測試小于
@pytest.mark.aaaa
def test_add4():assert add(17, 22) >= 50# 測試相等
def test_in():a = "hello"b = "he"assert b in a# 測試不相等
def test_not_in():a = "hello"b = "hi"assert b not in a# 用于判斷素數
def is_prime(n):if n <= 1:return Falsefor i in range(2, n):if n % i == 0:return Falsereturn True# 判斷是否為素數
def test_true():assert is_prime(13)# 判斷是否不為素數
def test_not_true():assert not is_prime(7)
執行單一文件
E:\Programs\Python\Python_Pytest\TestScripts>pytest tobetest.py
============================================= test session starts ====================================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.13.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts, inifile: pytest.ini
plugins: allure-pytest-2.6.3, cov-2.7.1, emoji-0.2.0, forked-1.0.2, instafail-0.4.1, nice-0.1.0, repeat-0.8.0, timeout-1.3.3, xdist-1.29.0
collected 8 items tobetest.py ...F...F [100%]================================================ FAILURES ===========================================================
_________________________________________________ test_add4 __________________________________________________________@pytest.mark.aaaadef test_add4():
> assert add(17, 22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:36: AssertionError
_________________________________________________ test_not_true ______________________________________________________def test_not_true():
> assert not is_prime(7)
E assert not True
E + where True = is_prime(7)test_asserts.py:70: AssertionError
========================================= warnings summary ============================================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.aaaa - is this a typo? You can register custom marks to avoidthis warning - for details, see https://docs.pytest.org/en/latest/mark.htmlPytestUnknownMarkWarning,test_asserts.py::test_add4
test_asserts.py::test_not_truec:\python37\lib\site-packages\pytest_nice.py:22: PytestDeprecationWarning: the `pytest.config` global is deprecated. Please use `request.config` or `pytest_configure` (i
f you're a pytest plugin) instead.if report.failed and pytest.config.getoption('nice'):-- Docs: https://docs.pytest.org/en/latest/warnings.html
================================ 2 failed, 6 passed, 3 warnings in 0.46 seconds =========================================
- 第一行顯示執行代碼的操作系統、python版本以及pytest的版本:
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.13.0
- 第二行顯示搜索代碼的啟示目錄以及配置文件,在本例中沒有配置文件,因此inifile為空:
rootdir: E:\Programs\Python\Python_Pytest\TestScripts, inifile: pytest.ini
- 第三行顯示當前已經安裝的pytest插件
plugins: allure-pytest-2.6.3, cov-2.7.1, emoji-0.2.0, forked-1.0.2, instafail-0.4.1, nice-0.1.0, repeat-0.8.0, timeout-1.3.3, xdist-1.29.0
- 第四行
collected 8 items
表示找到8個測試函數。 - 第五行
tobetest.py ...F...F
顯示的是測試文件名,后邊的點表示測試通過,除了點以外,還可能遇到Failure、error(測試異常)、skip、xfail(預期失敗并確實失敗)、xpass(預期失敗但實際通過,不符合預期)分別會顯示F、E、s、x、X 2 failed, 6 passed, 3 warnings in 0.46 seconds
表示測試結果和執行時間
執行單一測試函數
使用命令 pytest -v 路徑/文件名::測試用例函數名
執行結果如下:
E:\Programs\Python\Python_Pytest\TestScripts>pytest test_asserts.py::test_true
==================================================== test session starts ===============================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.13.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts, inifile: pytest.ini
plugins: allure-pytest-2.6.3, cov-2.7.1, emoji-0.2.0, forked-1.0.2, instafail-0.4.1, nice-0.1.0, repeat-0.8.0, timeout-1.3.3, xdist-1.29.0
collected 1 item test_asserts.py . [100%]================================================== warnings summary ====================================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.aaaa - is this a typo? You can register custom marks to avoidthis warning - for details, see https://docs.pytest.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
========================================== 1 passed, 1 warnings in 0.07 seconds =========================================
其他命令行規則
- 運行某個模塊內的某個測試函數
pytest test_mod.py::test_func
- 運行某個模塊內某個類的某個測試方法
pytest test_mod.py::TestClass::test_method
- 執行單一測試模塊的語法是
pytest test_module.py
- 執行某個目錄下的所有測試函數語法是
pytest test/
常用pytest命令選項
--collect-only
在批量執行測試用例之前,我們往往會想知道哪些用例將被執行是否符合我們的預期等等,這種場景下可以使用–collect-only選項,如下執行結果所示:
D:\PythonPrograms\Python_Pytest\TestScripts>pytest --collect-only
================================================= test session starts ===================================================
platform win32 -- Python 3.7.2, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\PythonPrograms\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 17 items
<Package 'D:\\PythonPrograms\\Python_Pytest\\TestScripts'><Module 'test_asserts.py'><Function 'test_add'><Function 'test_add2'><Function 'test_add3'><Function 'test_add4'><Function 'test_in'><Function 'test_not_in'><Function 'test_true'><Module 'test_fixture1.py'><Function 'test_numbers_3_4'><Function 'test_strings_a_3'><Module 'test_fixture2.py'><Class 'TestUM'><Function 'test_numbers_5_6'><Function 'test_strings_b_2'><Module 'test_one.py'><Function 'test_equal'><Function 'test_not_equal'><Module 'test_two.py'><Function 'test_default'><Function 'test_member_access'><Function 'test_asdict'><Function 'test_replace'>============================================= no tests ran in 0.09 seconds ==============================================
-k
該選項允許我們使用表達式指定希望運行的測試用例,如果某測試名是唯一的或者多個測試名的前綴或后綴相同,則可以使用這個選項來執行,如下執行結果所示:
D:\PythonPrograms\Python_Pytest\TestScripts>pytest -k "asdict or default" --collect-only
================================================= test session starts ===================================================
platform win32 -- Python 3.7.2, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\PythonPrograms\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 17 items / 15 deselected
<Package 'D:\\PythonPrograms\\Python_Pytest\\TestScripts'><Module 'test_two.py'><Function 'test_default'><Function 'test_asdict'>============================================ 15 deselected in 0.06 seconds ===========================================
從執行結果中我們能看到使用-k和–collect-only組合能夠查詢到我們設置的參數所能執行的測試方法。
然后我們將–collect-only從命令行移出,只使用-k便可執行test_default和test_asdict了
D:\PythonPrograms\Python_Pytest\TestScripts>pytest -k "asdict or default"
================================================ test session starts =================================================
platform win32 -- Python 3.7.2, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\PythonPrograms\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 17 items / 15 deselectedtest_two.py .. [100%]============================================= 2 passed, 15 deselected in 0.07 seconds ================================
如果我們在定義用例名的時候特別注意一下便可以使用-k的方式執行一系列測試用例了,同時表達式中科包含 and、or、not
-m
用于標記并分組,然后僅執行帶有標記的用例,如此便實現了執行某個測試集合的場景,如下代碼所示,給我們之前的兩個測試方法添加標記
@pytest.mark.run_these_cases
def test_member_access():"""利用屬性名來訪問對象成員:return:"""t = Task('buy milk', 'brian')assert t.summary == 'buy milk'assert t.owner == 'brian'assert(t.done, t.id) == (False, None)@pytest.mark.run_these_cases
def test_asdict():"""_asdict()返回一個字典"""t_task = Task('do something','okken',True, 21)t_dict = t_task._asdict()expected_dict = {'summary': 'do something','owner': 'okken','done': True,'id': 21}assert t_dict == expected_dict
執行命令pytest -v -m run_these_cases
,結果如下:
D:\PythonPrograms\Python_Pytest\TestScripts>pytest -v -m run_these_cases
============================================== test session starts ======================================================
platform win32 -- Python 3.7.2, pytest-4.0.2, py-1.8.0, pluggy-0.12.0 -- c:\python37\python.exe
cachedir: .pytest_cache
rootdir: D:\PythonPrograms\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 17 items / 15 deselectedtest_two.py::test_member_access PASSED [ 50%]
test_two.py::test_asdict PASSED [100%]======================================= 2 passed, 15 deselected in 0.07 seconds =========================================
-m選項也可以用表達式指定多個標記名,例如-m “mark1 and mark2” 或者-m “mark1 and not mark2” 或者-m “mark1 or mark2”
-x
Pytest會運行每一個搜索到的測試用例,如果某個測試函數被斷言失敗,或者觸發了外部異常,則該測試用例的運行就會停止,pytest將其標記為失敗后繼續運行一下測試用例,然而在debug的時候,我們往往希望遇到失敗時立刻停止整個會話,-x選項為我們提供了該場景的支持,如下執行結果所示:
E:\Programs\Python\Python_Pytest\TestScripts>pytest -x
=============================================== test session starts =================================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts
plugins: allure-pytest-2.6.3
collected 17 items test_asserts.py ...F=====================================================FAILURES ===========================================================
____________________________________________________test_add4 ___________________________________________________________def test_add4():
> assert add(17,22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:34: AssertionError
============================================ warnings summary ===========================================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.run_these_cases - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pyt
est.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
=============================== 1 failed, 3 passed, 1 warnings in 0.41 seconds ==========================================
在執行結果中我們可以看到實際收集的測試用例是17條,但執行了4條,通過3條失敗一條,執行便停止了。
如果不適用-x選項再執行一次結果如下:
E:\Programs\Python\Python_Pytest\TestScripts>pytest --tb=no
============================================ test session starts =====================================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts
plugins: allure-pytest-2.6.3
collected 17 items test_asserts.py ...F..F [ 41%]
test_fixture1.py .. [ 52%]
test_fixture2.py .. [ 64%]
test_one.py .F [ 76%]
test_two.py .... [100%]============================================= warnings summary =======================================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.run_these_cases - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pyt
est.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
==================================== 3 failed, 14 passed, 1 warnings in 0.31 seconds =================================
從執行結果中我們看到一共收集的測試用例為17條,14條通過,3條失敗,使用了選項–tb=no關閉錯誤信息回溯,當我們只想看執行結果而不想看那么多報錯信息的時候可以使用它。
--maxfail=num
-x是遇到失敗便全局停止,如果我們想遇到失敗幾次再停止呢?–maxfail選項為我們提供了這個場景的支持,如下執行結果所示:
E:\Programs\Python\Python_Pytest\TestScripts>pytest --maxfail=2 --tb=no
============================================= test session starts =======================================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts
plugins: allure-pytest-2.6.3
collected 17 items test_asserts.py ...F..F================================================= warnings summary ======================================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.run_these_cases - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pyt
est.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
========================================= 2 failed, 5 passed, 1 warnings in 0.22 seconds ================================
從執行結果中我們看到收集了17條用例,執行了7條,當錯誤數量達到2的時候便停止了執行。
--tb=
命令及參數 | 描述 |
---|---|
pytest --showlocals | # show local variables in tracebacks |
pytest -l | # show local variables (shortcut) |
pytest --tb=auto | # (default) ‘long’ tracebacks for the first and last entry, but ‘short’ style for the other entries |
pytest --tb=long | # exhaustive, informative traceback formatting |
pytest --tb=short | # shorter traceback format |
pytest --tb=line | # only one line per failure |
pytest --tb=native | # Python standard library formatting |
pytest --tb=no | # no traceback at all |
pytest --full-trace | #causes very long traces to be printed on error (longer than --tb=long). |
-v (--verbose)
-v, --verbose:increase verbosity.
-q (--quiet)
-q, --quiet:decrease verbosity.
--lf (--last-failed)
–lf, --last-failed:rerun only the tests that failed at the last run (or all if none failed)
E:\Programs\Python\Python_Pytest\TestScripts>pytest --lf --tb=no
================================== test session starts ==========================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts
plugins: allure-pytest-2.6.3
collected 9 items / 6 deselected / 3 selected
run-last-failure: rerun previous 3 failures (skipped 7 files)
test_asserts.py FF [ 66%]
test_one.py F [100%]
============================= 3 failed, 6 deselected in 0.15 seconds ============================
--ff (--failed-first)
–ff, --failed-first :run all tests but run the last failures first. This may re-order tests and thus lead to repeated fixture setup/teardown
E:\Programs\Python\Python_Pytest\TestScripts>pytest --ff --tb=no
================================= test session starts ==================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest\TestScripts
plugins: allure-pytest-2.6.3
collected 17 items
run-last-failure: rerun previous 3 failures first
test_asserts.py FF [ 11%]
test_one.py F [ 17%]
test_asserts.py ..... [ 47%]
test_fixture1.py .. [ 58%]
test_fixture2.py .. [ 70%]
test_one.py . [ 76%]
test_two.py .... [100%]
======================== warnings summary ==========================================
c:\python37\lib\site-packages\_pytest\mark\structures.py:324c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.run_these_cases - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pyt
est.org/en/latest/mark.htmlPytestUnknownMarkWarning,-- Docs: https://docs.pytest.org/en/latest/warnings.html
================= 3 failed, 14 passed, 1 warnings in 0.25 seconds ==========================
-s與--capture=method
-s等同于--capture=no
(venv) D:\Python_Pytest\TestScripts>pytest -s
============================= test session starts ============================================
platform win32 -- Python 3.7.3, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 18 items test_asserts.py ...F...F
test_fixture1.pysetup_module================>
setup_function------>
test_numbers_3_4
.teardown_function--->
setup_function------>
test_strings_a_3
.teardown_function--->
teardown_module=============>test_fixture2.pysetup_class=========>
setup_method----->>
setup----->
test_numbers_5_6
.teardown-->
teardown_method-->>
setup_method----->>
setup----->
test_strings_b_2
.teardown-->
teardown_method-->>
teardown_class=========>test_one.py .F
test_two.py ....========================================== FAILURES ============================================
____________________________________________ test_add4 ______________________________________________@pytest.mark.aaaadef test_add4():
> assert add(17, 22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:36: AssertionError
_____________________________________________________________________________________________________________ test_not_true ______________________________________________________________________________________________________________def test_not_true():
> assert not is_prime(7)
E assert not True
E + where True = is_prime(7)test_asserts.py:70: AssertionError
_______________________________________ test_not_equal ________________________________________________def test_not_equal():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full difftest_one.py:9: AssertionError
================================== 3 failed, 15 passed in 0.15 seconds =================================
--capture=method per-test capturing method: one of fd|sys|no.
-l (--showlocals)
-l, --showlocals show locals in tracebacks (disabled by default).
--duration=N
--durations=N show N slowest setup/test durations (N=0 for all).
該選項絕大多數用于調優測試代碼,該選項展示最慢的N個用例,等于0則表示全部倒序
(venv) D:\Python_Pytest\TestScripts>pytest --duration=5
===================================================== test session starts ==============================================
platform win32 -- Python 3.7.3, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 18 items test_asserts.py ...F...F [ 44%]
test_fixture1.py .. [ 55%]
test_fixture2.py .. [ 66%]
test_one.py .F [ 77%]
test_two.py .... [100%]======================================================= FAILURES ======================================================
_______________________________________________________ test_add4 _____________________________________________________@pytest.mark.aaaadef test_add4():
> assert add(17, 22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:36: AssertionError
_____________________________________________________ test_not_true _____________________________________________________def test_not_true():
> assert not is_prime(7)
E assert not True
E + where True = is_prime(7)test_asserts.py:70: AssertionError
___________________________________________________ test_not_equal ______________________________________________________def test_not_equal():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full difftest_one.py:9: AssertionError
================================================ slowest 5 test durations ===============================================
0.01s call test_asserts.py::test_add4(0.00 durations hidden. Use -vv to show these durations.)
========================================== 3 failed, 15 passed in 0.27 seconds ==========================================
在執行結果中我們看到提示(0.00 durations hidden. Use -vv to show these durations.),如果加上-vv,執行結果如下:
(venv) D:\Python_Pytest\TestScripts>pytest --duration=5 -vv
============================= test session starts =============================
platform win32 -- Python 3.7.3, pytest-4.0.2, py-1.8.0, pluggy-0.12.0 -- c:\python37\python.exe
cachedir: .pytest_cache
rootdir: D:\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 18 items test_asserts.py::test_add PASSED [ 5%]
test_asserts.py::test_add2 PASSED [ 11%]
test_asserts.py::test_add3 PASSED [ 16%]
test_asserts.py::test_add4 FAILED [ 22%]
test_asserts.py::test_in PASSED [ 27%]
test_asserts.py::test_not_in PASSED [ 33%]
test_asserts.py::test_true PASSED [ 38%]
test_asserts.py::test_not_true FAILED [ 44%]
test_fixture1.py::test_numbers_3_4 PASSED [ 50%]
test_fixture1.py::test_strings_a_3 PASSED [ 55%]
test_fixture2.py::TestUM::test_numbers_5_6 PASSED [ 61%]
test_fixture2.py::TestUM::test_strings_b_2 PASSED [ 66%]
test_one.py::test_equal PASSED [ 72%]
test_one.py::test_not_equal FAILED [ 77%]
test_two.py::test_default PASSED [ 83%]
test_two.py::test_member_access PASSED [ 88%]
test_two.py::test_asdict PASSED [ 94%]
test_two.py::test_replace PASSED [100%]====================================================== FAILURES =========================================================
______________________________________________________ test_add4 ________________________________________________________@pytest.mark.aaaadef test_add4():
> assert add(17, 22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:36: AssertionError
____________________________________________________ test_not_true ____________________________________________________def test_not_true():
> assert not is_prime(7)
E assert not True
E + where True = is_prime(7)test_asserts.py:70: AssertionError
___________________________________________________ test_not_equal ____________________________________________________def test_not_equal():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Full diff:
E - (1, 2, 3)
E ? ^ ^
E + (3, 2, 1)
E ? ^ ^test_one.py:9: AssertionError
============================================== slowest 5 test durations ===============================================
0.00s setup test_one.py::test_not_equal
0.00s setup test_fixture1.py::test_strings_a_3
0.00s setup test_asserts.py::test_add3
0.00s call test_fixture2.py::TestUM::test_strings_b_2
0.00s call test_asserts.py::test_in
========================================= 3 failed, 15 passed in 0.16 seconds =========================================
-r
生成一個簡短的概述報告,同時配合-r還可以使用
Option | Description |
---|---|
f | failed |
E | error |
s | skipped |
x | xfailed |
X | xpassed |
p | passed |
P | passed with output |
a | all except pP |
A | all |
例如只想看失敗的和跳過的測試,可以這樣執行 |
(venv) E:\Python_Pytest\TestScripts>pytest -rfs
=================================================== test session starts =================================================
platform win32 -- Python 3.7.3, pytest-4.0.2, py-1.8.0, pluggy-0.12.0
rootdir: E:\Python_Pytest\TestScripts, inifile:
plugins: allure-adaptor-1.7.10
collected 18 items test_asserts.py ...F...F [ 44%]
test_fixture1.py .. [ 55%]
test_fixture2.py .. [ 66%]
test_one.py .F [ 77%]
test_two.py .... [100%]==================================================== FAILURES ===========================================================
____________________________________________________ test_add4 __________________________________________________________@pytest.mark.aaaadef test_add4():
> assert add(17, 22) >= 50
E assert 39 >= 50
E + where 39 = add(17, 22)test_asserts.py:36: AssertionError
__________________________________________________ test_not_true _______________________________________________________def test_not_true():
> assert not is_prime(7)
E assert not True
E + where True = is_prime(7)test_asserts.py:70: AssertionError
____________________________________________________ test_not_equal _____________________________________________________def test_not_equal():
> assert (1, 2, 3) == (3, 2, 1)
E assert (1, 2, 3) == (3, 2, 1)
E At index 0 diff: 1 != 3
E Use -v to get the full difftest_one.py:9: AssertionError
================================================ short test summary info ================================================
FAIL test_asserts.py::test_add4
FAIL test_asserts.py::test_not_true
FAIL test_one.py::test_not_equal
======================================== 3 failed, 15 passed in 0.10 seconds ============================================
pytest --help
獲取更多參數
在命令行輸入pytest --help 然后執行結果如下,在打印出來的結果中我們能夠看到pytest命令的使用方式usage: pytest [options] [file_or_dir] [file_or_dir] […]以及一系列的執行方式(options)及其描述。
C:\Users\Administrator>pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:file_or_dir
general:-k EXPRESSION only run tests which match the given substringexpression. An expression is a python evaluatableexpression where all names are substring-matchedagainst test names and their parent classes. Example:-k 'test_method or test_other' matches all testfunctions and classes whose name contains'test_method' or 'test_other', while -k 'nottest_method' matches those that don't contain'test_method' in their names. Additionally keywordsare matched to classes and functions containing extranames in their 'extra_keyword_matches' set, as well asfunctions which have names assigned directly to them.-m MARKEXPR only run tests matching given mark expression.example: -m 'mark1 and not mark2'.--markers show markers (builtin, plugin and per-project ones).-x, --exitfirst exit instantly on first error or failed test.--maxfail=num exit after first num failures or errors.--strict marks not registered in configuration file raiseerrors.-c file load configuration from `file` instead of trying tolocate one of the implicit configuration files.--continue-on-collection-errorsForce test execution even if collection errors occur.--rootdir=ROOTDIR Define root directory for tests. Can be relative path:'root_dir', './root_dir', 'root_dir/another_dir/';absolute path: '/home/user/root_dir'; path withvariables: '$HOME/root_dir'.--fixtures, --funcargsshow available fixtures, sorted by plugin appearance(fixtures with leading '_' are only shown with '-v')--fixtures-per-test show fixtures per test--import-mode={prepend,append}prepend/append to sys.path when importing testmodules, default is to prepend.--pdb start the interactive Python debugger on errors orKeyboardInterrupt.--pdbcls=modulename:classnamestart a custom interactive Python debugger on errors.For example:--pdbcls=IPython.terminal.debugger:TerminalPdb--trace Immediately break when running each test.--capture=method per-test capturing method: one of fd|sys|no.-s shortcut for --capture=no.--runxfail run tests even if they are marked xfail--lf, --last-failed rerun only the tests that failed at the last run (orall if none failed)--ff, --failed-first run all tests but run the last failures first. Thismay re-order tests and thus lead to repeated fixturesetup/teardown--nf, --new-first run tests from new files first, then the rest of thetests sorted by file mtime--cache-show show cache contents, don't perform collection or tests--cache-clear remove all cache contents at start of test run.--lfnf={all,none}, --last-failed-no-failures={all,none}change the behavior when no test failed in the lastrun or no information about the last failures wasfound in the cache--sw, --stepwise exit on test fail and continue from last failing testnext time--stepwise-skip ignore the first failing test but stop on the nextfailing test--allure_severities=SEVERITIES_SETComma-separated list of severity names. Tests onlywith these severities will be run. Possible valuesare:blocker, critical, minor, normal, trivial.--allure_features=FEATURES_SETComma-separated list of feature names. Run tests thathave at least one of the specified feature labels.--allure_stories=STORIES_SETComma-separated list of story names. Run tests thathave at least one of the specified story labels.reporting:-v, --verbose increase verbosity.-q, --quiet decrease verbosity.--verbosity=VERBOSE set verbosity-r chars show extra test summary info as specified by chars(f)ailed, (E)error, (s)skipped, (x)failed, (X)passed,(p)passed, (P)passed with output, (a)all except pP.Warnings are displayed at all times except when--disable-warnings is set--disable-warnings, --disable-pytest-warningsdisable warnings summary-l, --showlocals show locals in tracebacks (disabled by default).--tb=style traceback print mode (auto/long/short/line/native/no).--show-capture={no,stdout,stderr,log,all}Controls how captured stdout/stderr/log is shown onfailed tests. Default is 'all'.--full-trace don't cut any tracebacks (default is to cut).--color=color color terminal output (yes/no/auto).--durations=N show N slowest setup/test durations (N=0 for all).--pastebin=mode send failed|all info to bpaste.net pastebin service.--junit-xml=path create junit-xml style report file at given path.--junit-prefix=str prepend prefix to classnames in junit-xml output--result-log=path DEPRECATED path for machine-readable result log.collection:--collect-only only collect tests, don't execute them.--pyargs try to interpret all arguments as python packages.--ignore=path ignore path during collection (multi-allowed).--deselect=nodeid_prefixdeselect item during collection (multi-allowed).--confcutdir=dir only load conftest.py's relative to specified dir.--noconftest Don't load any conftest.py files.--keep-duplicates Keep duplicate tests.--collect-in-virtualenvDon't ignore tests in a local virtualenv directory--doctest-modules run doctests in all .py modules--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}choose another output format for diffs on doctestfailure--doctest-glob=pat doctests file matching pattern, default: test*.txt--doctest-ignore-import-errorsignore doctest ImportErrors--doctest-continue-on-failurefor a given doctest, continue to run after the firstfailuretest session debugging and configuration:--basetemp=dir base temporary directory for this test run.(warning:this directory is removed if it exists)--version display pytest lib version and import information.-h, --help show help message and configuration info-p name early-load given plugin (multi-allowed). To avoidloading of plugins, use the `no:` prefix, e.g.`no:doctest`.--trace-config trace considerations of conftest.py files.--debug store internal tracing debug information in'pytestdebug.log'.-o OVERRIDE_INI, --override-ini=OVERRIDE_INIoverride ini option with "option=value" style, e.g.`-o xfail_strict=True -o cache_dir=cache`.--assert=MODE Control assertion debugging tools. 'plain' performs noassertion debugging. 'rewrite' (the default) rewritesassert statements in test modules on import to provideassert expression information.--setup-only only setup fixtures, do not execute tests.--setup-show show setup of fixtures while executing tests.--setup-plan show what fixtures and tests would be executed butdon't execute anything.pytest-warnings:-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGSset which warnings to report, see -W option of pythonitself.logging:--no-print-logs disable printing caught logs on failed tests.--log-level=LOG_LEVELlogging level used by the logging module--log-format=LOG_FORMATlog format as used by the logging module.--log-date-format=LOG_DATE_FORMATlog date format as used by the logging module.--log-cli-level=LOG_CLI_LEVELcli logging level.--log-cli-format=LOG_CLI_FORMATlog format as used by the logging module.--log-cli-date-format=LOG_CLI_DATE_FORMATlog date format as used by the logging module.--log-file=LOG_FILE path to a file when logging will be written to.--log-file-level=LOG_FILE_LEVELlog file logging level.--log-file-format=LOG_FILE_FORMATlog format as used by the logging module.--log-file-date-format=LOG_FILE_DATE_FORMATlog date format as used by the logging module.reporting:--alluredir=DIR Generate Allure report in the specified directory (maynot exist)[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:markers (linelist) markers for test functionsempty_parameter_set_mark (string) default marker for empty parametersetsnorecursedirs (args) directory patterns to avoid for recursiontestpaths (args) directories to search for tests when no files or direconsole_output_style (string) console output: classic or with additional progrusefixtures (args) list of default fixtures to be used with this projectpython_files (args) glob-style file patterns for Python test module discopython_classes (args) prefixes or glob names for Python test class discoverpython_functions (args) prefixes or glob names for Python test function and mxfail_strict (bool) default for the strict parameter of xfail markers whejunit_suite_name (string) Test suite name for JUnit reportjunit_logging (string) Write captured log messages to JUnit report: one of ndoctest_optionflags (args) option flags for doctestsdoctest_encoding (string) encoding used for doctest filescache_dir (string) cache directory path.filterwarnings (linelist) Each line specifies a pattern for warnings.filterwarlog_print (bool) default value for --no-print-logslog_level (string) default value for --log-levellog_format (string) default value for --log-formatlog_date_format (string) default value for --log-date-formatlog_cli (bool) enable log display during test run (also known as "lilog_cli_level (string) default value for --log-cli-levellog_cli_format (string) default value for --log-cli-formatlog_cli_date_format (string) default value for --log-cli-date-formatlog_file (string) default value for --log-filelog_file_level (string) default value for --log-file-levellog_file_format (string) default value for --log-file-formatlog_file_date_format (string) default value for --log-file-date-formataddopts (args) extra command line optionsminversion (string) minimally required pytest versionenvironment variables:PYTEST_ADDOPTS extra command line optionsPYTEST_PLUGINS comma-separated plugins to load during startupPYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loadingPYTEST_DEBUG set to enable debug tracing of pytest's internalsto see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading '_' are only shown with the '-v' option
理解Pytest的配置文件
Pytest里有哪些配置文件:
配置文件 | 描述:無論選擇使用哪種配置文件,它們的格式幾乎是一樣的 |
---|---|
pytest.ini | pytest主配置文件,可以改變pytest默認行為 |
conftest.py | 本地插件庫,其中的hook函數和fixture將作用于該文件所在目錄及其子目錄 |
__init__.py | 每個測試子目錄都包含該文件時,在多個測試目錄中可以出現同名的測試文件 |
tox.ini | 如果你使用tox工具,會用到tox.ini,它與pytest.ini類似,只不過是tox的配置文件,可以把pytest的配置寫在tox.ini里,就無需同時使用pytest.ini和tox.ini了 |
setup.cfg | 它也采用ini文件格式,而且可以影響setup.py的行為,如果要發布一個python包,它的作用也很大,可以在setup.py文件里添加幾行代碼,使用python setup.py test 運行所有的pytest測試用例;如果打算發布python包,也可以使用setup.cfg文件存儲pytest的配置信息 |
pytest.ini |
;---
; Excerpted from "Python Testing with pytest",
; published by The Pragmatic Bookshelf.
; Copyrights apply to this code. It may not be used to create training material,
; courses, books, articles, and the like. Contact us if you are in doubt.
; We make no guarantees that this code is fit for any purpose.
; Visit http://www.pragmaticprogrammer.com/titles/bopytest for more book information.
;---
[pytest]
addopts = -rsxX -l --tb=short --strict
xfail_strict = true
;... more options ...
tox.ini
;---
; Excerpted from "Python Testing with pytest",
; published by The Pragmatic Bookshelf.
; Copyrights apply to this code. It may not be used to create training material,
; courses, books, articles, and the like. Contact us if you are in doubt.
; We make no guarantees that this code is fit for any purpose.
; Visit http://www.pragmaticprogrammer.com/titles/bopytest for more book information.
;---
;... tox specific stuff ...[pytest]
addopts = -rsxX -l --tb=short --strict
xfail_strict = true
;... more options ...
setup.cfg
;... packaging specific stuff ...[tool:pytest]
addopts = -rsxX -l --tb=short --strict
xfail_strict = true
;... more options ...
執行命令pytest --help能夠看到所有設置選項
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:markers (linelist) markers for test functionsempty_parameter_set_mark (string) default marker for empty parametersetsnorecursedirs (args) directory patterns to avoid for recursiontestpaths (args) directories to search for tests when no files or directories are given in the command line.usefixtures (args) list of default fixtures to be used with this projectpython_files (args) glob-style file patterns for Python test module discoverypython_classes (args) prefixes or glob names for Python test class discoverypython_functions (args) prefixes or glob names for Python test function and method discoverydisable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool) disable string escape non-ascii characters, might cause unwanted side effects(use at your ownconsole_output_style (string) console output: "classic", or with additional progress information ("progress" (percentage) | "count").xfail_strict (bool) default for the strict parameter of xfail markers when not given explicitly (default: False)junit_suite_name (string) Test suite name for JUnit reportjunit_logging (string) Write captured log messages to JUnit report: one of no|system-out|system-errjunit_duration_report (string) Duration time to report: one of total|calljunit_family (string) Emit XML for schema: one of legacy|xunit1|xunit2doctest_optionflags (args) option flags for doctestsdoctest_encoding (string) encoding used for doctest filescache_dir (string) cache directory path.filterwarnings (linelist) Each line specifies a pattern for warnings.filterwarnings. Processed after -W and --pythonwarnings.log_print (bool) default value for --no-print-logslog_level (string) default value for --log-levellog_format (string) default value for --log-formatlog_date_format (string) default value for --log-date-formatlog_cli (bool) enable log display during test run (also known as "live logging").log_cli_level (string) default value for --log-cli-levellog_cli_format (string) default value for --log-cli-formatlog_cli_date_format (string) default value for --log-cli-date-formatlog_file (string) default value for --log-filelog_file_level (string) default value for --log-file-levellog_file_format (string) default value for --log-file-formatlog_file_date_format (string) default value for --log-file-date-formataddopts (args) extra command line optionsminversion (string) minimally required pytest versionrsyncdirs (pathlist) list of (relative) paths to be rsynced for remote distributed testing.rsyncignore (pathlist) list of (relative) glob-style paths to be ignored for rsyncing.looponfailroots (pathlist) directories to check for changestimeout (string) Timeout in seconds before dumping the stacks. Default is 0 which
means no timeout.timeout_method (string) Timeout mechanism to use. 'signal' uses SIGALRM if available,
'thread' uses a timer thread. The default is to use 'signal' and fall
back to 'thtimeout_func_only (bool) When set to True, defers the timeout evaluation to only the test
function body, ignoring the time it takes when evaluating any fixtures
used in tpytester_example_dir (string) directory to take the pytester example files fromenvironment variables:PYTEST_ADDOPTS extra command line optionsPYTEST_PLUGINS comma-separated plugins to load during startupPYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loadingPYTEST_DEBUG set to enable debug tracing of pytest's internals
插件可以添加ini文件選項
除了前邊列出來的這些選項,利用插件和conftest.py文件還可以添加新的選項,而且新增的選項也可以使用pytest --help查看。
更改默認命令行選項
經過前邊的文章,已經涉獵到很多pytest選項了,例如-v/–verbose可以輸出詳細信息,-l/–showlocals可以查看失敗測試用例里堆棧中的局部變量,你可能經常用到這些選項,但又不想重復輸入,此時就可以借助pytest.ini文件里的addopts設置
[pytest]
addopts = -rsxX -l --tb=short --strict
選項 | 介紹 |
---|---|
-rsxX | 表示pytest報告所有測試用例被跳過、預計失敗、預計失敗但實際通過的原因 |
-l | 表示pytest報告所有失敗測試用例的對戰中的局部變量 |
–tb=short | 表示簡化堆棧回溯信息,只保留文件和行數 |
–strict | 選項表示禁止使用未在配置文件中注冊的標記 |
注冊標記來防范拼寫錯誤
在pytest.ini中注冊標記:
[pytest]
markers=smoke: Run the smoke test functions for tasks projectget:Run the test functions that test tasks.get()
標記注冊好后,可以通過pytest --markers來查看
(venv) E:\Programs\Python\Python_Pytest\pytest-nice>pytest --markers
@pytest.mark.smoke: Run the smoke test functions for tasks project@pytest.mark.get:Run the test functions that test tasks.get()
這樣當我們給addopts加上–strict時,沒有注冊的標記就不能再使用,因此也就盡可能減少拼寫錯誤
指定pytest的最低版本號
minversion選項可以指定運行測試用例的pytest的最低版本,例如測試兩個浮點數的值是否接近,我們會使用approx()函數,但這個功能直到pytest3.0才出現,為此我們可以在pytest.ini文件中添加
[pytest]
minversion = 3.0
指定pytest忽略某些目錄
pytest執行搜索時,會遞歸遍歷所有子目錄,可以使用norecurse選項簡化pytest的搜索工作。
norecurse的默認值是.* build dist CVS _darcs {arch}
和*.egg
如果讓pytest忽略Tasks項目的src目錄,則需要加入norecursedirs里
[pytest]
norecursedirs = .* venv src *.egg dist build
指定測試目錄
testpaths只是pytest去哪里訪問,它是一系列相對于根目錄的路徑,用于限定測試用例的搜索范圍,只有在pytest未指定文件目錄參數或者測試用例標識符時,該選項才會啟動。
task_proj/
|------pytest.ini
|------src
| |------tasks
| |------api.py
| |------......
|------test|------conftest.py|------func| |------__init__py| |------test_add.py| |------......|------unit|------__init__.py|------test_task.py|------......
例如這樣的機構目錄,我們要指定test目錄為pytest的執行路徑
[pytest]
testpaths = test
然后只需要從tasks_proj開始運行pytest,pytest就會直接去找test路徑。
更改測試搜索的規則
pytest的執行,是根據一定的規則搜索并運行測試的:
- 從一個或多個目錄開始查找
- 在該目錄和所有子目錄下遞歸查找測試模塊
- 測試模塊是指定文件名為test_.py和_test.py的文件
- 在測試模塊中查找以test_開頭的函數名
- 查找名字以Test開頭的類,首先篩選掉包含__init__函數的類,再查找類中以Test_開頭的類方法
接下來修改規則:
默認規則pytest尋找Test*開頭的類,而這個類不能含有__init__()函數,可以使用python_classes來修改
[pytest]python_classes = *Test Test* *Suite
像python_classes一樣,python_files可以更改默認的測試搜索規則,而不是僅查找以test_開頭的文件和_test結尾的文件
[pytest]
python_files = test_* *_test check_*
同樣的可以修改搜索測試函數和方法的命名規則
[pytest]
python_functions = test_* check_*
禁用XPASS
設置xfail_strict = true
將會使那些被標記為@pytest.mark.xfail但是實際通過的測試用例也會報告為失敗。
避免文件名沖突
duplicate
|------dup_a
| |------test_func.py
| dup_b
| |------test_func.py
兩個py文件中分別寫入函數test_a()和test_b()
def test_a():pass
def test_b():pass
如此目錄結構,兩個同名文件,雖然文件內容不同,但他們還是會沖突,可以單獨運行py文件,但在duplicate路徑下執行就不行了,會報如下錯誤:
(venv) E:\Programs\Python\Python_Pytest\SourceCode\ch6\duplicate>pytest
================== test session starts ===================================
platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0
rootdir: E:\Programs\Python\Python_Pytest, inifile: pytest.ini
plugins: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, nice-0.1.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3
collected 1 item / 1 errors =========================================== ERRORS ============================
____________________ ERROR collecting SourceCode/ch6/duplicate/b/test_func.py __________________________
import file mismatch:
imported module 'test_func' has this __file__ attribute:E:\Programs\Python\Python_Pytest\SourceCode\ch6\duplicate\a\test_func.py
which is not the same as the test file we want to collect:E:\Programs\Python\Python_Pytest\SourceCode\ch6\duplicate\b\test_func.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
============================== 1 error in 0.32 seconds ==========================================
報錯信息中也并沒明顯指出問題在哪,要解決這個問題,只需要在各個子目錄里添加一個空的__init__.py文件即可,測試子目錄添加__init__.py是個好習慣