Using pytest with an existing test suite¶
pytest可以运行既有unittest或者nose写成的测试用例。建议把受测代码以及测试用例安装到在虚拟环境中,这样一来可以避免修改sys.path,二来可以避免多次安装:
cd <repository>
pip install -e . # Environment dependent alternatives include
# 'python setup.py develop' and 'conda develop'
另一个选择是使用tox
The writing and reporting of assertions in tests¶
pytest允许直接使用python的assert来进行断言。如果要测试异常的话,可以:
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
如果需要访问异常的回溯信息,可以:
def test_recursion_depth():
with pytest.raises(RuntimeError) as excinfo:
f()
assert "maximum recursion" in str(excinfo.value)
exeinfo是ExceptionInfo 的实例。
和unittest的TestCase.assertRaisesRegexp方法相同,可以使用match来匹配异常:
def test_match():
with pytest.raises(ValueError, match=r".* 123 .*"):
myfunc()
match是通过re.search实现的,所以上面的例子也可以写成 match='123'
。
pytest.raise有一个变体:pytest.raises(ExpectedException, func, *args, **kwargs)
,往里传一个函数,让这个函数来消耗args和kwargs。
在pytest.mark.xfail上也可以指定一个异常:
@pytest.mark.xfail(raises=IndexError)
def test_f():
f()
针对warning可以使用pytest.warns
对于比较,pytest可以产生比较丰富的上下文信息。如果不适用,则可以自定义pytest_assertrepr_compare来添加额外的信息。一个例子:
# content of conftest.py
from test_foocompare import Foo
def pytest_assertrepr_compare(op, left, right):
if isinstance(left, Foo) and isinstance(right, Foo) and op == "==":
return [
"Comparing Foo instances:",
" vals: {} != {}".format(left.val, right.val),
]
pytest是通过对assert语句进行改写来增加额外的信息,pytest只会改写测试用例中的断言,不会触及其他代码中的assert。可以通过调用register_assert_rewrite 来对指定模块进行assert改写。更多参考Behind the scenes of pytest’s new assertion rewriting.
pytest会被改写后的模块写回硬盘以便进行缓存。可以通过sys.dont_write_bytecode = True
来取消这个行为。
pytest通过import钩子作为改写的时机。有时候需要禁止改写:
- 在模块的docstring中加入PYTEST_DONT_REWRITE
- 在命令行指定–assert=plain (废弃–no-assert、–nomagic以及–assert=reinterp)
(本篇完)