目录
安装和入门
- Python版本:Python 3.5, 3.6, 3.7, PyPy3
- 平台: Linux或者Windows
- PyPI包:pytest
pytest是一个测试框架,它能够简化测试系统的构建,和规模化测试的组织。测试系统将会变得更具有表现力和可读性———不再需要通过阅读模版代码来了解系统。只需要几分钟的时间,就可以开始对你的应用做一个简单的单元测试或者复杂的功能测试。
安装pytest
在你的命令行中执行如下命令:
pip install -U pytest
检查pytest的版本信息:
$ pytest --version This is pytest version 5.1.2, imported from $PYTHON_PREFIX/lib/python3.7/site-packages/pytest.py
创建你的第一个测试用例
创建一个简单的测试用例,它只有四行代码:
# test_sample.py
def func(x):
return x + 1
def test_sample():
assert func(3) == 5
现在你可以执行这个测试用例:
/d/Personal Files/Python/pytest-chinese-doc/src (5.1.2)
λ pytest test_sample.py
================================================= test session starts =================================================
platform win32 -- Python 3.7.3, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\Personal Files\Python\pytest-chinese-doc\src
collected 1 item
test_sample.py F [100%]
====================================================== FAILURES =======================================================
_____________________________________________________ test_sample _____________________________________________________
def test_sample():
> assert func(3) == 5
E assert 4 == 5
E + where 4 = func(3)
test_sample.py:28: AssertionError
================================================== 1 failed in 0.07s ==================================================
pytest返回一个失败的测试报告,因为func(3)
不等于5
执行多个测试用例
在当前文件夹和子文件夹中,pytest会执行所有符合test_*.py
和*_test.py
命名规则的文件。一般来说,其遵循标准的测试发现规则。
检查代码是否触发一个指定的异常
使用raises
可以检查代码是否抛出一个指定的异常:
# test_sysexit.py
import pytest
def f():
# 解释器请求退出
raise SystemExit(1)
def test_mytest():
with pytest.raises(SystemExit):
f()
执行这个测试用例,加上-q
选项可以减少不必要的日志输出:
/d/Personal Files/Python/pytest-chinese-doc/src (5.1.2)
λ pytest -q test_sysexit.py
. [100%] 1 passed in 0.01s
在一个类中组织多个测试用例
当你需要新建多个相似的测试用例时,pytest可以让你很容易的通过创建一个测试类来包含所有的测试用例:
测试类的命名也有确定的规则,通常需要以
Test
开头或结尾;
# 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')
pytest可以发现测试类中所有以test_
开头的实例函数,查找过程遵循Python发现测试的约定,你只需要通过传入具体的文件名来执行这些测试:
/d/Personal Files/Python/pytest-chinese-doc/src (5.1.2)
λ pytest test_class.py
================================================= test session starts =================================================
platform win32 -- Python 3.7.3, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\Personal Files\Python\pytest-chinese-doc\src
collected 2 items
test_class.py .F [100%]
====================================================== FAILURES ======================================================= _________________________________________________ TestClass.test_two __________________________________________________
self = <test_class.TestClass object at 0x00000200EFA83550>
def test_two(self):
x = 'hello'
> assert hasattr(x, 'check')
E AssertionError: assert False
E + where False = hasattr('hello', 'check')
test_class.py:30: AssertionError
============================================= 1 failed, 1 passed in 0.05s =============================================
第一个用例测试通过,第二个用例测试失败。并且,你可以很清楚的看到失败断言处判断的依据。
申请一个唯一的临时目录用于功能测试
pytest提供一些内置的fixture,以参数的形式来请求任意资源,例如请求一个唯一的临时性目录:
# test_tmpdir.py
def test_needsfiles(tmpdir):
print(type(tmpdir))
print(tmpdir)
assert 0
在测试用例执行前,pytest会查找并调用工厂函数tmpdir
来创建一个的临时性目录,并返回其路径对象:
/d/Personal Files/Python/pytest-chinese-doc/src (5.1.2)
λ pytest -q test_tmpdir.py
F [100%] ====================================================== FAILURES ======================================================= ___________________________________________________ test_needsfiles ___________________________________________________
tmpdir = local('C:\\Users\\luyao\\AppData\\Local\\Temp\\pytest-of-luyao\\pytest-0\\test_needsfiles0')
def test_needsfiles(tmpdir):
print(tmpdir)
> assert 0
E assert 0
test_tmpdir.py:25: AssertionError
------------------------------------------------ Captured stdout call -------------------------------------------------
<class 'py._path.local.LocalPath'>
C:\Users\luyao\AppData\Local\Temp\pytest-of-luyao\pytest-0\test_needsfiles0
1 failed in 0.05s
查找有哪些可用的fixture
:
λ pytest --fixtures # 内置的和自定义的
================================================= test session starts =================================================
platform win32 -- Python 3.7.3, pytest-5.1.2, py-1.8.0, pluggy-0.12.0
rootdir: D:\Personal Files\Python\pytest-chinese-doc\src
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 ================================================
这个命令会忽略以_
开头的fixture
,你可以通过添加-v
选项来查看它们;