自動化測試框架工具pytest教程2-測試函式
第2章 測試函式
測試Tasks程式
被測程式Tasks的結構如下
tasks_proj/ ├── CHANGELOG.rst ├── LICENSE ├── MANIFEST.in ├── README.rst ├── setup.py ├── src │ └── tasks │ ├── __init__.py │ ├── api.py │ ├── cli.py │ ├── config.py │ ├── tasksdb_pymongo.py │ └── tasksdb_tinydb.py └── tests ├── conftest.py ├── pytest.ini ├── func │ ├── __init__.py │ ├── test_add.py │ └── ... └── unit ├── __init__.py ├── test_task.py └── ...
安裝:
# python3 setup.py install running install Checking .pth file support in /usr/local/lib/python3.5/dist-packages/ /usr/bin/python3 -E -c pass TEST PASSED: /usr/local/lib/python3.5/dist-packages/ appears to support .pth files running bdist_egg running egg_info creating src/tasks.egg-info writing src/tasks.egg-info/PKG-INFO writing dependency_links to src/tasks.egg-info/dependency_links.txt writing top-level names to src/tasks.egg-info/top_level.txt writing requirements to src/tasks.egg-info/requires.txt writing entry points to src/tasks.egg-info/entry_points.txt writing manifest file 'src/tasks.egg-info/SOURCES.txt' reading manifest file 'src/tasks.egg-info/SOURCES.txt' reading manifest template 'MANIFEST.in' writing manifest file 'src/tasks.egg-info/SOURCES.txt' installing library code to build/bdist.linux-x86_64/egg running install_lib running build_py creating build creating build/lib creating build/lib/tasks copying src/tasks/api.py -> build/lib/tasks copying src/tasks/tasksdb_pymongo.py -> build/lib/tasks copying src/tasks/tasksdb_tinydb.py -> build/lib/tasks copying src/tasks/config.py -> build/lib/tasks copying src/tasks/__init__.py -> build/lib/tasks copying src/tasks/cli.py -> build/lib/tasks creating build/bdist.linux-x86_64 creating build/bdist.linux-x86_64/egg creating build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/api.py -> build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/tasksdb_pymongo.py -> build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/tasksdb_tinydb.py -> build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/config.py -> build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/__init__.py -> build/bdist.linux-x86_64/egg/tasks copying build/lib/tasks/cli.py -> build/bdist.linux-x86_64/egg/tasks byte-compiling build/bdist.linux-x86_64/egg/tasks/api.py to api.cpython-35.pyc byte-compiling build/bdist.linux-x86_64/egg/tasks/tasksdb_pymongo.py to tasksdb_pymongo.cpython-35.pyc byte-compiling build/bdist.linux-x86_64/egg/tasks/tasksdb_tinydb.py to tasksdb_tinydb.cpython-35.pyc byte-compiling build/bdist.linux-x86_64/egg/tasks/config.py to config.cpython-35.pyc byte-compiling build/bdist.linux-x86_64/egg/tasks/__init__.py to __init__.cpython-35.pyc byte-compiling build/bdist.linux-x86_64/egg/tasks/cli.py to cli.cpython-35.pyc creating build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/PKG-INFO -> build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/SOURCES.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/dependency_links.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/entry_points.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/requires.txt -> build/bdist.linux-x86_64/egg/EGG-INFO copying src/tasks.egg-info/top_level.txt -> build/bdist.linux-x86_64/egg/EGG-INFO zip_safe flag not set; analyzing archive contents... creating dist creating 'dist/tasks-0.1.0-py3.5.egg' and adding 'build/bdist.linux-x86_64/egg' to it removing 'build/bdist.linux-x86_64/egg' (and everything under it) Processing tasks-0.1.0-py3.5.egg Copying tasks-0.1.0-py3.5.egg to /usr/local/lib/python3.5/dist-packages Adding tasks 0.1.0 to easy-install.pth file Installing tasks script to /usr/local/bin Installed /usr/local/lib/python3.5/dist-packages/tasks-0.1.0-py3.5.egg Processing dependencies for tasks==0.1.0 Searching for tinydb Reading https://pypi.python.org/simple/tinydb/ Best match: tinydb 3.9.0.post1 Downloading https://files.pythonhosted.org/packages/82/f2/c26a5c4b8486349dacc8abba33c495b77a0b67052b5c79c5d5c90da49b95/tinydb-3.9.0.post1.tar.gz#sha256=88793016ba94267e3606372e1564d4e797eae855acd5a48352011bfdcf8ee7ad Processing tinydb-3.9.0.post1.tar.gz Writing /tmp/easy_install-_cvtvm1f/tinydb-3.9.0.post1/setup.cfg Running tinydb-3.9.0.post1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-_cvtvm1f/tinydb-3.9.0.post1/egg-dist-tmp-xpn6fitk /usr/lib/python3.5/distutils/dist.py:261: UserWarning: Unknown distribution option: 'python_requires' warnings.warn(msg) zip_safe flag not set; analyzing archive contents... Installed /tmp/easy_install-_cvtvm1f/tinydb-3.9.0.post1/.eggs/pytest_runner-4.2-py3.5.egg /usr/lib/python3.5/distutils/dist.py:261: UserWarning: Unknown distribution option: 'project_urls' warnings.warn(msg) Moving tinydb-3.9.0.post1-py3.5.egg to /usr/local/lib/python3.5/dist-packages Adding tinydb 3.9.0.post1 to easy-install.pth file Installed /usr/local/lib/python3.5/dist-packages/tinydb-3.9.0.post1-py3.5.egg Searching for six==1.10.0 Best match: six 1.10.0 Adding six 1.10.0 to easy-install.pth file Using /usr/lib/python3/dist-packages Searching for click==6.7 Best match: click 6.7 Adding click 6.7 to easy-install.pth file Using /usr/local/lib/python3.5/dist-packages Finished processing dependencies for tasks==0.1.0
其他安裝方式: 在tasks_proj執行:“pip install . ” 或者 “pip install -e .”, 或者在上級目錄執行“pip install -e tasks_proj”。 -e 為editor,可以編輯原始碼。
被測程式演示:
$ tasks add "reading pytest!" --owner Andrew $ tasks add "do something else" $ tasks list IDownerdone summary ----------- ------- 1Andrew False reading pytest! 2False do something else $ tasks update 2 --owner Brian $ tasks list IDownerdone summary ----------- ------- 1Andrew False reading pytest! 2Brian False do something else $ tasks update 1 --done True $ tasks list IDownerdone summary ----------- ------- 1AndrewTrue reading pytest! 2Brian False do something else $ tasks delete 1 $ tasks list IDownerdone summary ----------- ------- 2Brian False do something else
把前面的單元測試進行彙總:
/ch2/tasks_proj/tests/unit/test_task.py
"""Test the Task data type.""" from tasks import Task def test_asdict(): """_asdict() should return a dictionary.""" t_task = Task('do something', 'okken', True, 21) t_dict = t_task._asdict() expected = {'summary': 'do something', 'owner': 'okken', 'done': True, 'id': 21} assert t_dict == expected def test_replace(): """replace() should change passed in fields.""" t_before = Task('finish book', 'brian', False) t_after = t_before._replace(id=10, done=True) t_expected = Task('finish book', 'brian', True, 10) assert t_after == t_expected def test_defaults(): """Using no parameters should invoke defaults.""" t1 = Task() t2 = Task(None, None, False, None) assert t1 == t2 def test_member_access(): """Check .field functionality of namedtuple.""" t = Task('buy milk', 'brian') assert t.summary == 'buy milk' assert t.owner == 'brian' assert (t.done, t.id) == (False, None)
執行
andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/unit$ pytest test_task.py =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 4 items test_task.py ....[100%] ======================================== 4 passed in 0.02 seconds =========================================
斷言
test_task_fail.py
from tasks import Task def test_task_equality(): """Different tasks should not be equal.""" t1 = Task('sit there', 'brian') t2 = Task('do something', 'okken') assert t1 == t2 def test_dict_equality(): """Different tasks compared as dicts should not be equal.""" t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() assert t1_dict == t2_dict
執行:
~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/unit$ pytest test_task_fail.py =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 2 items test_task_fail.py FF[100%] ================================================ FAILURES ================================================= ___________________________________________ test_task_equality ____________________________________________ def test_task_equality(): """Different tasks should not be equal.""" t1 = Task('sit there', 'brian') t2 = Task('do something', 'okken') >assert t1 == t2 EAssertionError: assert Task(summary=...alse, id=None) == Task(summary='...alse, id=None) EAt index 0 diff: 'sit there' != 'do something' EUse -v to get the full diff test_task_fail.py:9: AssertionError ___________________________________________ test_dict_equality ____________________________________________ def test_dict_equality(): """Different tasks compared as dicts should not be equal.""" t1_dict = Task('make sandwich', 'okken')._asdict() t2_dict = Task('make sandwich', 'okkem')._asdict() >assert t1_dict == t2_dict EAssertionError: assert OrderedDict([...('id', None)]) == OrderedDict([(...('id', None)]) EOmitting 3 identical items, use -vv to show EDiffering items: E{'owner': 'okken'} != {'owner': 'okkem'} EUse -v to get the full diff test_task_fail.py:16: AssertionError ======================================== 2 failed in 0.04 seconds =========================================
ofollow,noindex">更多斷言例項
預期異常
tasks/api.py的函式如下:
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
test_api_exceptions.py
"""Test for expected exceptions from using the API wrong.""" import pytest import tasks def test_add_raises(): """add() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.add(task='not a Task object') @pytest.mark.smoke def test_list_raises(): """list() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.list_tasks(owner=123) @pytest.mark.get @pytest.mark.smoke def test_get_raises(): """get() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.get(task_id='123') class TestUpdate(): """Test expected exceptions with tasks.update().""" def test_bad_id(self): """A non-int id should raise an excption.""" with pytest.raises(TypeError): tasks.update(task_id={'dict instead': 1}, task=tasks.Task()) def test_bad_task(self): """A non-Task task should raise an excption.""" with pytest.raises(TypeError): tasks.update(task_id=1, task='not a task') def test_delete_raises(): """delete() should raise an exception with wrong type param.""" with pytest.raises(TypeError): tasks.delete(task_id=(1, 2, 3)) def test_start_tasks_db_raises(): """Make sure unsupported db raises an exception.""" 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'"
標記測試函式
基於標籤實現,參見上面程式碼。
andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$pytest test_api_exceptions.py =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 7 items test_api_exceptions.py .......[100%] ======================================== 7 passed in 0.03 seconds ========================================= andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_api_exceptions.py-v -m "smoke" =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python3 cachedir: ../.pytest_cache rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 7 items / 5 deselected test_api_exceptions.py::test_list_raises PASSED[ 50%] test_api_exceptions.py::test_get_raises PASSED[100%] ================================= 2 passed, 5 deselected in 0.02 seconds ================================== andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_api_exceptions.py-v -m "smoke and get" =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python3 cachedir: ../.pytest_cache rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 7 items / 6 deselected test_api_exceptions.py::test_get_raises PASSED[100%] ================================= 1 passed, 6 deselected in 0.01 seconds ================================== andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_api_exceptions.py-v -m "smoke and not get" =========================================== test session starts =========================================== platform linux -- Python 3.5.2, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/bin/python3 cachedir: ../.pytest_cache rootdir: /home/andrew/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini collected 7 items / 6 deselected test_api_exceptions.py::test_list_raises PASSED[100%] ================================= 1 passed, 6 deselected in 0.01 seconds ================================== andrew@andrew-PowerEdge-T630:~/code/china-testing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ $ pytest -v -m smoke ======================================================== test session starts ========================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: ../.pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 50 items / 47 deselected test_add.py::test_added_task_has_id_set PASSED[ 33%] test_api_exceptions.py::test_list_raises PASSED[ 66%] test_api_exceptions.py::test_get_raises PASSED[100%] ============================================== 3 passed, 47 deselected in 0.07 seconds ===============================================
忽略測試
test_unique_id_1.py
# 技術支援 釘釘群:21745728(可以加釘釘pythontesting邀請加入) # qq群:144081101 591302926567351477 """Test tasks.unique_id().""" import pytest import tasks def test_unique_id(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 @pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """Connect to db before testing, disconnect after.""" tasks.start_tasks_db(str(tmpdir), 'tiny') yield tasks.stop_tasks_db()
執行:
andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_unique_id_1.py ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 1 item test_unique_id_1.py F[100%] ================================================================== FAILURES ================================================================== _______________________________________________________________ test_unique_id _______________________________________________________________ def test_unique_id(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() >assert id_1 != id_2 Eassert 1 != 1 test_unique_id_1.py:11: AssertionError ========================================================== 1 failed in 0.08 seconds ==========================================================
上述用例沒有通過,我們現在想暫時不執行。
test_unique_id_2.py
# 技術支援 釘釘群:21745728(可以加釘釘pythontesting邀請加入) # qq群:144081101 591302926567351477 """Test tasks.unique_id().""" import pytest import tasks from tasks import Task @pytest.mark.skip(reason='misunderstood the API') def test_unique_id_1(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 def test_unique_id_2(): """unique_id() should return an unused id.""" ids = [] ids.append(tasks.add(Task('one'))) ids.append(tasks.add(Task('two'))) ids.append(tasks.add(Task('three'))) # grab a unique id uid = tasks.unique_id() # make sure it isn't in the list of existing ids assert uid not in ids @pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """Connect to db before testing, disconnect after.""" tasks.start_tasks_db(str(tmpdir), 'tiny') yield tasks.stop_tasks_db()
執行:
$ pytest test_unique_id_2.py ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 2 items test_unique_id_2.py s.[100%] ==================================================== 1 passed, 1 skipped in 0.03 seconds =====================================================
skipif可以基於條件,比如基於版本號忽略用例。
test_unique_id_3.py
# 技術支援 釘釘群:21745728(可以加釘釘pythontesting邀請加入) # qq群:144081101 591302926567351477 """Test tasks.unique_id().""" import pytest import tasks from tasks import Task @pytest.mark.skipif(tasks.__version__ < '0.2.0', reason='not supported until version 0.2.0') def test_unique_id_1(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 def test_unique_id_2(): """unique_id() should return an unused id.""" ids = [] ids.append(tasks.add(Task('one'))) ids.append(tasks.add(Task('two'))) ids.append(tasks.add(Task('three'))) # grab a unique id uid = tasks.unique_id() # make sure it isn't in the list of existing ids assert uid not in ids @pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """Connect to db before testing, disconnect after.""" tasks.start_tasks_db(str(tmpdir), 'tiny') yield tasks.stop_tasks_db()
執行:
andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_unique_id_3.py -v ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: ../.pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 2 items test_unique_id_3.py::test_unique_id_1 SKIPPED[ 50%] test_unique_id_3.py::test_unique_id_2 PASSED[100%] ==================================================== 1 passed, 1 skipped in 0.03 seconds ===================================================== andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_unique_id_3.py -rs ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 2 items test_unique_id_3.py s.[100%] ========================================================== short test summary info =========================================================== SKIP [1] func/test_unique_id_3.py:8: not supported until version 0.2.0 ==================================================== 1 passed, 1 skipped in 0.03 seconds ===================================================== $ pytest --help ... -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. ...
預期失敗
上例中xfail可以標識在0.2.0失敗,以上成功。
test_unique_id_4.py
# 技術支援 釘釘群:21745728(可以加釘釘pythontesting邀請加入) # qq群:144081101 591302926567351477 """Test tasks.unique_id().""" import pytest import tasks from tasks import Task @pytest.mark.xfail(tasks.__version__ < '0.2.0', reason='not supported until version 0.2.0') def test_unique_id_1(): """Calling unique_id() twice should return different numbers.""" id_1 = tasks.unique_id() id_2 = tasks.unique_id() assert id_1 != id_2 @pytest.mark.xfail() def test_unique_id_is_a_duck(): """Demonstrate xfail.""" uid = tasks.unique_id() assert uid == 'a duck' @pytest.mark.xfail() def test_unique_id_not_a_duck(): """Demonstrate xpass.""" uid = tasks.unique_id() assert uid != 'a duck' def test_unique_id_2(): """unique_id() should return an unused id.""" ids = [] ids.append(tasks.add(Task('one'))) ids.append(tasks.add(Task('two'))) ids.append(tasks.add(Task('three'))) # grab a unique id uid = tasks.unique_id() # make sure it isn't in the list of existing ids assert uid not in ids @pytest.fixture(autouse=True) def initialized_tasks_db(tmpdir): """Connect to db before testing, disconnect after.""" tasks.start_tasks_db(str(tmpdir), 'tiny') yield tasks.stop_tasks_db()
執行:
c$ pytest test_unique_id_4.py ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 4 items test_unique_id_4.py xxX.[100%] =============================================== 1 passed, 2 xfailed, 1 xpassed in 0.10 seconds =============================================== andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests/func$ pytest test_unique_id_4.py -v ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: ../.pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 4 items test_unique_id_4.py::test_unique_id_1 xfail[ 25%] test_unique_id_4.py::test_unique_id_is_a_duck xfail[ 50%] test_unique_id_4.py::test_unique_id_not_a_duck XPASS[ 75%] test_unique_id_4.py::test_unique_id_2 PASSED[100%] =============================================== 1 passed, 2 xfailed, 1 xpassed in 0.11 seconds ===============================================
在pytest.ini設定
[pytest] xfail_strict=true
xfail會置為FAIL。
批量執行
- 單個目錄
andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj$ pytesttests/func --tb=no ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 50 items tests/func/test_add.py ..[4%] tests/func/test_add_variety.py ................................[ 68%] tests/func/test_api_exceptions.py .......[ 82%] tests/func/test_unique_id_1.py F[ 84%] tests/func/test_unique_id_2.py s.[ 88%] tests/func/test_unique_id_3.py s.[ 92%] tests/func/test_unique_id_4.py xxX.[100%] ==================================== 1 failed, 44 passed, 2 skipped, 2 xfailed, 1 xpassed in 0.31 seconds ==================================== andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj$ pytesttests/func --tb=no -v ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: tests/.pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 50 items tests/func/test_add.py::test_add_returns_valid_id PASSED[2%] tests/func/test_add.py::test_added_task_has_id_set PASSED[4%] tests/func/test_add_variety.py::test_add_1 PASSED[6%] tests/func/test_add_variety.py::test_add_2[task0] PASSED[8%] tests/func/test_add_variety.py::test_add_2[task1] PASSED[ 10%] tests/func/test_add_variety.py::test_add_2[task2] PASSED[ 12%] tests/func/test_add_variety.py::test_add_2[task3] PASSED[ 14%] tests/func/test_add_variety.py::test_add_3[sleep-None-False] PASSED[ 16%] tests/func/test_add_variety.py::test_add_3[wake-brian-False] PASSED[ 18%] tests/func/test_add_variety.py::test_add_3[breathe-BRIAN-True] PASSED[ 20%] tests/func/test_add_variety.py::test_add_3[eat eggs-BrIaN-False] PASSED[ 22%] tests/func/test_add_variety.py::test_add_4[task0] PASSED[ 24%] tests/func/test_add_variety.py::test_add_4[task1] PASSED[ 26%] tests/func/test_add_variety.py::test_add_4[task2] PASSED[ 28%] tests/func/test_add_variety.py::test_add_4[task3] PASSED[ 30%] tests/func/test_add_variety.py::test_add_4[task4] PASSED[ 32%] tests/func/test_add_variety.py::test_add_5[Task(sleep,None,True)] PASSED[ 34%] tests/func/test_add_variety.py::test_add_5[Task(wake,brian,False)0] PASSED[ 36%] tests/func/test_add_variety.py::test_add_5[Task(wake,brian,False)1] PASSED[ 38%] tests/func/test_add_variety.py::test_add_5[Task(breathe,BRIAN,True)] PASSED[ 40%] tests/func/test_add_variety.py::test_add_5[Task(exercise,BrIaN,False)] PASSED[ 42%] tests/func/test_add_variety.py::test_add_6[just summary] PASSED[ 44%] tests/func/test_add_variety.py::test_add_6[summary/owner] PASSED[ 46%] tests/func/test_add_variety.py::test_add_6[summary/owner/done] PASSED[ 48%] tests/func/test_add_variety.py::TestAdd::test_equivalent[Task(sleep,None,True)] PASSED[ 50%] tests/func/test_add_variety.py::TestAdd::test_equivalent[Task(wake,brian,False)0] PASSED[ 52%] tests/func/test_add_variety.py::TestAdd::test_equivalent[Task(wake,brian,False)1] PASSED[ 54%] tests/func/test_add_variety.py::TestAdd::test_equivalent[Task(breathe,BRIAN,True)] PASSED[ 56%] tests/func/test_add_variety.py::TestAdd::test_equivalent[Task(exercise,BrIaN,False)] PASSED[ 58%] tests/func/test_add_variety.py::TestAdd::test_valid_id[Task(sleep,None,True)] PASSED[ 60%] tests/func/test_add_variety.py::TestAdd::test_valid_id[Task(wake,brian,False)0] PASSED[ 62%] tests/func/test_add_variety.py::TestAdd::test_valid_id[Task(wake,brian,False)1] PASSED[ 64%] tests/func/test_add_variety.py::TestAdd::test_valid_id[Task(breathe,BRIAN,True)] PASSED[ 66%] tests/func/test_add_variety.py::TestAdd::test_valid_id[Task(exercise,BrIaN,False)] PASSED[ 68%] tests/func/test_api_exceptions.py::test_add_raises PASSED[ 70%] tests/func/test_api_exceptions.py::test_list_raises PASSED[ 72%] tests/func/test_api_exceptions.py::test_get_raises PASSED[ 74%] tests/func/test_api_exceptions.py::TestUpdate::test_bad_id PASSED[ 76%] tests/func/test_api_exceptions.py::TestUpdate::test_bad_task PASSED[ 78%] tests/func/test_api_exceptions.py::test_delete_raises PASSED[ 80%] tests/func/test_api_exceptions.py::test_start_tasks_db_raises PASSED[ 82%] tests/func/test_unique_id_1.py::test_unique_id FAILED[ 84%] tests/func/test_unique_id_2.py::test_unique_id_1 SKIPPED[ 86%] tests/func/test_unique_id_2.py::test_unique_id_2 PASSED[ 88%] tests/func/test_unique_id_3.py::test_unique_id_1 SKIPPED[ 90%] tests/func/test_unique_id_3.py::test_unique_id_2 PASSED[ 92%] tests/func/test_unique_id_4.py::test_unique_id_1 xfail[ 94%] tests/func/test_unique_id_4.py::test_unique_id_is_a_duck xfail[ 96%] tests/func/test_unique_id_4.py::test_unique_id_not_a_duck XPASS[ 98%] tests/func/test_unique_id_4.py::test_unique_id_2 PASSED[100%] ==================================== 1 failed, 44 passed, 2 skipped, 2 xfailed, 1 xpassed in 0.34 seconds ====================================
- 單個檔案/模組
andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj$ pytest tests/func/test_add.py ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 2 items tests/func/test_add.py ..[100%]
- 單個函式
$ pytest tests/func/test_add.py::test_add_returns_valid_id -v ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: tests/.pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 1 item tests/func/test_add.py::test_add_returns_valid_id PASSED[100%] ========================================================== 1 passed in 0.03 seconds ========================================================== [100%]
- 單個類
$ pytest tests/func/test_api_exceptions.py::TestUpdate ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 2 items tests/func/test_api_exceptions.py ..[100%] ========================================================== 2 passed in 0.01 seconds ==========================================================
- 單個類的測試方法
andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj$ pytest tests/func/test_api_exceptions.py::TestUpdate::test_bad_id ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj/tests, inifile: pytest.ini plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 1 item tests/func/test_api_exceptions.py .[100%] ========================================================== 1 passed in 0.01 seconds ==========================================================
- 基於測試名
$ pytest -v -k _raises ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: .pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj, inifile: plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 56 items / 51 deselected tests/func/test_api_exceptions.py::test_add_raises PASSED[ 20%] tests/func/test_api_exceptions.py::test_list_raises PASSED[ 40%] tests/func/test_api_exceptions.py::test_get_raises PASSED[ 60%] tests/func/test_api_exceptions.py::test_delete_raises PASSED[ 80%] tests/func/test_api_exceptions.py::test_start_tasks_db_raises PASSED[100%] ================================================== 5 passed, 51 deselected in 0.12 seconds =================================================== andrew@andrew-PowerEdge-T630:~/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj$ pytest -v -k "_raises and not delete" ============================================================ test session starts ============================================================= platform linux -- Python 3.6.5, pytest-3.5.1, py-1.5.3, pluggy-0.6.0 -- /usr/local/anaconda3/bin/python cachedir: .pytest_cache metadata: {'Python': '3.6.5', 'Platform': 'Linux-4.4.0-130-generic-x86_64-with-debian-stretch-sid', 'Packages': {'pytest': '3.5.1', 'py': '1.5.3', 'pluggy': '0.6.0'}, 'Plugins': {'remotedata': '0.2.1', 'openfiles': '0.3.0', 'metadata': '1.7.0', 'html': '1.19.0', 'doctestplus': '0.1.3', 'arraydiff': '0.2'}, 'JAVA_HOME': '/usr/lib/jvm/java-8-oracle/jre/bin'} rootdir: /home/andrew/code/python-api-tesing/python3_libraries/pytest_testing/ch2/tasks_proj, inifile: plugins: remotedata-0.2.1, openfiles-0.3.0, metadata-1.7.0, html-1.19.0, doctestplus-0.1.3, arraydiff-0.2 collected 56 items / 52 deselected tests/func/test_api_exceptions.py::test_add_raises PASSED[ 25%] tests/func/test_api_exceptions.py::test_list_raises PASSED[ 50%] tests/func/test_api_exceptions.py::test_get_raises PASSED[ 75%] tests/func/test_api_exceptions.py::test_start_tasks_db_raises PASSED[100%] ================================================== 4 passed, 52 deselected in 0.06 seconds ===================================================
資料驅動(引數化)
參考資料
- 緊張整理更新中,討論 釘釘免費群21745728 qq群144081101 567351477
- 本文最新版本地址
- 本文英文原版書籍
- 本文原始碼地址
- 本文涉及的python測試開發庫 謝謝點贊!
- 本文相關海量書籍下載