This page looks best with JavaScript enabled

Getting Started with Pytest

The Pytest framework is simple to use, rich in plugins, and powerful, and it is widely used for Python automated testing. This article introduces some basic concepts and usage of Pytest.

1. How It Runs

Step one, Pytest reads its configuration from the command line or a file.

Step two, it looks for and imports conftest.py files in the specified directory.

Step three, it finds test files that match the criteria, usually py files starting with test_.

Step four, it executes session or module level fixtures.

Step four, it finds and runs the test cases defined in classes and functions.

2. The pytest.ini and conftest.py Files

First, let’s look at how test files are organized:

1
2
3
4
5
6
7
8
/ -
  | - pytest.ini  # pytest 的配置文件
  | - tests
    |
    | - conftest.py  # 全局通用的配置和功能
    | - fun_module   # 某个模块的测试
          | - test_a.py  # 该模块下的测试
          | - conftest.py  # 该模块下通用的配置和功能

When running Pytest, you can pass runtime parameters on the command line, and you can also use a configuration file. The order in which Pytest searches for configuration files is:

1
2
3
4
5
path/pytest.ini
path/setup.cfg     # must also contain [pytest] section to match
path/tox.ini       # must also contain [pytest] section to match
pytest.ini
...                # all the way down to the root

Usually you place a pytest.ini file in the project and configure the relevant parameters there.

pytest.ini:

1
2
3
4
5
6
7
[pytest]
# 指定测试目录
testpaths  = tests
# 指定测试用例文件的命名格式
python_files = test_*.py
# 指定 conftest 文件的路径
pytest_plugins = tests

tests/conftest.py, the global dependency configuration

1
2
def pytest_configure():
    pass

When running the tests, execute the command:

1
# pytest . -s

3. pytest.fixture

A fixture is a concept introduced by Pytest and one of the powerful features it provides. Let’s look at how it is used:

3.1 Using It Directly as a Constant

1
2
3
4
5
6
@pytest.fixture()
def remote_api():
    return 'success'

def test_remote_api(remote_api):
    assert remote_api == 'success'

3.2 Running It as a Setup Function

A fixture lets you run some preparatory actions before a test case executes.

1
2
3
4
5
6
7
8
9
import pytest

@pytest.fixture()
def before():
    pass

@pytest.mark.usefixtures("before")
def test_1():
    pass

With autouse and scope, you can handle the preparation for many test cases.

3.3 Scope

The scope is declared with the scope parameter. There are four options, and the default is function:

  • function, function level, executed once for every test function
  • class, class level, executed once per test class, available to all its methods
  • module, module level, executed once per module, available to all functions and methods in the module
  • session, session level, executed only once per test run, available to all functions and methods that are found
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
@pytest.fixture(scope='function')
def func_scope():
    pass

@pytest.fixture(scope='module')
def mod_scope():
    pass

@pytest.fixture(scope='session')
def sess_scope():
    pass

@pytest.fixture(scope='class')
def class_scope():
    pass

4. pytest.mark

pytest.mark is used to mark test cases, giving you finer-grained control over them.

A marker does not need to be defined beforehand to be used. Here is an example:

1
2
3
4
5
6
7
import pytest

A = pytest.mark.A

@A
def test_A():
    assert True

Some built-in markers:

  • skip, skips the decorated test case
  • skipif, takes a condition and skips the test when it is met
  • xfail, treats a failure as a pass and a success as a failure
  • parametrize, supplies data to a test case in batches. If the parameter name of parametrize is the same as a fixture name, it overrides the fixture.
1
2
3
4
5
6
@pytest.mark.parametrize('name',
                      ['12345',
                       'abcdef',
                       '0a1b2c3'])
def test_name_length(passwd):
    assert len(passwd) == 6

5. Common Plugins

5.1 pytest-cov

pytest-cov is a plugin that automatically measures test coverage. Example usage:

1
# pytest --cov=myproj tests/

5.2 pytest-mock

Mocking is meant to shield a test from some of its dependencies. A dependency should have its own test cases; each test only needs to care about whether its own functionality works. Example usage:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import os

class UnixFS:

    @staticmethod
    def rm(filename):
        os.remove(filename)

def test_unix_fs(mocker):
    mocker.patch('os.remove')
    UnixFS.rm('file')
    os.remove.assert_called_once_with('file')

5.3 pytest-html

pytest-html is a plugin that automatically generates test reports in HTML format. Example usage:

1
# pytest --html=report.html

5.4 pytest-django

pytest-django adds Pytest support to Django applications and projects. Specifically, pytest-django brings the ability to test Django projects with pytest fixtures, and it runs faster than the standard Django test suite.


微信公众号
WRITTEN BY
微信公众号