第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
└── ...
安装:
# python setup.py install
...
Successfully built tasks
Installing collected packages: tinydb, tasks
Successfully installed tasks-0.1.0 tinydb-3.15.1
其他安装方式: 在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
ID owner done summary
-- ----- ---- -------
1 Andrew False reading pytest!
2 False do something else
$ tasks update 2 --owner Brian
$ tasks list
ID owner done summary
-- ----- ---- -------
1 Andrew False reading pytest!
2 Brian False do something else
$ tasks update 1 --done True
$ tasks list
ID owner done summary
-- ----- ---- -------
1 Andrew True reading pytest!
2 Brian False do something else
$ tasks delete 1
$ tasks list
ID owner done summary
-- ----- ---- -------
2 Brian False do something else
把前面的单元测试进行汇总:
/ch2/tasks_proj/tests/unit/test_task.py
# 讨论钉钉免费群21745728 qq群144081101 567351477
"""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
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_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
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_task_fail.py:16: AssertionError
======================================== 2 failed in 0.04 seconds =========================================
更多断言实例
预期异常
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 591302926 567351477
"""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
E assert 1 != 1
test_unique_id_1.py:11: AssertionError
========================================================== 1 failed in 0.08 seconds ==========================================================
上述用例没有通过,我们现在想暂时不执行。
test_unique_id_2.py
# 技术支持 钉钉群:21745728(可以加钉钉pythontesting邀请加入)
# qq群:144081101 591302926 567351477
"""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 591302926 567351477
"""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 591302926 567351477
"""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$ pytest tests/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$ pytest tests/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 ===================================================
数据驱动(参数化)
test_add_variety.py
"""Test the tasks.add() API function."""
import pytest
import tasks
from tasks import Task
def test_add_1():
"""tasks.get() using id returned from add() works."""
task = Task('breathe', 'BRIAN', True)
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
# everything but the id should be the same
assert equivalent(t_from_db, task)
def equivalent(t1, t2):
"""Check two tasks for equivalence."""
# Compare everything but the id field
return ((t1.summary == t2.summary) and
(t1.owner == t2.owner) and
(t1.done == t2.done))
@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.mark.parametrize('task',
[Task('sleep', done=True),
Task('wake', 'brian'),
Task('breathe', 'BRIAN', True),
Task('exercise', 'BrIaN', False)])
def test_add_2(task):
"""Demonstrate parametrize with one parameter."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
@pytest.mark.parametrize('summary, owner, done',
[('sleep', None, False),
('wake', 'brian', False),
('breathe', 'BRIAN', True),
('eat eggs', 'BrIaN', False),
])
def test_add_3(summary, owner, done):
"""Demonstrate parametrize with multiple parameters."""
task = Task(summary, owner, done)
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
tasks_to_try = (Task('sleep', done=True),
Task('wake', 'brian'),
Task('wake', 'brian'),
Task('breathe', 'BRIAN', True),
Task('exercise', 'BrIaN', False))
@pytest.mark.parametrize('task', tasks_to_try)
def test_add_4(task):
"""Slightly different take."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
task_ids = ['Task({},{},{})'.format(t.summary, t.owner, t.done)
for t in tasks_to_try]
@pytest.mark.parametrize('task', tasks_to_try, ids=task_ids)
def test_add_5(task):
"""Demonstrate ids."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
@pytest.mark.parametrize('task', [
pytest.param(Task('create'), id='just summary'),
pytest.param(Task('inspire', 'Michelle'), id='summary/owner'),
pytest.param(Task('encourage', 'Michelle', True), id='summary/owner/done')])
def test_add_6(task):
"""Demonstrate pytest.param and id."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
@pytest.mark.parametrize('task', tasks_to_try, ids=task_ids)
class TestAdd():
"""Demonstrate parametrize and test classes."""
def test_equivalent(self, task):
"""Similar test, just within a class."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert equivalent(t_from_db, task)
def test_valid_id(self, task):
"""We can use the same data for multiple tests."""
task_id = tasks.add(task)
t_from_db = tasks.get(task_id)
assert t_from_db.id == task_id
自定义输入的执行方法:$ pytest -v "test_add_variety.py::test_add_5[Task(exercise,BrIaN,False)]"
参考资料
- 本文最新版本地址
- 本文英文原版书籍
- 本文源码地址
- 本文涉及的python测试开发库 谢谢点赞!
- 本文相关海量书籍下载