一個規範的測試方法必定帶有斷言,在使用pytest時,能夠直接使用Python自帶的assert關鍵字html
Pytest | Unittest |
---|---|
assert something | assertTrue(something) |
assert a==b | assertEqual(a,b) |
assert a<=b | assertLessEqual(a,b) |
… | … |
Pytest容許在assert關鍵字添加任意表達式,表達式的值經過bool轉換後等於False則表示斷言失敗,測試用例執行失敗;若是等於True則表示斷言成功,測試用例執行成功。python
pytest能夠重寫assert關鍵字,它能夠截斷對原生assert的調用,替換爲pytest定義的assert,從而展現更詳細的信息和細節。mysql
from collections import namedtuple Task = namedtuple('Task', ['summary','owner','done','id']) # __new__.__defaults__建立默認的Task對象 Task.__new__.__defaults__ = (None, None, False, None) import pytest def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) assert t1 == t2 def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) assert t1_dict == t2_dict
執行結果以下:sql
E:\Programs\Python\Python_Pytest\TestScripts>pytest test_three.py =========================================== 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: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items test_three.py FF [100%] ================================================ FAILURES ==================================================== ___________________________________________ test_task_equality _______________________________________________ def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Use -v to get the full diff test_three.py:14: AssertionError ---------------------------------------- Captured stdout call ------------------------------------------------ Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ___________________________________________ test_dict_equal __________________________________________________ def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) > assert t1_dict == t2_dict E AssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) E Omitting 3 identical items, use -vv to show E Differing items: E {'owner': 'okken'} != {'owner': 'okkem'} E Use -v to get the full diff test_three.py:22: AssertionError ------------------------------------------- Captured stdout call --------------------------------------------- OrderedDict([('summary', 'make sandwich'), ('owner', 'okken'), ('done', False), ('id', None)]) OrderedDict([('summary', 'make sandwich'), ('owner', 'okkem'), ('done', False), ('id', None)]) ========================================== 2 failed in 0.20 seconds===========================================
加上參數-v,執行結果以下:session
E:\Programs\Python\Python_Pytest\TestScripts>pytest test_three.py -v =========================================== test session starts ============================================== platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0 -- c:\python37\python.exe cachedir: .pytest_cache rootdir: E:\Programs\Python\Python_Pytest\TestScripts plugins: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items test_three.py::test_task_equality FAILED [ 50%] test_three.py::test_dict_equal FAILED [100%] ================================================ FAILURES =================================================== ___________________________________________ test_task_equality ______________________________________________ def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Full diff: E - Task(summary='sit there', owner='brain', done=False, id=None) E ? ^^^ ^^^ ^^^^ E + Task(summary='do something', owner='okken', done=False, id=None) E ? +++ ^^^ ^^^ ^^^^ test_three.py:14: AssertionError ----------------------------------------- Captured stdout call ----------------------------------------------- Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ___________________________________________ test_dict_equal __________________________________________________ def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) > assert t1_dict == t2_dict E AssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) E Omitting 3 identical items, use -vv to show E Differing items: E {'owner': 'okken'} != {'owner': 'okkem'} E Full diff: E OrderedDict([('summary', 'make sandwich'), E - ('owner', 'okken'), E ? ^... E E ...Full output truncated (5 lines hidden), use '-vv' to show test_three.py:22: AssertionError -------------------------------------------- Captured stdout call -------------------------------------------- OrderedDict([('summary', 'make sandwich'), ('owner', 'okken'), ('done', False), ('id', None)]) OrderedDict([('summary', 'make sandwich'), ('owner', 'okkem'), ('done', False), ('id', None)]) ========================================== 2 failed in 0.13 seconds ==========================================
""" 在Task項目的API中,有幾個地方可能拋出異常 def add(task): # type:(Task) ->int def get(task_id): # type:(int) ->Task def list_tasks(owner=None): # type:(str|None) ->list of task def count(): # type:(None) ->int def update(task_id, task): # type:(int, Task) ->None def delete(task_id): # type:(int) ->None def delete_all(): # type:() ->None def unique_id(): # type:() ->int def start_tasks_db(db_path, db_type): # type:(str, str) ->None def stop_tasks_db(): # type:() ->None """ import pytest import tasks def test_add_raises(): with pytest.raises(TypeError): tasks.add(task='no a Task object') """ 測試用例中有with pytest.raise(TypeError)生命,意味着不管with結構中的內容是什麼 都至少會發生TypeError異常,若是測試經過,說明確實發生了咱們預期TypeError,若是拋出的是其餘類型的異常 則與咱們預期的異常不一致,測試用例執行失敗 """ def test_start_tasks_db_raises(): with pytest.raises(ValueError) as excinfo: tasks.start_tasks_db('some/great/path', 'mysql') exception_msg = excinfo.value.args[0] assert exception_msg == "db_type must be a 'tiny' or 'mongo' "
from collections import namedtuple import pytest Task = namedtuple('Task', ['summary','owner','done','id']) # __new__.__defaults__建立默認的Task對象 Task.__new__.__defaults__ = (None, None, False, None) @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) assert t1 == t2 @pytest.mark.dict @pytest.mark.smoke def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) assert t1_dict == t2_dict
執行結果以下:ide
E:\Programs\Python\Python_Pytest\TestScripts>pytest -v -m 'smoke' test_five.py ======================================== test session starts ================================================= platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0 -- c:\python37\python.exe cachedir: .pytest_cache rootdir: E:\Programs\Python\Python_Pytest\TestScripts plugins: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items test_five.py::test_task_equality FAILED [ 50%] test_five.py::test_dict_equal FAILED [100%] ================================================ FAILURES ==================================================== __________________________________________ test_task_equality ________________________________________________ @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Full diff: E - Task(summary='sit there', owner='brain', done=False, id=None) E ? ^^^ ^^^ ^^^^ E + Task(summary='do something', owner='okken', done=False, id=None) E ? +++ ^^^ ^^^ ^^^^ test_five.py:14: AssertionError --------------------------------------- Captured stdout call ------------------------------------------------- Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ___________________________________________ test_dict_equal __________________________________________________ @pytest.mark.dict @pytest.mark.smoke def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) > assert t1_dict == t2_dict E AssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) E Omitting 3 identical items, use -vv to show E Differing items: E {'owner': 'okken'} != {'owner': 'okkem'} E Full diff: E OrderedDict([('summary', 'make sandwich'), E - ('owner', 'okken'), E ? ^... E E ...Full output truncated (5 lines hidden), use '-vv' to show test_five.py:24: AssertionError --------------------------------------- Captured stdout call ------------------------------------------------- OrderedDict([('summary', 'make sandwich'), ('owner', 'okken'), ('done', False), ('id', None)]) OrderedDict([('summary', 'make sandwich'), ('owner', 'okkem'), ('done', False), ('id', None)]) ============================================ warnings summary ================================================ c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.smoke - is this a typo? You can register custom marks to avoi d this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.dict - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, -- Docs: https://docs.pytest.org/en/latest/warnings.html =================================== 2 failed, 2 warnings in 0.22 seconds =====================================
在命令行執行使用了 -m marker_name參數,pytest在執行時會自動尋找被標記爲marker_name的測試方法去執行,同時-m還支持and、or、not關鍵字,以下方式:函數
E:\Programs\Python\Python_Pytest\TestScripts>pytest -v -m "smoke and not dict" test_five.py ========================================= test session starts ================================================ platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0 -- c:\python37\python.exe cachedir: .pytest_cache rootdir: E:\Programs\Python\Python_Pytest\TestScripts plugins: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items / 1 deselected / 1 selected test_five.py::test_task_equality FAILED [100%] ============================================= FAILURES ======================================================= _______________________________________ test_task_equality ___________________________________________________ @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Full diff: E - Task(summary='sit there', owner='brain', done=False, id=None) E ? ^^^ ^^^ ^^^^ E + Task(summary='do something', owner='okken', done=False, id=None) E ? +++ ^^^ ^^^ ^^^^ test_five.py:14: AssertionError --------------------------------------- Captured stdout call ------------------------------------------------ Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ========================================= warnings summary =================================================== c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.smoke - is this a typo? You can register custom marks to avoi d this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.dict - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, -- Docs: https://docs.pytest.org/en/latest/warnings.html ============================= 1 failed, 1 deselected, 2 warnings in 0.14 seconds =============================
from collections import namedtuple import pytest Task = namedtuple('Task', ['summary','owner','done','id']) # __new__.__defaults__建立默認的Task對象 Task.__new__.__defaults__ = (None, None, False, None) @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) assert t1 == t2 @pytest.mark.dict @pytest.mark.smoke @pytest.mark.skip(reason="跳過緣由你不知道嗎?") def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) assert t1_dict == t2_dict
E:\Programs\Python\Python_Pytest\TestScripts>pytest -v test_five.py ======================================= test session starts ================================================== platform win32 -- Python 3.7.3, pytest-4.5.0, py-1.8.0, pluggy-0.11.0 -- c:\python37\python.exe cachedir: .pytest_cache rootdir: E:\Programs\Python\Python_Pytest\TestScripts plugins: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items test_five.py::test_task_equality FAILED [ 50%] test_five.py::test_dict_equal SKIPPED [100%] ============================================== FAILURES ====================================================== _____________________________________________ test_task_equality _____________________________________________ @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Full diff: E - Task(summary='sit there', owner='brain', done=False, id=None) E ? ^^^ ^^^ ^^^^ E + Task(summary='do something', owner='okken', done=False, id=None) E ? +++ ^^^ ^^^ ^^^^ test_five.py:14: AssertionError --------------------------------------- Captured stdout call ------------------------------------------------- Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ========================================= warnings summary =================================================== c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.smoke - is this a typo? You can register custom marks to avoi d this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.dict - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, -- Docs: https://docs.pytest.org/en/latest/warnings.html ============================= 1 failed, 1 skipped, 2 warnings in 0.21 seconds ================================
從測試結果中咱們看到,測試用例test_five.py::test_dict_equal SKIPPED 被跳過了,然而跳過緣由並無如期的展現出來,可使用參數-rs來展現跳過緣由,以下方式:測試
E:\Programs\Python\Python_Pytest\TestScripts>pytest -rs test_five.py ==================================== 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: xdist-1.29.0, timeout-1.3.3, repeat-0.8.0, instafail-0.4.1, forked-1.0.2, emoji-0.2.0, allure-pytest-2.6.3 collected 2 items test_five.py Fs [100%] ========================================== FAILURES ========================================================== ________________________________________ test_task_equality __________________________________________________ @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) > assert t1 == t2 E AssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) E At index 0 diff: 'sit there' != 'do something' E Use -v to get the full diff test_five.py:14: AssertionError -------------------------------------------- Captured stdout call -------------------------------------------- Task(summary='sit there', owner='brain', done=False, id=None) Task(summary='do something', owner='okken', done=False, id=None) ============================================== warnings summary ============================================== c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.smoke - is this a typo? You can register custom marks to avoi d this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, c:\python37\lib\site-packages\_pytest\mark\structures.py:324 c:\python37\lib\site-packages\_pytest\mark\structures.py:324: PytestUnknownMarkWarning: Unknown pytest.mark.dict - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html PytestUnknownMarkWarning, -- Docs: https://docs.pytest.org/en/latest/warnings.html ==================================== short test summary info ================================================= SKIPPED [1] test_five.py:17: 跳過緣由你不知道嗎? ============================== 1 failed, 1 skipped, 2 warnings in 0.14 seconds ===============================
還能夠給跳過添加理由,例如當selenium版本是1.0.4的時候跳過this
from collections import namedtuple import pytest import selenium Task = namedtuple('Task', ['summary','owner','done','id']) # __new__.__defaults__建立默認的Task對象 Task.__new__.__defaults__ = (None, None, False, None) @pytest.mark.smoke def test_task_equality(): t1 = Task('sit there', 'brain') t2 = Task('do something', 'okken') print(t1) print(t2) assert t1 == t2 @pytest.mark.dict @pytest.mark.smoke @pytest.mark.skipif(selenium.__version__ == '1.0.4', reason="跳過緣由你不知道嗎?") def test_dict_equal(): t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() print(t1_dict) print(t2_dict) assert t1_dict == t2_dict
運行單個目錄,只須要將目錄做爲pytest的參數便可pytest -v test/func --tb=no
運行單個測試函數,只須要在文件名後添加::符號和函數名pytest -v test/func/test_five.py::test_dict_equal
運行單個測試類,與運行單個測試函數相似,在文件名後添加::符號和類名pytest -v test/func/test_five.py::Test_Update
運行單個測試類中的測試方法,在文件名後添加::符號和類名而後再跟::符號和函數名pytest -v test/func/test_five.py::Test_Update::test_dict_equal
spa