1. pytest -- installation and getting started

Posted by Fergusfer on Fri, 25 Oct 2019 03:40:24 +0200

Article directory


pytest is a framework that can simplify the construction of test system and facilitate the scale expansion of test. It makes test more expressive and readable - template code is no longer necessary.

In just a few minutes, you can start a simple unit test or complex function test on your application.

1. installation

  • The command line executes the following command: pipenv install pytest==5.1.3

  • View the installed version information: pipenv run pytest --version

2. Create your first test case

It has only four lines of code:

# src/chapter-1/test_sample.py

def func(x):
    return x + 1


def test_sample():
    assert func(3) == 5

Perform the test with the following command:

λ pipenv run pytest src/chapter-1/test_sample.py
============================= test session starts ============================== 
platform win32 -- Python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0
rootdir: D:\Personal Files\Projects\pytest-chinese-doc
collected 1 item

src\chapter-1\test_sample.py F                                            [100%]

=================================== FAILURES =================================== 
_________________________________ test_sample __________________________________

    def test_sample():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)

src\chapter-1\test_sample.py:28: AssertionError
============================== 1 failed in 0.05s ===============================

pytest returns a failed test report because func(3) is not equal to 5.

3. Execute multiple test cases

Execute the pipenv run py test command, which will execute all files in the current and its subfolders named in accordance with the rules of test *. Py or * _test.py;

4. Trigger an assertion of the specified exception

Use raises to check whether the code throws a specified exception:

# src/chapter-1/test_sysexit.py

import pytest


def f():
    # Interpreter request exit
    raise SystemExit(1)


def test_mytest():
    with pytest.raises(SystemExit):
        f()

When executing this test case, add the - q option to view the simplified test report:

λ pipenv run pytest -q src/chapter-1/test_sysexit.py
.                                                                         [100%] 
1 passed in 0.01s

5. Organize multiple test cases in a class

pytest allows you to easily include multiple test cases by creating a test class:

# src/chapter-1/test_class.py

class TestClass:
    def test_one(self):
        x = 'this'
        assert 'h' in x

    def test_two(self):
        x = 'hello'
        assert hasattr(x, 'check')

Now let's execute this test case:

λ pipenv run pytest -q src/chapter-1/test_class.py
.F                                                                        [100%] 
=================================== FAILURES =================================== 
______________________________ TestClass.test_two ______________________________

self = <test_class.TestClass object at 0x000001D364778E48>

    def test_two(self):
        x = 'hello'
>       assert hasattr(x, 'check')
E       AssertionError: assert False
E        +  where False = hasattr('hello', 'check')

src\chapter-1\test_class.py:30: AssertionError
1 failed, 1 passed in 0.05s

From the output report, we can see:

  • Test one is passed, represented by; test two is failed, represented by F;
  • It can be seen from the clearing that the reason for test two failure is: false = hasattr ('Hello ',' check ');

Be careful:

The test class must conform to specific rules before pytest can discover it:

  • The commands of the Test class should conform to the Test * rule;
  • The test class cannot have an init method.

6. Apply for a unique temporary directory

pytest provides some built-in fixtures that can be used to request some system resources. For example, a unique temporary directory:

# src/chapter-1/test_tmpdir.py

def test_needsfiles(tmpdir):
    print(tmpdir)
    assert 0

In the test case, the built-in tempdir fixture is used as a parameter. pytest will create a directory in advance and pass in a py.path.local object as an argument.

Now, let's execute this test case:

λ pipenv run pytest -q src/chapter-1/test_tmpdir.py
F                                                                         [100%] 
=================================== FAILURES =================================== 
_______________________________ test_needsfiles ________________________________

tmpdir = local('C:\\Users\\luyao\\AppData\\Local\\Temp\\pytest-of-luyao\\pytest-1\\test_needsfiles0')

    def test_needsfiles(tmpdir):
        print(tmpdir)
>       assert 0
E       assert 0

src\chapter-1\test_tmpdir.py:25: AssertionError
----------------------------- Captured stdout call ----------------------------- C:\Users\luyao\AppData\Local\Temp\pytest-of-luyao\pytest-1\test_needsfiles0
1 failed in 0.05s

You can use the following command to view all the available fixtures. If you want to view the fixtures starting with "at the same time, you need to add the - v option:

λ pipenv run pytest -q -v --fixtures
============================= test session starts ============================== 
platform win32 -- Python 3.7.3, pytest-5.1.3, py-1.8.0, pluggy-0.13.0
rootdir: D:\Personal Files\Projects\pytest-chinese-doc
collected 5 items
cache
    Return a cache object that can persist state between testing sessions.

    cache.get(key, default)
    cache.set(key, value)

    Keys must be a ``/`` separated value, where the first part is usually the
    name of your plugin or application to avoid clashes with other cache users.

    Values can be any object handled by the json stdlib module.

capsys
    Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.

    The captured output is made available via ``capsys.readouterr()`` method
    calls, which return a ``(out, err)`` namedtuple.
    ``out`` and ``err`` will be ``text`` objects.

capsysbinary
    Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.

    The captured output is made available via ``capsysbinary.readouterr()``
    method calls, which return a ``(out, err)`` namedtuple.
    ``out`` and ``err`` will be ``bytes`` objects.

capfd
    Enable text capturing of writes to file descriptors ``1`` and ``2``.

    The captured output is made available via ``capfd.readouterr()`` method
    calls, which return a ``(out, err)`` namedtuple.
    ``out`` and ``err`` will be ``text`` objects.

capfdbinary
    Enable bytes capturing of writes to file descriptors ``1`` and ``2``.

    The captured output is made available via ``capfd.readouterr()`` method
    calls, which return a ``(out, err)`` namedtuple.
    ``out`` and ``err`` will be ``byte`` objects.

doctest_namespace [session scope]
    Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.

pytestconfig [session scope]
    Session-scoped fixture that returns the :class:`_pytest.config.Config` object.

    Example::

        def test_foo(pytestconfig):
            if pytestconfig.getoption("verbose") > 0:
                ...

record_property
    Add an extra properties the calling test.
    User properties become part of the test report and are available to the
    configured reporters, like JUnit XML.
    The fixture is callable with ``(name, value)``, with value being automatically
    xml-encoded.

    Example::

        def test_function(record_property):
            record_property("example_key", 1)

record_xml_attribute
    Add extra xml attributes to the tag for the calling test.
    The fixture is callable with ``(name, value)``, with value being
    automatically xml-encoded

record_testsuite_property [session scope]
    Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
    writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.

    This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:

    .. code-block:: python

        def test_foo(record_testsuite_property):
            record_testsuite_property("ARCH", "PPC")
            record_testsuite_property("STORAGE_TYPE", "CEPH")

    ``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.

caplog
    Access and control log capturing.

    Captured logs are available through the following properties/methods::

    * caplog.text            -> string containing formatted log output
    * caplog.records         -> list of logging.LogRecord instances
    * caplog.record_tuples   -> list of (logger_name, level, message) tuples
    * caplog.clear()         -> clear captured records and formatted log output string

monkeypatch
    The returned ``monkeypatch`` fixture provides these
    helper methods to modify objects, dictionaries or os.environ::

        monkeypatch.setattr(obj, name, value, raising=True)
        monkeypatch.delattr(obj, name, raising=True)
        monkeypatch.setitem(mapping, name, value)
        monkeypatch.delitem(obj, name, raising=True)
        monkeypatch.setenv(name, value, prepend=False)
        monkeypatch.delenv(name, raising=True)
        monkeypatch.syspath_prepend(path)
        monkeypatch.chdir(path)

    All modifications will be undone after the requesting
    test function or fixture has finished. The ``raising``
    parameter determines if a KeyError or AttributeError
    will be raised if the set/deletion operation has no target.

recwarn
    Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.

    See http://docs.python.org/library/warnings.html for information
    on warning categories.

tmpdir_factory [session scope]
    Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.

tmp_path_factory [session scope]
    Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.

tmpdir
    Return a temporary directory path object
    which is unique to each test function invocation,
    created as a sub directory of the base temporary
    directory.  The returned object is a `py.path.local`_
    path object.

    .. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html

tmp_path
    Return a temporary directory path object
    which is unique to each test function invocation,
    created as a sub directory of the base temporary
    directory.  The returned object is a :class:`pathlib.Path`
    object.

    .. note::

        in python < 3.6 this is a pathlib2.Path


============================ no tests ran in 0.10s =============================

GitHub warehouse address: https://github.com/luizyao/pytest-chinese-doc

Topics: Session Python xml Junit