自动化测试框架工具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
└── ...


安装:


# 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测试开发库 谢谢点赞!
  • 本文相关海量书籍下载

你可能感兴趣的:(自动化测试框架工具pytest教程2-测试函数)