测试用例设计
断言比较
用例前置和后置
参数化
生成报告方式
pytest 是一个非常成熟的 Python 测试框架,可以做到做个场景的测试工作,如:单元测试、接口测试、web测试等。
pytest 是一个插件化平台,这就是它比 unittest 强大的原因,丰富的插件扩展增强了它的功能,也可以根据自己的需要定制化开发自己的插件,非常的灵活。
# 安装 pytest
# !pip3 install pytest
Collecting pytest
Downloading http://mirrors.tencentyun.com/pypi/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 1.6MB/s ta 0:00:01
[?25hCollecting more-itertools>=4.0.0 (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 48.1MB/s ta 0:00:01
[?25hCollecting packaging (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 2.8MB/s ta 0:00:011
[?25hCollecting pluggy<1.0,>=0.12 (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting attrs>=17.4.0 (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting wcwidth (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 2.2MB/s eta 0:00:01
[?25hCollecting six (from packaging->pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest)
Downloading http://mirrors.tencentyun.com/pypi/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Installing collected packages: more-itertools, pyparsing, six, packaging, py, zipp, importlib-metadata, pluggy, attrs, wcwidth, pytest
Successfully installed attrs-19.3.0 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
# 查看 pytest 是否安装成功
# !pytest --version
This is pytest version 5.4.1, imported from /home/ubuntu/.local/lib/python3.6/site-packages/pytest/__init__.py
# 显示可用的内置参数
# !pytest --fixtures
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 0 items [0m[1m
[32mcache[0m
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.
[32mcapsys[0m
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.
[32mcapsysbinary[0m
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.
[32mcapfd[0m
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.
[32mcapfdbinary[0m
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.
[32mdoctest_namespace[0m[36m [session scope][0m
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
[32mpytestconfig[0m[36m [session scope][0m
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
Example::
def test_foo(pytestconfig):
if pytestconfig.getoption("verbose") > 0:
...
[32mrecord_property[0m
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)
[32mrecord_xml_attribute[0m
Add extra xml attributes to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being
automatically xml-encoded
[32mrecord_testsuite_property[0m[36m [session scope][0m
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.
[32mcaplog[0m
Access and control log capturing.
Captured logs are available through the following properties/methods::
* caplog.messages -> list of format-interpolated log messages
* 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
[32mmonkeypatch[0m
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.
[32mrecwarn[0m
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.
[32mtmpdir_factory[0m[36m [session scope][0m
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
[32mtmp_path_factory[0m[36m [session scope][0m
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
[32mtmpdir[0m
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
[32mtmp_path[0m
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
[33m============================ [33mno tests ran[0m[33m in 0.03s[0m[33m =============================[0m
0 -- 成功地收集并传递了所有测试
1 -- 测试被收集和运行但一些测试失败
2 -- 测试执行被用户中断
3 -- 执行测试时发生内部错误
4 -- pytest 命令行使用错误
5 -- 未收集任何测试
"""
示例文件
@FileName: test_start.py
"""
def func(x):
return x + 1
def test_func():
assert func(3) == 5
class TestClass:
def test_one(self):
x = "This"
assert "h" in x
def test_two(self):
x = "hello"
assert hasattr(x, "check")
!pytest
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
test_start.py [31mF[0m[32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mtest_start.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <test_start.TestClass object at 0x7f384557fc18>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mtest_start.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED test_start.py::test_func - assert 4 == 5
FAILED test_start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.12s[0m[31m ==========================[0m
!pytest start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py [31mF[0m[32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7f0d00651278>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.12s[0m[31m ==========================[0m
!pytest start.py::test_func
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
start.py [31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
[31m============================== [31m[1m1 failed[0m[31m in 0.10s[0m[31m ===============================[0m
!pytest start.py::TestClass
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
start.py [32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7f5fc75cb160>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m1 failed[0m, [32m1 passed[0m[31m in 0.13s[0m[31m ==========================[0m
!pytest start.py::TestClass::test_one
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
start.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
"""显示每一个测试函数的执行结果"""
!pytest -v start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py::test_func [31mFAILED[0m[31m [ 33%][0m
start.py::TestClass::test_one [32mPASSED[0m[31m [ 66%][0m
start.py::TestClass::test_two [31mFAILED[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE +4[0m
[1m[31mE -5[0m
[1m[31mstart.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7fc060a955c0>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.16s[0m[31m ==========================[0m
# 将运行用 @pytest.mark.login 装饰器修饰的所有测试
!pytest -m login
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 4 items / 4 deselected [0m
[33m============================ [33m[1m4 deselected[0m[33m in 0.04s[0m[33m =============================[0m
!pytest -q start.py
[31mF[0m[32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7fa6e310a4a8>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m[31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.16s[0m[0m
!pytest -s start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py [31mF[0m[32m.[0m[31mF[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7f087090bd30>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.12s[0m[31m ==========================[0m
!pytest start.py -x
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py [31mF[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
[31m!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!![0m
[31m============================== [31m[1m1 failed[0m[31m in 0.11s[0m[31m ===============================[0m
!pytest start.py --maxfail=1
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py [31mF[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
[31m!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!![0m
[31m============================== [31m[1m1 failed[0m[31m in 0.12s[0m[31m ===============================[0m
# 执行测试用例名称包含http的所有用例
!pytest -s -k http start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items / 3 deselected [0m
[33m============================ [33m[1m3 deselected[0m[33m in 0.01s[0m[33m =============================[0m
!pytest -s -k "not http" start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
start.py [31mF[0m[32m.[0m[31mF[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_func ___________________________________[0m
[94mdef[39;49;00m [92mtest_func[39;49;00m():
> [94massert[39;49;00m func([94m3[39;49;00m) == [94m5[39;49;00m
[1m[31mE assert 4 == 5[0m
[1m[31mE + where 4 = func(3)[0m
[1m[31mstart.py[0m:8: AssertionError
[31m[1m______________________________ TestClass.test_two ______________________________[0m
self = <start.TestClass object at 0x7f946a3cfe80>
[94mdef[39;49;00m [92mtest_two[39;49;00m([96mself[39;49;00m):
x = [33m"[39;49;00m[33mhello[39;49;00m[33m"[39;49;00m
> [94massert[39;49;00m [96mhasattr[39;49;00m(x, [33m"[39;49;00m[33mcheck[39;49;00m[33m"[39;49;00m)
[1m[31mE AssertionError: assert False[0m
[1m[31mE + where False = hasattr(‘hello‘, ‘check‘)[0m
[1m[31mstart.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED start.py::test_func - assert 4 == 5
FAILED start.py::TestClass::test_two - AssertionError: assert False
[31m========================= [31m[1m2 failed[0m, [32m1 passed[0m[31m in 0.12s[0m[31m ==========================[0m
!pytest -s -k "method or weibo" start.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items / 3 deselected [0m
[33m============================ [33m[1m3 deselected[0m[33m in 0.01s[0m[33m =============================[0m
与unittest不同,pytest使用的是python自带的assert关键字来进行断言
assert关键字后面可以接一个表达式,只要表达式的最终结果为True,那么断言通过,用例执行成功,否则用例执行失败
常用断言方法:
import pytest
def f():
return 3
def test_function():
a = f()
assert a % 2 == 0, "判断 a 为偶数,当前 a 的值为:%s" % a
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
!pytest assert.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
assert.py [31mF[0m[32m.[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m________________________________ test_function _________________________________[0m
[94mdef[39;49;00m [92mtest_function[39;49;00m():
a = f()
> [94massert[39;49;00m a % [94m2[39;49;00m == [94m0[39;49;00m, [33m"[39;49;00m[33m判断 a 为偶数,当前 a 的值为:[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m % a
[1m[31mE AssertionError: 判断 a 为偶数,当前 a 的值为:3[0m
[1m[31mE assert (3 % 2) == 0[0m
[1m[31massert.py[0m:8: AssertionError
=========================== short test summary info ============================
FAILED assert.py::test_function - AssertionError: 判断 a 为偶数,当前 a 的值...
[31m========================= [31m[1m1 failed[0m, [32m1 passed[0m[31m in 0.11s[0m[31m ==========================[0m
可以使用 pytest.raises 作为上下文管理器,当抛出异常时可以获取到对应的异常实例
"""异常断言"""
import pytest
def test_zero_division():
with pytest.raises(ZeroDivisionError):
1 / 0
"""详细断言异常"""
def test_zero_division_long_info():
with pytest.raises(ZeroDivisionError) as excinfo:
1 / 0
"""断言异常类型"""
assert excinfo.type == ZeroDivisionError
"""断言异常 value 的值"""
assert "Division by Zero" in str(excinfo.value)
!pytest assert_except.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
assert_except.py [32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m_________________________ test_zero_division_long_info _________________________[0m
[94mdef[39;49;00m [92mtest_zero_division_long_info[39;49;00m():
[94mwith[39;49;00m pytest.raises([96mZeroDivisionError[39;49;00m) [94mas[39;49;00m excinfo:
[94m1[39;49;00m / [94m0[39;49;00m
[33m"""断言异常类型"""[39;49;00m
[94massert[39;49;00m excinfo.type == [96mZeroDivisionError[39;49;00m
[33m"""断言异常 value 的值"""[39;49;00m
> [94massert[39;49;00m [33m"[39;49;00m[33mDivision by Zero[39;49;00m[33m"[39;49;00m [95min[39;49;00m [96mstr[39;49;00m(excinfo.value)
[1m[31mE AssertionError: assert ‘Division by Zero‘ in ‘division by zero‘[0m
[1m[31mE + where ‘division by zero‘ = str(ZeroDivisionError(‘division by zero‘,))[0m
[1m[31mE + where ZeroDivisionError(‘division by zero‘,) = <ExceptionInfo ZeroDivisionError(‘division by zero‘,) tblen=1>.value[0m
[1m[31massert_except.py[0m:17: AssertionError
=========================== short test summary info ============================
FAILED assert_except.py::test_zero_division_long_info - AssertionError: asser...
[31m========================= [31m[1m1 failed[0m, [32m1 passed[0m[31m in 0.11s[0m[31m ==========================[0m
"""自定义消息"""
def test_zero_division_custom_incinfo():
with pytest.raises(ZeroDivisionError, match="*.zero.*") as excinfo:
1 / 0
!pytest assert_except.py::test_zero_division_custom_incinfo
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
assert_except.py [31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m______________________ test_zero_division_custom_incinfo _______________________[0m
[94mdef[39;49;00m [92mtest_zero_division_custom_incinfo[39;49;00m():
[94mwith[39;49;00m pytest.raises([96mZeroDivisionError[39;49;00m, match=[33m"[39;49;00m[33m*.zero.*[39;49;00m[33m"[39;49;00m) [94mas[39;49;00m excinfo:
> [94m1[39;49;00m / [94m0[39;49;00m
[1m[31mE ZeroDivisionError: division by zero[0m
[1m[31massert_except.py[0m:23: ZeroDivisionError
[33mDuring handling of the above exception, another exception occurred:[0m
[94mdef[39;49;00m [92mtest_zero_division_custom_incinfo[39;49;00m():
[94mwith[39;49;00m pytest.raises([96mZeroDivisionError[39;49;00m, match=[33m"[39;49;00m[33m*.zero.*[39;49;00m[33m"[39;49;00m) [94mas[39;49;00m excinfo:
> [94m1[39;49;00m / [94m0[39;49;00m
[1m[31massert_except.py[0m:23:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
[1m[31m/usr/lib/python3.6/re.py[0m:182: in search
[94mreturn[39;49;00m _compile(pattern, flags).search(string)
[1m[31m/usr/lib/python3.6/re.py[0m:301: in _compile
p = sre_compile.compile(pattern, flags)
[1m[31m/usr/lib/python3.6/sre_compile.py[0m:562: in compile
p = sre_parse.parse(p, flags)
[1m[31m/usr/lib/python3.6/sre_parse.py[0m:855: in parse
p = _parse_sub(source, pattern, flags & SRE_FLAG_VERBOSE, [94m0[39;49;00m)
[1m[31m/usr/lib/python3.6/sre_parse.py[0m:416: in _parse_sub
[95mnot[39;49;00m nested [95mand[39;49;00m [95mnot[39;49;00m items))
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
source = <sre_parse.Tokenizer object at 0x7f7aac6d9630>
state = <sre_parse.Pattern object at 0x7f7aac663390>, verbose = 0, nested = 1
first = True
[94mdef[39;49;00m [92m_parse[39;49;00m(source, state, verbose, nested, first=[94mFalse[39;49;00m):
[90m# parse a simple pattern[39;49;00m
subpattern = SubPattern(state)
[90m# precompute constants into local variables[39;49;00m
subpatternappend = subpattern.append
sourceget = source.get
sourcematch = source.match
_len = [96mlen[39;49;00m
_ord = [96mord[39;49;00m
[94mwhile[39;49;00m [94mTrue[39;49;00m:
this = source.next
[94mif[39;49;00m this [95mis[39;49;00m [94mNone[39;49;00m:
[94mbreak[39;49;00m [90m# end of pattern[39;49;00m
[94mif[39;49;00m this [95min[39;49;00m [33m"[39;49;00m[33m|)[39;49;00m[33m"[39;49;00m:
[94mbreak[39;49;00m [90m# end of subpattern[39;49;00m
sourceget()
[94mif[39;49;00m verbose:
[90m# skip whitespace and comments[39;49;00m
[94mif[39;49;00m this [95min[39;49;00m WHITESPACE:
[94mcontinue[39;49;00m
[94mif[39;49;00m this == [33m"[39;49;00m[33m#[39;49;00m[33m"[39;49;00m:
[94mwhile[39;49;00m [94mTrue[39;49;00m:
this = sourceget()
[94mif[39;49;00m this [95mis[39;49;00m [94mNone[39;49;00m [95mor[39;49;00m this == [33m"[39;49;00m[33m\n[39;49;00m[33m"[39;49;00m:
[94mbreak[39;49;00m
[94mcontinue[39;49;00m
[94mif[39;49;00m this[[94m0[39;49;00m] == [33m"[39;49;00m[33m\\[39;49;00m[33m"[39;49;00m:
code = _escape(source, this, state)
subpatternappend(code)
[94melif[39;49;00m this [95mnot[39;49;00m [95min[39;49;00m SPECIAL_CHARS:
subpatternappend((LITERAL, _ord(this)))
[94melif[39;49;00m this == [33m"[39;49;00m[33m[[39;49;00m[33m"[39;49;00m:
here = source.tell() - [94m1[39;49;00m
[90m# character set[39;49;00m
[96mset[39;49;00m = []
setappend = [96mset[39;49;00m.append
[90m## if sourcematch(":"):[39;49;00m
[90m## pass # handle character classes[39;49;00m
[94mif[39;49;00m sourcematch([33m"[39;49;00m[33m^[39;49;00m[33m"[39;49;00m):
setappend((NEGATE, [94mNone[39;49;00m))
[90m# check remaining characters[39;49;00m
start = [96mset[39;49;00m[:]
[94mwhile[39;49;00m [94mTrue[39;49;00m:
this = sourceget()
[94mif[39;49;00m this [95mis[39;49;00m [94mNone[39;49;00m:
[94mraise[39;49;00m source.error([33m"[39;49;00m[33munterminated character set[39;49;00m[33m"[39;49;00m,
source.tell() - here)
[94mif[39;49;00m this == [33m"[39;49;00m[33m][39;49;00m[33m"[39;49;00m [95mand[39;49;00m [96mset[39;49;00m != start:
[94mbreak[39;49;00m
[94melif[39;49;00m this[[94m0[39;49;00m] == [33m"[39;49;00m[33m\\[39;49;00m[33m"[39;49;00m:
code1 = _class_escape(source, this)
[94melse[39;49;00m:
code1 = LITERAL, _ord(this)
[94mif[39;49;00m sourcematch([33m"[39;49;00m[33m-[39;49;00m[33m"[39;49;00m):
[90m# potential range[39;49;00m
that = sourceget()
[94mif[39;49;00m that [95mis[39;49;00m [94mNone[39;49;00m:
[94mraise[39;49;00m source.error([33m"[39;49;00m[33munterminated character set[39;49;00m[33m"[39;49;00m,
source.tell() - here)
[94mif[39;49;00m that == [33m"[39;49;00m[33m][39;49;00m[33m"[39;49;00m:
[94mif[39;49;00m code1[[94m0[39;49;00m] [95mis[39;49;00m IN:
code1 = code1[[94m1[39;49;00m][[94m0[39;49;00m]
setappend(code1)
setappend((LITERAL, _ord([33m"[39;49;00m[33m-[39;49;00m[33m"[39;49;00m)))
[94mbreak[39;49;00m
[94mif[39;49;00m that[[94m0[39;49;00m] == [33m"[39;49;00m[33m\\[39;49;00m[33m"[39;49;00m:
code2 = _class_escape(source, that)
[94melse[39;49;00m:
code2 = LITERAL, _ord(that)
[94mif[39;49;00m code1[[94m0[39;49;00m] != LITERAL [95mor[39;49;00m code2[[94m0[39;49;00m] != LITERAL:
msg = [33m"[39;49;00m[33mbad character range [39;49;00m[33m%s[39;49;00m[33m-[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m % (this, that)
[94mraise[39;49;00m source.error(msg, [96mlen[39;49;00m(this) + [94m1[39;49;00m + [96mlen[39;49;00m(that))
lo = code1[[94m1[39;49;00m]
hi = code2[[94m1[39;49;00m]
[94mif[39;49;00m hi < lo:
msg = [33m"[39;49;00m[33mbad character range [39;49;00m[33m%s[39;49;00m[33m-[39;49;00m[33m%s[39;49;00m[33m"[39;49;00m % (this, that)
[94mraise[39;49;00m source.error(msg, [96mlen[39;49;00m(this) + [94m1[39;49;00m + [96mlen[39;49;00m(that))
setappend((RANGE, (lo, hi)))
[94melse[39;49;00m:
[94mif[39;49;00m code1[[94m0[39;49;00m] [95mis[39;49;00m IN:
code1 = code1[[94m1[39;49;00m][[94m0[39;49;00m]
setappend(code1)
[90m# XXX: <fl> should move set optimization to compiler![39;49;00m
[94mif[39;49;00m _len([96mset[39;49;00m)==[94m1[39;49;00m [95mand[39;49;00m [96mset[39;49;00m[[94m0[39;49;00m][[94m0[39;49;00m] [95mis[39;49;00m LITERAL:
subpatternappend([96mset[39;49;00m[[94m0[39;49;00m]) [90m# optimization[39;49;00m
[94melif[39;49;00m _len([96mset[39;49;00m)==[94m2[39;49;00m [95mand[39;49;00m [96mset[39;49;00m[[94m0[39;49;00m][[94m0[39;49;00m] [95mis[39;49;00m NEGATE [95mand[39;49;00m [96mset[39;49;00m[[94m1[39;49;00m][[94m0[39;49;00m] [95mis[39;49;00m LITERAL:
subpatternappend((NOT_LITERAL, [96mset[39;49;00m[[94m1[39;49;00m][[94m1[39;49;00m])) [90m# optimization[39;49;00m
[94melse[39;49;00m:
[90m# XXX: <fl> should add charmap optimization here[39;49;00m
subpatternappend((IN, [96mset[39;49;00m))
[94melif[39;49;00m this [95min[39;49;00m REPEAT_CHARS:
[90m# repeat previous item[39;49;00m
here = source.tell()
[94mif[39;49;00m this == [33m"[39;49;00m[33m?[39;49;00m[33m"[39;49;00m:
[96mmin[39;49;00m, [96mmax[39;49;00m = [94m0[39;49;00m, [94m1[39;49;00m
[94melif[39;49;00m this == [33m"[39;49;00m[33m*[39;49;00m[33m"[39;49;00m:
[96mmin[39;49;00m, [96mmax[39;49;00m = [94m0[39;49;00m, MAXREPEAT
[94melif[39;49;00m this == [33m"[39;49;00m[33m+[39;49;00m[33m"[39;49;00m:
[96mmin[39;49;00m, [96mmax[39;49;00m = [94m1[39;49;00m, MAXREPEAT
[94melif[39;49;00m this == [33m"[39;49;00m[33m{[39;49;00m[33m"[39;49;00m:
[94mif[39;49;00m source.next == [33m"[39;49;00m[33m}[39;49;00m[33m"[39;49;00m:
subpatternappend((LITERAL, _ord(this)))
[94mcontinue[39;49;00m
[96mmin[39;49;00m, [96mmax[39;49;00m = [94m0[39;49;00m, MAXREPEAT
lo = hi = [33m"[39;49;00m[33m"[39;49;00m
[94mwhile[39;49;00m source.next [95min[39;49;00m DIGITS:
lo += sourceget()
[94mif[39;49;00m sourcematch([33m"[39;49;00m[33m,[39;49;00m[33m"[39;49;00m):
[94mwhile[39;49;00m source.next [95min[39;49;00m DIGITS:
hi += sourceget()
[94melse[39;49;00m:
hi = lo
[94mif[39;49;00m [95mnot[39;49;00m sourcematch([33m"[39;49;00m[33m}[39;49;00m[33m"[39;49;00m):
subpatternappend((LITERAL, _ord(this)))
source.seek(here)
[94mcontinue[39;49;00m
[94mif[39;49;00m lo:
[96mmin[39;49;00m = [96mint[39;49;00m(lo)
[94mif[39;49;00m [96mmin[39;49;00m >= MAXREPEAT:
[94mraise[39;49;00m [96mOverflowError[39;49;00m([33m"[39;49;00m[33mthe repetition number is too large[39;49;00m[33m"[39;49;00m)
[94mif[39;49;00m hi:
[96mmax[39;49;00m = [96mint[39;49;00m(hi)
[94mif[39;49;00m [96mmax[39;49;00m >= MAXREPEAT:
[94mraise[39;49;00m [96mOverflowError[39;49;00m([33m"[39;49;00m[33mthe repetition number is too large[39;49;00m[33m"[39;49;00m)
[94mif[39;49;00m [96mmax[39;49;00m < [96mmin[39;49;00m:
[94mraise[39;49;00m source.error([33m"[39;49;00m[33mmin repeat greater than max repeat[39;49;00m[33m"[39;49;00m,
source.tell() - here)
[94melse[39;49;00m:
[94mraise[39;49;00m [96mAssertionError[39;49;00m([33m"[39;49;00m[33munsupported quantifier [39;49;00m[33m%r[39;49;00m[33m"[39;49;00m % (char,))
[90m# figure out which item to repeat[39;49;00m
[94mif[39;49;00m subpattern:
item = subpattern[-[94m1[39;49;00m:]
[94melse[39;49;00m:
item = [94mNone[39;49;00m
[94mif[39;49;00m [95mnot[39;49;00m item [95mor[39;49;00m (_len(item) == [94m1[39;49;00m [95mand[39;49;00m item[[94m0[39;49;00m][[94m0[39;49;00m] [95mis[39;49;00m AT):
[94mraise[39;49;00m source.error([33m"[39;49;00m[33mnothing to repeat[39;49;00m[33m"[39;49;00m,
> source.tell() - here + [96mlen[39;49;00m(this))
[1m[31mE sre_constants.error: nothing to repeat at position 0[0m
[1m[31m/usr/lib/python3.6/sre_parse.py[0m:616: error
=========================== short test summary info ============================
FAILED assert_except.py::test_zero_division_custom_incinfo - sre_constants.er...
[31m============================== [31m[1m1 failed[0m[31m in 0.26s[0m[31m ===============================[0m
"""异常装饰器"""
@pytest.mark.xfail(raises=ZeroDivisionError)
def test_except_decorate():
1 / 0
!pytest assert_except.py::test_except_decorate
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
assert_except.py [33mx[0m[33m [100%][0m
[33m============================== [33m[1m1 xfailed[0m[33m in 0.03s[0m[33m ==============================[0m
unittest的前置后置
pytest的前置后置
注意:setup、teardown可以实现在执行用例前或结束后加入一些操作,但这种都是针对整个脚本全局生效的
"""前置后置条件"""
import pytest
def setup_module():
print("=====整个.py模块开始前只执行一次:打开浏览器=====")
def teardown_module():
print("=====整个.py模块结束后只执行一次:关闭浏览器=====")
def setup_function():
print("===每个函数级别用例开始前都执行setup_function===")
def teardown_function():
print("===每个函数级别用例结束后都执行teardown_function====")
def test_one():
print("one")
def test_two():
print("two")
class TestCase():
def setup_class(self):
print("====整个测试类开始前只执行一次setup_class====")
def teardown_class(self):
print("====整个测试类结束后只执行一次teardown_class====")
def setup_method(self):
print("==类里面每个用例执行前都会执行setup_method==")
def teardown_method(self):
print("==类里面每个用例结束后都会执行teardown_method==")
def setup(self):
print("=类里面每个用例执行前都会执行setup=")
def teardown(self):
print("=类里面每个用例结束后都会执行teardown=")
def test_three(self):
print("three")
def test_four(self):
print("four")
if __name__ == ‘__main__‘:
pytest.main(["-q", "-s", "-ra", "setup_teardown.py"])
!pytest setup_teardown.py
=====整个.py模块开始前只执行一次:打开浏览器=====
===每个函数级别用例开始前都执行setup_function===
one
.===每个函数级别用例结束后都执行teardown_function====
===每个函数级别用例开始前都执行setup_function===
two
.===每个函数级别用例结束后都执行teardown_function====
====整个测试类开始前只执行一次setup_class====
==类里面每个用例执行前都会执行setup_method==
=类里面每个用例执行前都会执行setup=
three
.=类里面每个用例结束后都会执行teardown=
==类里面每个用例结束后都会执行teardown_method==
====整个测试类结束后只执行一次teardown_class====
===每个函数级别用例开始前都执行setup_function===
E===每个函数级别用例结束后都执行teardown_function====
=====整个.py模块结束后只执行一次:关闭浏览器=====
==================================== ERRORS ====================================
_________________________ ERROR at setup of test_four __________________________
file /home/ubuntu/MySpace/Python/pytest/setup_teardown.py, line 48
def test_four(self):
E fixture ‘self‘ not found
> available fixtures: _Module__pytest_setup_function, _Module__pytest_setup_module, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/setup_teardown.py:48
=========================== short test summary info ============================
ERROR setup_teardown.py::test_four
3 passed, 1 error in 0.05s
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 4 items [0m
setup_teardown.py [32m.[0m[32m.[0m[32m.[0m[31mE[0m[31m [100%][0m
==================================== ERRORS ====================================
[31m[1m_________________________ ERROR at setup of test_four __________________________[0m
file /home/ubuntu/MySpace/Python/pytest/setup_teardown.py, line 48
def test_four(self):
[31mE fixture ‘self‘ not found[0m
[31m> available fixtures: _Module__pytest_setup_function, _Module__pytest_setup_module, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/setup_teardown.py:48
---------------------------- Captured stdout setup -----------------------------
===每个函数级别用例开始前都执行setup_function===
=========================== short test summary info ============================
ERROR setup_teardown.py::test_four
[31m========================== [32m3 passed[0m, [31m[1m1 error[0m[31m in 0.04s[0m[31m ==========================[0m
如果有以下场景:用例 1 需要先登录,用例 2 不需要登录,用例 3 需要先登录。很显然无法用 setup 和 teardown 来实现了
fixture可以让我们自定义测试用例的前置条件
setup
和 teardown
这几个命名conftest.py
配置里可以实现数据共享,不需要 import
就能自动找到 fixture
scope="module"
可以实现多个 .py
跨文件共享前置scope="session"
以实现多个 .py
跨文件使用一个 session
来完成多个用例@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)
def test():
print("fixture初始化的参数列表")
参数列表
注意
方法一:将fixture名称作为测试用例函数的输入参数
import pytest
@pytest.fixture
def login():
print("请输入帐号和密码")
def test_s1(login):
print("用例1,登录后进行的,操作 111")
"""不穿login"""
def test_s2():
print("用例2,不需要登录,操作 222")
!pytest fixture.py::test_s1
!pytest fixture.py::test_s2
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
fixture.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
fixture.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
方法二:测试用例加上装饰器:@pytest.mark.usefixtures(fixture_name)
import pytest
@pytest.fixture
def login():
print("请输入帐号和密码")
@pytest.fixture
def login2():
print("please输入账号,密码先登录")
@pytest.mark.usefixtures("login2", "login")
def test_s11():
print("用例 11:登录之后其它动作 111")
!pytest fixture.py::test_s11
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
fixture.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
方法三:fixture设置autouse=True
@pytest.fixture(autouse=True)
def login3():
print("====auto===")
"""不是test开头,加了装饰器也不会执行fixture"""
@pytest.mark.usefixtures("login2")
def test_loginss():
print(123)
!pytest fixture.py::test_loginss
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
fixture.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
import pytest
order = []
@pytest.fixture(scope="session")
def s1():
order.append("s1")
@pytest.fixture(scope="module")
def m1():
order.append("m1")
@pytest.fixture
def f1(f3, a1):
# 先实例化f3, 再实例化a1, 最后实例化f1
order.append("f1")
assert f3 == 123
@pytest.fixture
def f3():
order.append("f3")
a = 123
yield a
@pytest.fixture
def a1():
order.append("a1")
@pytest.fixture
def f2():
order.append("f2")
def test_order(f1, m1, f2, s1):
# m1、s1在f1后,但因为scope范围大,所以会优先实例化
assert order == ["s1", "m1", "f3", "a1", "f1", "f2"]
!pytest fixture_order.py::test_order
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
fixture_order.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
添加了 @pytest.fixture ,如果fixture还想依赖其他fixture,需要用函数传参的方式,不能用 @pytest.mark.usefixtures() 的方式,否则会不生效
import pytest
@pytest.fixture(scope="session")
def open():
print("===打开浏览器===")
@pytest.fixture
# @pytest.mark.usefixtures("open") 不可取!!!不生效!!!
def test_login(open):
# 方法级别前置操作setup
print(f"输入账号,密码先登录{open}")
!pytest fixture_attention.py::test_login
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 0 items [0m
[33m============================ [33mno tests ran[0m[33m in 0.01s[0m[33m =============================[0m
[31mERROR: not found: /home/ubuntu/MySpace/Python/pytest/fixture_attention.py::test_login
(no name ‘/home/ubuntu/MySpace/Python/pytest/fixture_attention.py::test_login‘ in any of [<Module fixture_attention.py>])
[0m
用fixture实现teardown并不是一个独立的函数,而是用 yield 关键字来开启teardown操作
import pytest
@pytest.fixture(scope="session")
def open():
# 会话前置操作setup
print("===打开浏览器===")
test = "测试变量是否返回"
yield test
# 会话后置操作teardown
print("==关闭浏览器==")
@pytest.fixture
def login(open):
# 方法级别前置操作setup
print(f"输入账号,密码先登录{open}")
name = "==我是账号=="
pwd = "==我是密码=="
age = "==我是年龄=="
# 返回变量
yield name, pwd, age
# 方法级别后置操作teardown
print("登录成功")
def test_s1(login):
print("==用例1==")
# 返回的是一个元组
print(login)
# 分别赋值给不同变量
name, pwd, age = login
print(name, pwd, age)
assert "账号" in name
assert "密码" in pwd
assert "年龄" in age
def test_s2(login):
print("==用例2==")
print(login)
!pytest fixture_teardown.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
fixture_teardown.py [32m.[0m[32m.[0m[32m [100%][0m
[32m============================== [32m[1m2 passed[0m[32m in 0.01s[0m[32m ===============================[0m
import pytest
@pytest.fixture(scope="module")
def smtp_connection():
with smtp.SMTP("smtp.gmail.com", 587, timeout=5) as smtp_connection:
yield smtp_connection # provide the fixture value
!pytest fixture_yeild_with.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 0 items [0m
[33m============================ [33mno tests ran[0m[33m in 0.00s[0m[33m =============================[0m
@pytest.fixture(scope="module")
def test_addfinalizer(request):
# 前置操作setup
print("==再次打开浏览器==")
test = "test_addfinalizer"
def fin():
# 后置操作teardown
print("==再次关闭浏览器==")
request.addfinalizer(fin)
# 返回前置操作的变量
return test
def test_anthor(test_addfinalizer):
print("==最新用例==", test_addfinalizer)
conftest.py --- 一个专门存放 fixture 的配置文件,多个测试用例文件(test_*.py)的所有用例都需要用登录功能来作为前置操作,那就不能把登录功能写到某个用例文件中去了
conftest.py的出现,就是为了解决上述问题,单独管理一些全局的fixture
conftest.py配置fixture注意事项
!tree ./conftest/
!pytest ./conftest/run.py
[01;34m./conftest/[00m
├── confest.py
├── [01;34m__pycache__[00m
│?? └── test_1.cpython-36-pytest-5.4.1.pyc
├── run.py
└── test_1.py
1 directory, 4 files
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 0 items [0m
[33m============================ [33mno tests ran[0m[33m in 0.00s[0m[33m =============================[0m
import pytest
@pytest.fixture()
def login(request):
name = request.param
print(f"== 账号是:{name} ==")
return name
data = ["pyy1", "polo"]
ids = [f"login_test_name is:{name}" for name in data]
"""
(1)添加 indirect=True 参数是为了把 login 当成一个函数去执行,而不是一个参数,并且将data当做参数传入函数
(2)def test_name(login) ,这里的login是获取fixture返回的值
"""
@pytest.mark.parametrize("login", data, ids=ids, indirect=True)
def test_name(login):
print(f" 测试用例的登录账号是:{login} ")
!pytest -s fixture/fixture_request_one.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
fixture/fixture_request_one.py == 账号是:pyy1 ==
测试用例的登录账号是:pyy1
[32m.[0m== 账号是:polo ==
测试用例的登录账号是:polo
[32m.[0m
[32m============================== [32m[1m2 passed[0m[32m in 0.01s[0m[32m ===============================[0m
需要传多个参数,需要通过字典去传
"""多个参数"""
import pytest
@pytest.fixture()
def login(request):
param = request.param
print(f"账号是:{param[‘username‘]}, 密码是:{param[‘passwd‘]}")
return param
data = [
{"username": "crisimple1", "passwd": "123456"},
{"username": "crisimple2", "passwd": "654321"},
]
@pytest.mark.parametrize("login", data, indirect=True)
def test_login(login):
print(f"账号是:{login[‘username‘]},密码是:{login[‘passwd‘]}")
!pytest -v -s fixture/fixture_request_more.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
fixture/fixture_request_more.py::test_login[login0] 账号是:crisimple1, 密码是:123456
账号是:crisimple1,密码是:123456
[32mPASSED[0m
fixture/fixture_request_more.py::test_login[login1] 账号是:crisimple2, 密码是:654321
账号是:crisimple2,密码是:654321
[32mPASSED[0m
[32m============================== [32m[1m2 passed[0m[32m in 0.01s[0m[32m ===============================[0m
"""多个fixture,只加一个装饰器"""
import pytest
@pytest.fixture(scope="function")
def input_user(request):
user = request.param
print("登录账号为:%s" % user)
return user
@pytest.fixture(scope="function")
def input_pwd(request):
pwd = request.param
print("登录密码为:%s" % pwd)
return pwd
data = [
("name1", "pwd1"),
("name2", "pwd2")
]
@pytest.mark.parametrize("input_user, input_pwd", data, indirect=True)
def test_more_fixture(input_user, input_pwd):
print("fixture返回的内容:", input_user, input_pwd)
!pytest -v -s fixture/fixture_one_fixture.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 2 items [0m
fixture/fixture_one_fixture.py::test_more_fixture[name1-pwd1] 登录账号为:name1
登录密码为:pwd1
fixture返回的内容: name1 pwd1
[32mPASSED[0m
fixture/fixture_one_fixture.py::test_more_fixture[name2-pwd2] 登录账号为:name2
登录密码为:pwd2
fixture返回的内容: name2 pwd2
[32mPASSED[0m
[32m============================== [32m[1m2 passed[0m[32m in 0.01s[0m[32m ===============================[0m
"""多个fixture"""
import pytest
@pytest.fixture(scope="function")
def input_user(request):
user = request.param
print("登录账号为:%s" % user)
return user
@pytest.fixture(scope="function")
def input_pwd(request):
pwd = request.param
print("登录密码为:%s" % pwd)
return pwd
name = ["name1", "name2"]
passwd = ["pwd1", "pwd2"]
@pytest.mark.parametrize("input_user", name, indirect=True)
@pytest.mark.parametrize("input_pwd", passwd, indirect=True)
def test_more_fixture(input_user, input_pwd):
print("fixture返回的内容:", input_user, input_pwd)
!pytest -v -s fixture/fixture_more_fixture.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 4 items [0m
fixture/fixture_more_fixture.py::test_more_fixture[pwd1-name1] 登录账号为:name1
登录密码为:pwd1
fixture返回的内容: name1 pwd1
[32mPASSED[0m
fixture/fixture_more_fixture.py::test_more_fixture[pwd1-name2] 登录账号为:name2
登录密码为:pwd1
fixture返回的内容: name2 pwd1
[32mPASSED[0m
fixture/fixture_more_fixture.py::test_more_fixture[pwd2-name1] 登录账号为:name1
登录密码为:pwd2
fixture返回的内容: name1 pwd2
[32mPASSED[0m
fixture/fixture_more_fixture.py::test_more_fixture[pwd2-name2] 登录账号为:name2
登录密码为:pwd2
fixture返回的内容: name2 pwd2
[32mPASSED[0m
[32m============================== [32m[1m4 passed[0m[32m in 0.02s[0m[32m ===============================[0m
跳过执行测试用例,有可选参数 reason:跳过的原因,会在执行结果中打印
import pytest
@pytest.fixture(autouse=True)
def login():
print("====登录====")
def test_case01():
print("我是测试用例11111")
@pytest.mark.skip(reason="不执行该用例!!因为没写好!!")
def test_case02():
print("我是测试用例22222")
class Test1:
def test_1(self):
print("%% 我是类测试用例1111 %%")
@pytest.mark.skip(reason="不想执行")
def test_2(self):
print("%% 我是类测试用例2222 %%")
@pytest.mark.skip(reason="类也可以跳过不执行")
class TestSkip:
def test_1(self):
print("%% 不会执行 %%")
!pytest skip_skipif.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 5 items [0m
skip_skipif.py [32m.[0m[33ms[0m[32m.[0m[33ms[0m[33ms[0m[32m [100%][0m
[32m========================= [32m[1m2 passed[0m, [33m3 skipped[0m[32m in 0.02s[0m[32m =========================[0m
def test_function():
n = 1
while True:
print(f"这是我第{n}条用例")
n += 1
if n == 5:
pytest.skip("我跑五次了不跑了")
test_function()
这是我第1条用例
这是我第2条用例
这是我第3条用例
这是我第4条用例
---------------------------------------------------------------------------
Skipped Traceback (most recent call last)
<ipython-input-76-4408d6b29e56> in <module>
7 pytest.skip("我跑五次了不跑了")
8
----> 9 test_function()
<ipython-input-76-4408d6b29e56> in test_function()
5 n += 1
6 if n == 5:
----> 7 pytest.skip("我跑五次了不跑了")
8
9 test_function()
~/.local/lib/python3.6/site-packages/_pytest/outcomes.py in skip(msg, allow_module_level)
143 """
144 __tracebackhide__ = True
--> 145 raise Skipped(msg=msg, allow_module_level=allow_module_level)
146
147
Skipped: 我跑五次了不跑了
当 allow_module_level=True,可以设置在模块级别跳过整个模块
import sys
import pytest
if sys.platform.startswith("win"):
pytest.skip("skipping windows-only tests", allow_module_level=True)
@pytest.fixture(autouse=True)
def login():
print("====登录====")
def test_case01():
print("我是测试用例11111")
!pytest skip_allow_module_level.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
skip_allow_module_level.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
@pytest.mark.skipif(sys.platform == ‘linux‘, reason="does not run on windows")
class TestSkipIf(object):
def test_function(self):
print("不能在window上运行")
!pytest skip_makr_skipif.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 1 item [0m
skip_makr_skipif.py [32m.[0m[32m [100%][0m
[32m============================== [32m[1m1 passed[0m[32m in 0.01s[0m[32m ===============================[0m
# 标记
skipmark = pytest.mark.skip(reason="不能在window上运行=====")
skipifmark = pytest.mark.skipif(sys.platform == ‘win32‘, reason="不能在window上运行啦啦啦=====")
@skipmark
class TestSkip_Mark(object):
@skipifmark
def test_function(self):
print("测试标记")
def test_def(self):
print("测试标记")
@skipmark
def test_skip():
print("测试标记")
!pytest skip_variable.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
collected 3 items [0m
skip_variable.py [33ms[0m[33ms[0m[33ms[0m[33m [100%][0m
[33m============================== [33m[1m3 skipped[0m[33m in 0.01s[0m[33m ==============================[0m
作用:如果缺少某些导入,则跳过模块中的所有测试
参数列表
pexpect = pytest.importorskip("pexpect", minversion="0.3")
@pexpect
def test_import():
print("test")
!pytest skip_importtoskip.py
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-88-05d178e742c2> in <module>
2
3
----> 4 @pexpect
5 def test_import():
6 print("test")
TypeError: ‘module‘ object is not callable
pytest 可以支持自定义标记,自定义标记可以把一个 web 项目划分多个模块,然后指定模块名称执行
import pytest
@pytest.mark.toutiao
def test_toutiao():
print("测试头条")
@pytest.mark.weibo
def test_weibo():
print("测试微博")
@pytest.mark.toutiao
def test_toutiao1():
print("再次测试头条")
@pytest.mark.xinlang
class TestClass:
def test_method(self):
print("测试新浪")
"""没有标记测试"""
def test_nomark():
print("没有标记测试")
!pytest -s -m weibo mark/mark.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 5 items / 4 deselected / 1 selected [0m
mark/mark.py 测试微博
[32m.[0m
[33m=============================== warnings summary ===============================[0m
mark/mark.py:4
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:4: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:12
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:12: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:16
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:16: PytestUnknownMarkWarning: Unknown pytest.mark.xinlang - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.xinlang
-- Docs: https://docs.pytest.org/en/latest/warnings.html
[33m================= [32m1 passed[0m, [33m[1m4 deselected[0m, [33m[1m3 warnings[0m[33m in 0.02s[0m[33m ==================[0m
"""
问题:上面的执行结果是有 warning 的
解决方案:在 同级目录 下添加 pytest.ini 配置文件,加上自定义mark
注意:pytest.ini需要和运行的测试用例同一个目录,或在根目录下作用于全局
"""
!pytest -s -m weibo mark/mark.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 5 items / 4 deselected / 1 selected [0m
mark/mark.py 测试微博
[32m.[0m
[33m=============================== warnings summary ===============================[0m
mark/mark.py:4
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:4: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:12
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:12: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:16
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:16: PytestUnknownMarkWarning: Unknown pytest.mark.xinlang - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.xinlang
-- Docs: https://docs.pytest.org/en/latest/warnings.html
[33m================= [32m1 passed[0m, [33m[1m4 deselected[0m, [33m[1m3 warnings[0m[33m in 0.01s[0m[33m ==================[0m
"""如果不想执行标记 weibo 的用例,取反即可"""
!pytest -s -m "no weibo" mark/mark.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 5 items [0m
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/mark/legacy.py", line 86, in matchmark
INTERNALERROR> return eval(markexpr, {}, MarkMapping.from_item(colitem))
INTERNALERROR> File "<string>", line 1
INTERNALERROR> no weibo
INTERNALERROR> ^
INTERNALERROR> SyntaxError: unexpected EOF while parsing
INTERNALERROR>
INTERNALERROR> During handling of the above exception, another exception occurred:
INTERNALERROR>
INTERNALERROR> Traceback (most recent call last):
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/main.py", line 191, in wrap_session
INTERNALERROR> session.exitstatus = doit(config, session) or 0
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/main.py", line 246, in _main
INTERNALERROR> config.hook.pytest_collection(session=session)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/manager.py", line 87, in <lambda>
INTERNALERROR> firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/main.py", line 257, in pytest_collection
INTERNALERROR> return session.perform_collect()
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/main.py", line 455, in perform_collect
INTERNALERROR> session=self, config=self.config, items=items
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/hooks.py", line 286, in __call__
INTERNALERROR> return self._hookexec(self, self.get_hookimpls(), kwargs)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/manager.py", line 93, in _hookexec
INTERNALERROR> return self._inner_hookexec(hook, methods, kwargs)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/manager.py", line 87, in <lambda>
INTERNALERROR> firstresult=hook.spec.opts.get("firstresult") if hook.spec else False,
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 208, in _multicall
INTERNALERROR> return outcome.get_result()
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 80, in get_result
INTERNALERROR> raise ex[1].with_traceback(ex[2])
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/pluggy/callers.py", line 187, in _multicall
INTERNALERROR> res = hook_impl.function(*args)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/mark/__init__.py", line 151, in pytest_collection_modifyitems
INTERNALERROR> deselect_by_mark(items, config)
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/mark/__init__.py", line 139, in deselect_by_mark
INTERNALERROR> if matchmark(item, matchexpr):
INTERNALERROR> File "/home/ubuntu/.local/lib/python3.6/site-packages/_pytest/mark/legacy.py", line 88, in matchmark
INTERNALERROR> raise SyntaxError(str(e) + "\nMarker expression must be valid Python!")
INTERNALERROR> File "<string>", line None
INTERNALERROR> SyntaxError: unexpected EOF while parsing (<string>, line 1)
INTERNALERROR> Marker expression must be valid Python!
[33m============================= [33m[1m3 warnings[0m[33m in 0.02s[0m[33m ==============================[0m
"""执行多个自定义标记的用例"""
!pytest -s -m "toutiao or weibo" mark/mark.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 5 items / 2 deselected / 3 selected [0m
mark/mark.py 测试头条
[32m.[0m测试微博
[32m.[0m再次测试头条
[32m.[0m
[33m=============================== warnings summary ===============================[0m
mark/mark.py:4
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:4: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:12
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:12: PytestUnknownMarkWarning: Unknown pytest.mark.toutiao - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.toutiao
mark/mark.py:16
/home/ubuntu/MySpace/Python/pytest/mark/mark.py:16: PytestUnknownMarkWarning: Unknown pytest.mark.xinlang - is this a typo? You can register custom marks to avoid this warning - for details, see https://docs.pytest.org/en/latest/mark.html
@pytest.mark.xinlang
-- Docs: https://docs.pytest.org/en/latest/warnings.html
[33m================= [32m3 passed[0m, [33m[1m2 deselected[0m, [33m[1m3 warnings[0m[33m in 0.02s[0m[33m ==================[0m
pytest允许在多个级别启用测试参数化:
那么什么情况下可以使用参数化呢?
——只有测试数据和期望结果不一样,但操作步骤是一样的测试用例可以用上参数化,例如下面的例子
def add_sample(a, b):
return a + b
def test_1():
assert 3 + 5 == 9
def test_2():
assert 2 + 4 == 6
def test_3():
assert 6 * 9 == 42
实际应用场景:实际Web UI自动化中的开发场景,比如是一个登录框
"""将上面重复的代码参数化"""
import pytest
@pytest.mark.parametrize("test_input, excepted", [("3+5", 8), ("2+4", 6), ("6*9", 42)])
def test_eval(test_input, excepted):
print(f"测试数据{test_input}, 期望结果{excepted}")
assert eval(test_input) == excepted
!pytest mark/mark_parametrize.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 3 items [0m
mark/mark_parametrize.py [32m.[0m[32m.[0m[31mF[0m[31m [100%][0m
=================================== FAILURES ===================================
[31m[1m______________________________ test_eval[6*9-42] _______________________________[0m
test_input = ‘6*9‘, excepted = 42
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mtest_input, excepted[39;49;00m[33m"[39;49;00m, [([33m"[39;49;00m[33m3+5[39;49;00m[33m"[39;49;00m, [94m8[39;49;00m), ([33m"[39;49;00m[33m2+4[39;49;00m[33m"[39;49;00m, [94m6[39;49;00m), ([33m"[39;49;00m[33m6*9[39;49;00m[33m"[39;49;00m, [94m42[39;49;00m)])
[94mdef[39;49;00m [92mtest_eval[39;49;00m(test_input, excepted):
[96mprint[39;49;00m([33mf[39;49;00m[33m"[39;49;00m[33m测试数据[39;49;00m[33m{[39;49;00mtest_input[33m}[39;49;00m[33m, 期望结果[39;49;00m[33m{[39;49;00mexcepted[33m}[39;49;00m[33m"[39;49;00m)
> [94massert[39;49;00m [96meval[39;49;00m(test_input) == excepted
[1m[31mE AssertionError: assert 54 == 42[0m
[1m[31mE + where 54 = eval(‘6*9‘)[0m
[1m[31mmark/mark_parametrize.py[0m:6: AssertionError
----------------------------- Captured stdout call -----------------------------
测试数据6*9, 期望结果42
=========================== short test summary info ============================
FAILED mark/mark_parametrize.py::test_eval[6*9-42] - AssertionError: assert 5...
[31m========================= [31m[1m1 failed[0m, [32m2 passed[0m[31m in 0.11s[0m[31m ==========================[0m
def parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):
pass
@pytest.mark.parametrize(["name", "pwd"], [("yy1", "123"), ("yy2", "123")]) # 错的
@pytest.mark.parametrize(("name", "pwd"), [("yy1", "123"), ("yy2", "123")]) # 错的
@pytest.mark.parametrize("name,pwd", [("yy1", "123"), ("yy2", "123")])
argvalues
ids
indirect
当装饰器 @pytest.mark.parametrize 装饰测试类时,会将数据集合传递给类的所有测试用例方法
import pytest
data_1 = [1, 2, 3]
@pytest.mark.parametrize(‘a, b, expect‘, data_1)
class TestParametrize:
def test_parametrize_1(self, a, b, expect):
print(‘\n测试函数11111 测试数据为\n{}-{}‘.format(a, b))
assert a + b == expect
def test_parametrize_2(self, a, b, expect):
print(‘\n测试函数22222 测试数据为\n{}-{}‘.format(a, b))
assert a + b == expect
!pytest -v mark/mark_class_parametrize.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 0 items / 1 error [0m
==================================== ERRORS ====================================
[31m[1m__________________ ERROR collecting mark_class_parametrize.py __________________[0m
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/hooks.py[0m:286: in __call__
[94mreturn[39;49;00m [96mself[39;49;00m._hookexec([96mself[39;49;00m, [96mself[39;49;00m.get_hookimpls(), kwargs)
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/manager.py[0m:93: in _hookexec
[94mreturn[39;49;00m [96mself[39;49;00m._inner_hookexec(hook, methods, kwargs)
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/manager.py[0m:87: in <lambda>
firstresult=hook.spec.opts.get([33m"[39;49;00m[33mfirstresult[39;49;00m[33m"[39;49;00m) [94mif[39;49;00m hook.spec [94melse[39;49;00m [94mFalse[39;49;00m,
[1m[31m../../../.local/lib/python3.6/site-packages/_pytest/python.py[0m:248: in pytest_pycollect_makeitem
res = [96mlist[39;49;00m(collector._genfunctions(name, obj))
[1m[31m../../../.local/lib/python3.6/site-packages/_pytest/python.py[0m:415: in _genfunctions
[96mself[39;49;00m.ihook.pytest_generate_tests.call_extra(methods, [96mdict[39;49;00m(metafunc=metafunc))
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/hooks.py[0m:324: in call_extra
[94mreturn[39;49;00m [96mself[39;49;00m(**kwargs)
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/hooks.py[0m:286: in __call__
[94mreturn[39;49;00m [96mself[39;49;00m._hookexec([96mself[39;49;00m, [96mself[39;49;00m.get_hookimpls(), kwargs)
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/manager.py[0m:93: in _hookexec
[94mreturn[39;49;00m [96mself[39;49;00m._inner_hookexec(hook, methods, kwargs)
[1m[31m../../../.local/lib/python3.6/site-packages/pluggy/manager.py[0m:87: in <lambda>
firstresult=hook.spec.opts.get([33m"[39;49;00m[33mfirstresult[39;49;00m[33m"[39;49;00m) [94mif[39;49;00m hook.spec [94melse[39;49;00m [94mFalse[39;49;00m,
[1m[31m../../../.local/lib/python3.6/site-packages/_pytest/python.py[0m:139: in pytest_generate_tests
metafunc.parametrize(*marker.args, **marker.kwargs, _param_mark=marker) [90m# type: ignore[misc] # noqa: F821[39;49;00m
[1m[31m../../../.local/lib/python3.6/site-packages/_pytest/python.py[0m:922: in parametrize
function_definition=[96mself[39;49;00m.definition,
[1m[31m../../../.local/lib/python3.6/site-packages/_pytest/mark/structures.py[0m:114: in _for_parametrize
[94mif[39;49;00m [96mlen[39;49;00m(param.values) != [96mlen[39;49;00m(argnames):
[1m[31mE TypeError: object of type ‘int‘ has no len()[0m
=========================== short test summary info ============================
ERROR mark/mark_class_parametrize.py::TestParametrize - TypeError: object of ...
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
[31m=============================== [31m[1m1 error[0m[31m in 0.37s[0m[31m ===============================[0m
"""笛卡尔积,组合数据"""
import pytest
data_1 = [1, 2, 3]
data_2 = [‘a‘, ‘b‘]
@pytest.mark.parametrize(‘a‘, data_1)
@pytest.mark.parametrize(‘b‘, data_2)
def test_parametrize_1(a, b):
print(f‘笛卡尔积 测试数据为 : {a},{b}‘)
!pytest -v mark/mark_many_parametrize.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 6 items [0m
mark/mark_many_parametrize.py::test_parametrize_1[a-1] [32mPASSED[0m[32m [ 16%][0m
mark/mark_many_parametrize.py::test_parametrize_1[a-2] [32mPASSED[0m[32m [ 33%][0m
mark/mark_many_parametrize.py::test_parametrize_1[a-3] [32mPASSED[0m[32m [ 50%][0m
mark/mark_many_parametrize.py::test_parametrize_1[b-1] [32mPASSED[0m[32m [ 66%][0m
mark/mark_many_parametrize.py::test_parametrize_1[b-2] [32mPASSED[0m[32m [ 83%][0m
mark/mark_many_parametrize.py::test_parametrize_1[b-3] [32mPASSED[0m[32m [100%][0m
[32m============================== [32m[1m6 passed[0m[32m in 0.03s[0m[32m ===============================[0m
"""字典"""
import pytest
data_1 = (
{
‘user‘: 1,
‘pwd‘: 2
},
{
‘user‘: 3,
‘pwd‘: 4
}
)
@pytest.mark.parametrize(‘dic‘, data_1)
def test_parametrize_1(dic):
print(f‘测试数据为\n{dic}‘)
print(f‘user:{dic["user"]},pwd{dic["pwd"]}‘)
!pytest -s mark/mark_dict_parametrize.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
collected 2 items [0m
mark/mark_dict_parametrize.py 测试数据为
{‘user‘: 1, ‘pwd‘: 2}
user:1,pwd2
[32m.[0m测试数据为
{‘user‘: 3, ‘pwd‘: 4}
user:3,pwd4
[32m.[0m
[32m============================== [32m[1m2 passed[0m[32m in 0.01s[0m[32m ===============================[0m
"""标记参数化"""
import pytest
@pytest.mark.parametrize("test_input,expected", [
("3+5", 8),
("2+4", 6),
pytest.param("6 * 9", 42, marks=pytest.mark.xfail),
pytest.param("6*6", 42, marks=pytest.mark.skip)
])
def test_mark(test_input, expected):
assert eval(test_input) == expected
!pytest -v mark/mark_mark_data.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest/mark, inifile: pytest.ini
plugins: rerunfailures-9.0, repeat-0.8.0
collected 4 items [0m
mark/mark_mark_data.py::test_mark[3+5-8] [32mPASSED[0m[32m [ 25%][0m
mark/mark_mark_data.py::test_mark[2+4-6] [32mPASSED[0m[32m [ 50%][0m
mark/mark_mark_data.py::test_mark[6 * 9-42] [33mXFAIL[0m[32m [ 75%][0m
mark/mark_mark_data.py::test_mark[6*6-42] [33mSKIPPED[0m[32m [100%][0m
[32m=================== [32m[1m2 passed[0m, [33m1 skipped[0m, [33m1 xfailed[0m[32m in 0.04s[0m[32m ====================[0m
"""增加可读性"""
import pytest
data_1 = [
(1, 2, 3),
(4, 5, 9)
]
ids = ["a:{} + b:{} = expect:{}".format(a, b, expect) for a, b, expect in data_1]
@pytest.mark.parametrize(‘a, b, expect‘, data_1, ids=ids)
class TestParametrize(object):
def test_parametrize_1(self, a, b, expect):
print(‘测试函数1测试数据为{}-{}‘.format(a, b))
assert a + b == expect
def test_parametrize_2(self, a, b, expect):
print(‘测试函数2数据为{}-{}‘.format(a, b))
assert a + b == expect
!pytest -v mark/mark_read.py
多少组数据,就要有多少个id,然后组成一个id的列表
作用:主要是为了更加清晰看到用例的含义
pytest配置文件可以改变pytest的运行方式,它是一个固定的文件pytest.ini文件,读取配置信息,按指定的方式去运行
pytest里面有些文件是非test文件
"""查看pytest.ini的配置选项"""
!pytest --help
usage: pytest [options] [file_or_dir] [file_or_dir] [...]
positional arguments:
file_or_dir
general:
-k EXPRESSION only run tests which match the given substring
expression. An expression is a python evaluatable
expression where all names are substring-matched against
test names and their parent classes. Example: -k
‘test_method or test_other‘ matches all test functions
and classes whose name contains ‘test_method‘ or
‘test_other‘, while -k ‘not test_method‘ matches those
that don‘t contain ‘test_method‘ in their names. -k ‘not
test_method and not test_other‘ will eliminate the
matches. Additionally keywords are matched to classes
and functions containing extra names in their
‘extra_keyword_matches‘ set, as well as functions which
have names assigned directly to them. The matching is
case-insensitive.
-m MARKEXPR only run tests matching given mark expression. example:
-m ‘mark1 and not mark2‘.
--markers show markers (builtin, plugin and per-project ones).
-x, --exitfirst exit instantly on first error or failed test.
--maxfail=num exit after first num failures or errors.
--strict-markers, --strict
markers not registered in the `markers` section of the
configuration file raise errors.
-c file load configuration from `file` instead of trying to
locate one of the implicit configuration files.
--continue-on-collection-errors
Force test execution even if collection errors occur.
--rootdir=ROOTDIR Define root directory for tests. Can be relative path:
‘root_dir‘, ‘./root_dir‘, ‘root_dir/another_dir/‘;
absolute path: ‘/home/user/root_dir‘; path with
variables: ‘$HOME/root_dir‘.
--fixtures, --funcargs
show available fixtures, sorted by plugin appearance
(fixtures with leading ‘_‘ are only shown with ‘-v‘)
--fixtures-per-test show fixtures per test
--import-mode={prepend,append}
prepend/append to sys.path when importing test modules,
default is to prepend.
--pdb start the interactive Python debugger on errors or
KeyboardInterrupt.
--pdbcls=modulename:classname
start a custom interactive Python debugger on errors.
For example:
--pdbcls=IPython.terminal.debugger:TerminalPdb
--trace Immediately break when running each test.
--capture=method per-test capturing method: one of fd|sys|no|tee-sys.
-s shortcut for --capture=no.
--runxfail report the results of xfail tests as if they were not
marked
--lf, --last-failed rerun only the tests that failed at the last run (or all
if none failed)
--ff, --failed-first run all tests but run the last failures first. This may
re-order tests and thus lead to repeated fixture
setup/teardown
--nf, --new-first run tests from new files first, then the rest of the
tests sorted by file mtime
--cache-show=[CACHESHOW]
show cache contents, don‘t perform collection or tests.
Optional argument: glob (default: ‘*‘).
--cache-clear remove all cache contents at start of test run.
--lfnf={all,none}, --last-failed-no-failures={all,none}
which tests to run with no previously (known) failures.
--sw, --stepwise exit on test failure and continue from last failing test
next time
--stepwise-skip ignore the first failing test but stop on the next
failing test
reporting:
--durations=N show N slowest setup/test durations (N=0 for all).
-v, --verbose increase verbosity.
-q, --quiet decrease verbosity.
--verbosity=VERBOSE set verbosity. Default is 0.
-r chars show extra test summary info as specified by chars:
(f)ailed, (E)rror, (s)kipped, (x)failed, (X)passed,
(p)assed, (P)assed with output, (a)ll except passed
(p/P), or (A)ll. (w)arnings are enabled by default (see
--disable-warnings), ‘N‘ can be used to reset the list.
(default: ‘fE‘).
--disable-warnings, --disable-pytest-warnings
disable warnings summary
-l, --showlocals show locals in tracebacks (disabled by default).
--tb=style traceback print mode (auto/long/short/line/native/no).
--show-capture={no,stdout,stderr,log,all}
Controls how captured stdout/stderr/log is shown on
failed tests. Default is ‘all‘.
--full-trace don‘t cut any tracebacks (default is to cut).
--color=color color terminal output (yes/no/auto).
--pastebin=mode send failed|all info to bpaste.net pastebin service.
--junit-xml=path create junit-xml style report file at given path.
--junit-prefix=str prepend prefix to classnames in junit-xml output
--result-log=path DEPRECATED path for machine-readable result log.
collection:
--collect-only, --co only collect tests, don‘t execute them.
--pyargs try to interpret all arguments as python packages.
--ignore=path ignore path during collection (multi-allowed).
--ignore-glob=path ignore path pattern during collection (multi-allowed).
--deselect=nodeid_prefix
deselect item (via node id prefix) during collection
(multi-allowed).
--confcutdir=dir only load conftest.py‘s relative to specified dir.
--noconftest Don‘t load any conftest.py files.
--keep-duplicates Keep duplicate tests.
--collect-in-virtualenv
Don‘t ignore tests in a local virtualenv directory
--doctest-modules run doctests in all .py modules
--doctest-report={none,cdiff,ndiff,udiff,only_first_failure}
choose another output format for diffs on doctest
failure
--doctest-glob=pat doctests file matching pattern, default: test*.txt
--doctest-ignore-import-errors
ignore doctest ImportErrors
--doctest-continue-on-failure
for a given doctest, continue to run after the first
failure
test session debugging and configuration:
--basetemp=dir base temporary directory for this test run.(warning:
this directory is removed if it exists)
-V, --version display pytest version and information about plugins.
-h, --help show help message and configuration info
-p name early-load given plugin module name or entry point
(multi-allowed). To avoid loading of plugins, use the
`no:` prefix, e.g. `no:doctest`.
--trace-config trace considerations of conftest.py files.
--debug store internal tracing debug information in
‘pytestdebug.log‘.
-o OVERRIDE_INI, --override-ini=OVERRIDE_INI
override ini option with "option=value" style, e.g. `-o
xfail_strict=True -o cache_dir=cache`.
--assert=MODE Control assertion debugging tools. ‘plain‘ performs no
assertion debugging. ‘rewrite‘ (the default) rewrites
assert statements in test modules on import to provide
assert expression information.
--setup-only only setup fixtures, do not execute tests.
--setup-show show setup of fixtures while executing tests.
--setup-plan show what fixtures and tests would be executed but don‘t
execute anything.
pytest-warnings:
-W PYTHONWARNINGS, --pythonwarnings=PYTHONWARNINGS
set which warnings to report, see -W option of python
itself.
logging:
--no-print-logs disable printing caught logs on failed tests.
--log-level=LEVEL level of messages to catch/display. Not set by default,
so it depends on the root/parent log handler‘s effective
level, where it is "WARNING" by default.
--log-format=LOG_FORMAT
log format as used by the logging module.
--log-date-format=LOG_DATE_FORMAT
log date format as used by the logging module.
--log-cli-level=LOG_CLI_LEVEL
cli logging level.
--log-cli-format=LOG_CLI_FORMAT
log format as used by the logging module.
--log-cli-date-format=LOG_CLI_DATE_FORMAT
log date format as used by the logging module.
--log-file=LOG_FILE path to a file when logging will be written to.
--log-file-level=LOG_FILE_LEVEL
log file logging level.
--log-file-format=LOG_FILE_FORMAT
log format as used by the logging module.
--log-file-date-format=LOG_FILE_DATE_FORMAT
log date format as used by the logging module.
--log-auto-indent=LOG_AUTO_INDENT
Auto-indent multiline messages passed to the logging
module. Accepts true|on, false|off or an integer.
re-run failing tests to eliminate flaky failures:
--reruns=RERUNS number of times to re-run failed tests. defaults to 0.
--reruns-delay=RERUNS_DELAY
add time (seconds) delay between reruns.
custom options:
--count=COUNT Number of times to repeat each test
--repeat-scope={function,class,module,session}
Scope for repeating tests
[pytest] ini-options in the first pytest.ini|tox.ini|setup.cfg file found:
markers (linelist): markers for test functions
empty_parameter_set_mark (string):
default marker for empty parametersets
norecursedirs (args): directory patterns to avoid for recursion
testpaths (args): directories to search for tests when no files or
directories are given in the command line.
usefixtures (args): list of default fixtures to be used with this project
python_files (args): glob-style file patterns for Python test module
discovery
python_classes (args):
prefixes or glob names for Python test class discovery
python_functions (args):
prefixes or glob names for Python test function and
method discovery
disable_test_id_escaping_and_forfeit_all_rights_to_community_support (bool):
disable string escape non-ascii characters, might cause
unwanted side effects(use at your own risk)
console_output_style (string):
console output: "classic", or with additional progress
information ("progress" (percentage) | "count").
xfail_strict (bool): default for the strict parameter of xfail markers when
not given explicitly (default: False)
enable_assertion_pass_hook (bool):
Enables the pytest_assertion_pass hook.Make sure to
delete any previously generated pyc cache files.
junit_suite_name (string):
Test suite name for JUnit report
junit_logging (string):
Write captured log messages to JUnit report: one of
no|log|system-out|system-err|out-err|all
junit_log_passing_tests (bool):
Capture log information for passing tests to JUnit
report:
junit_duration_report (string):
Duration time to report: one of total|call
junit_family (string):
Emit XML for schema: one of legacy|xunit1|xunit2
doctest_optionflags (args):
option flags for doctests
doctest_encoding (string):
encoding used for doctest files
cache_dir (string): cache directory path.
filterwarnings (linelist):
Each line specifies a pattern for
warnings.filterwarnings. Processed after
-W/--pythonwarnings.
log_print (bool): default value for --no-print-logs
log_level (string): default value for --log-level
log_format (string): default value for --log-format
log_date_format (string):
default value for --log-date-format
log_cli (bool): enable log display during test run (also known as "live
logging").
log_cli_level (string):
default value for --log-cli-level
log_cli_format (string):
default value for --log-cli-format
log_cli_date_format (string):
default value for --log-cli-date-format
log_file (string): default value for --log-file
log_file_level (string):
default value for --log-file-level
log_file_format (string):
default value for --log-file-format
log_file_date_format (string):
default value for --log-file-date-format
log_auto_indent (string):
default value for --log-auto-indent
faulthandler_timeout (string):
Dump the traceback of all threads if a test takes more
than TIMEOUT seconds to finish. Not available on
Windows.
addopts (args): extra command line options
minversion (string): minimally required pytest version
environment variables:
PYTEST_ADDOPTS extra command line options
PYTEST_PLUGINS comma-separated plugins to load during startup
PYTEST_DISABLE_PLUGIN_AUTOLOAD set to disable plugin auto-loading
PYTEST_DEBUG set to enable debug tracing of pytest‘s internals
to see available markers type: pytest --markers
to see available fixtures type: pytest --fixtures
(shown according to specified file_or_dir or current dir if not specified; fixtures with leading ‘_‘ are only shown with the ‘-v‘ option
[pytest]
markers =
weibo: this is weibo page
toutiao: toutiao
xinlang: xinlang
[pytest]
# mark标记说明
markers =
weibo: this is weibo page
toutiao: toutiao
xinlang: xinlang
xfail_strict = True
pytest -v --rerun=2 --count=2 --html=report.html --self-contained-html -n=auto
[pytest]
# mark
markers =
weibo: this is weibo page
toutiao: toutiao
xinlang: xinlang
xfail_strict = True
# 命令行参数
addopts = -v --reruns=1 --count=2 --html=reports.html --self-contained-html -n=auto
加了addopts之后,我们在cmd中只需要敲pytest就可以生效了!!
作用:控制台实时输出日志
格式:log_cli=True 或False(默认),或者log_cli=1 或 0
log_cli=0的运行结果
log_cli=1的运行结果
很明显,加了log_cli=1之后,可以清晰看到哪个package下的哪个module下的哪个测试用例是否passed还是failed;
所以平时测试代码是否有问题的情况下推荐加!!!但如果拿去批量跑测试用例的话不建议加,谁知道会不会影响运行性能呢?
[pytest]
norecursedirs = .* build dist CVS _darcs {arch} *.egg venv src resources log report util
pytest默认的测试用例收集规则
我们是可以修改或者添加这个用例收集规则的;当然啦,是建议在原有的规则上添加的,如下配置
[pytest]
python_files = test_* *_test test*
python_classes = Test* test*
python_functions = test_* test*
环境要求:
安装插件
#!pip3 install pytest-rerunfailures -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Collecting pytest-rerunfailures
Downloading http://pypi.doubanio.com/packages/25/91/a0d1ff828e6da1915e4972d76ea2b5f9a1b520f078b4197ef93eb8427b65/pytest_rerunfailures-9.0-py3-none-any.whl
Collecting pytest>=5.0 (from pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 23.5MB/s ta 0:00:01
[?25hCollecting setuptools>=40.0 (from pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/a0/df/635cdb901ee4a8a42ec68e480c49f85f4c59e8816effbf57d9e6ee8b3588/setuptools-46.1.3-py3-none-any.whl (582kB)
[K 100% |████████████████████████████████| 583kB 18.0MB/s ta 0:00:01
[?25hCollecting attrs>=17.4.0 (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting pluggy<1.0,>=0.12 (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting packaging (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 48.5MB/s ta 0:00:01
[?25hCollecting more-itertools>=4.0.0 (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 46.9MB/s ta 0:00:01
[?25hCollecting wcwidth (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 49.6MB/s ta 0:00:01
[?25hCollecting six (from packaging->pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest>=5.0->pytest-rerunfailures)
Downloading http://pypi.doubanio.com/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Installing collected packages: attrs, zipp, importlib-metadata, pluggy, pyparsing, six, packaging, py, more-itertools, wcwidth, pytest, setuptools, pytest-rerunfailures
Successfully installed attrs-19.3.0 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 pytest-rerunfailures-9.0 setuptools-46.1.3 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
命令行参数:--reruns n(重新运行次数),--reruns-delay m(等待运行秒数)
装饰器参数:reruns=n(重新运行次数),reruns_delay=m(等待运行秒数)
要重新运行所有测试失败,使用 --reruns 命令行选项,并指定要运行测试的最大次数:pytest --rerun 5 -s
运行失败的fixture或setup_class也将重新执行
要在两次重试之间增加延迟时间,使用 --reruns-delay 命令行选项,指定下次测试重新开始之前等待的秒数:pytest --reruns 5 --reruns-delay 10 -s
要将单个测试用例添加flaky装饰器 @pytest.mark.flaky(reruns=5) ,并在测试失败时自动重新运行,需要指定最大重新运行的次数
"""重新运行指定的测试用例"""
import pytest
import random
@pytest.mark.flasky(reruns=5, reruns_delay=2)
def test_example():
assert random.choice([True, False, False])
!pytest -v -s plug/pytest_rerunfailures.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: rerunfailures-9.0
collected 0 items / 1 error [0m
==================================== ERRORS ====================================
[31m[1m________________ ERROR collecting plug/pytest_rerunfailures.py _________________[0m
[31mimport file mismatch:
imported module ‘pytest_rerunfailures‘ has this __file__ attribute:
/home/ubuntu/.local/lib/python3.6/site-packages/pytest_rerunfailures.py
which is not the same as the test file we want to collect:
/home/ubuntu/MySpace/Python/pytest/plug/pytest_rerunfailures.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules[0m
=========================== short test summary info ============================
ERROR plug/pytest_rerunfailures.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
[31m=============================== [31m[1m1 error[0m[31m in 0.09s[0m[31m ===============================[0m
环境要求:
插件安装:
# !pip3 install pytest-repeat -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Collecting pytest-repeat
Downloading http://pypi.doubanio.com/packages/2e/de/c1d69002db74a99b3df0463e95066c03d82d9d2a53be738c140207134e0f/pytest_repeat-0.8.0-py2.py3-none-any.whl
Collecting pytest>=3.6 (from pytest-repeat)
Downloading http://pypi.doubanio.com/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 3.8MB/s ta 0:00:011
[?25hCollecting more-itertools>=4.0.0 (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 1.8MB/s ta 0:00:011
[?25hCollecting pluggy<1.0,>=0.12 (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting attrs>=17.4.0 (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 843kB/s ta 0:00:011
[?25hCollecting wcwidth (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting packaging (from pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Collecting six (from packaging->pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest>=3.6->pytest-repeat)
Downloading http://pypi.doubanio.com/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 40.3MB/s ta 0:00:01
[?25hInstalling collected packages: more-itertools, zipp, importlib-metadata, pluggy, attrs, py, wcwidth, six, pyparsing, packaging, pytest, pytest-repeat
Successfully installed attrs-19.3.0 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 pytest-repeat-0.8.0 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
import pytest
import random
def test_flag():
flag = random.choice([True, False])
print(flag)
assert flag
!pytest -s --count 5 -x plug/test_pytest_repeat.py
[31mERROR: /home/ubuntu/MySpace/Python/pytest/plug/pytest.ini:1: no section header defined
[0m
如果要在代码中将某些测试用例标记为执行重复多次,可以使用 @pytest.mark.repeat(count)
@pytest.mark.repeat(5)
def test_repeat():
print("测试用例执行")
!pytest plug/test_pytest_repeat.py::test_repeat
[31mERROR: /home/ubuntu/MySpace/Python/pytest/plug/pytest.ini:1: no section header defined
[0m
作用:可以覆盖默认的测试用例执行顺序,类似fixture的scope参数
!cat plug/test_pytest_repeat_scope.py
import pytest
class Test_repeat:
def test_repeat3(self):
print("测试用例执行333")
class Test_repeat2:
def test_repeat3(self):
print("测试用例执行444")
def test_repeat1():
print("测试用例执行111")
def test_repeat2():
print("测试用例执行222")
class Test_repeat:
def test_repeat3(self):
print("测试用例执行333")
!pytest -s --count=2 --repeat-scope=class plug/test_pytest_repeat_scope.py
[31mERROR: /home/ubuntu/MySpace/Python/pytest/plug/pytest.ini:1: no section header defined
[0m
!pytest -s --count=2 --repeat-scope=module plug/test_pytest_repeat_scope.py
[31mERROR: /home/ubuntu/MySpace/Python/pytest/plug/pytest.ini:1: no section header defined
[0m
pytest-repeat不能与unittest.TestCase测试类一起使用。无论--count设置多少,这些测试始终仅运行一次,并显示警告
pytest中可以用python的assert断言,也可以写多个断言,但一个失败,后面的断言将不再执行
而 pytest-assume即使中间的断言失败了,还是会执行后面的断言:
# !pip3 install pytest-assume -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Collecting pytest-assume
Downloading http://pypi.doubanio.com/packages/9a/a7/bd0f0289c2978082296936c3899c77b3e738c89fa56ecbaaafd826ec2f52/pytest_assume-2.2.1-py3-none-any.whl
Collecting pytest>=2.7 (from pytest-assume)
Downloading http://pypi.doubanio.com/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 56.4MB/s ta 0:00:01
[?25hCollecting more-itertools>=4.0.0 (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 43.4MB/s ta 0:00:01
[?25hCollecting wcwidth (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 48.0MB/s ta 0:00:01
[?25hCollecting importlib-metadata>=0.12; python_version < "3.8" (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting attrs>=17.4.0 (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting packaging (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting pluggy<1.0,>=0.12 (from pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 35.7MB/s ta 0:00:01
[?25hCollecting six (from packaging->pytest>=2.7->pytest-assume)
Downloading http://pypi.doubanio.com/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Installing collected packages: more-itertools, wcwidth, py, zipp, importlib-metadata, attrs, pyparsing, six, packaging, pluggy, pytest, pytest-assume
Successfully installed attrs-19.3.0 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 pytest-assume-2.2.1 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
def test_add1():
assert 1 + 4 == 5
assert 1 + 3 == 3
assert 2 + 5 == 7
assert 2 + 5 == 9
print("测试完成")
!pytest -v -s plug/more_assert.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: rerunfailures-9.0, assume-2.2.1, repeat-0.8.0
collected 1 item [0m
plug/more_assert.py::test_add1 [31mFAILED[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_add1 ___________________________________[0m
[94mdef[39;49;00m [92mtest_add1[39;49;00m():
[94massert[39;49;00m [94m1[39;49;00m + [94m4[39;49;00m == [94m5[39;49;00m
> [94massert[39;49;00m [94m1[39;49;00m + [94m3[39;49;00m == [94m3[39;49;00m
[1m[31mE assert 4 == 3[0m
[1m[31mE +4[0m
[1m[31mE -3[0m
[1m[31mplug/more_assert.py[0m:3: AssertionError
=========================== short test summary info ============================
FAILED plug/more_assert.py::test_add1 - assert 4 == 3
[31m============================== [31m[1m1 failed[0m[31m in 0.11s[0m[31m ===============================[0m
import pytest
def test_add2():
pytest.assume(1 + 4 == 5)
pytest.assume(1 + 3 == 3)
pytest.assume(2 + 5 == 7)
pytest.assume(2 + 5 == 9)
print("测试完成")
!pytest -v -s plug/more_pytest_assume.py
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1 -- /usr/bin/python3
cachedir: .pytest_cache
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: rerunfailures-9.0, assume-2.2.1, repeat-0.8.0
collected 1 item [0m
plug/more_pytest_assume.py::test_add2 测试完成
[31mFAILED[0m
=================================== FAILURES ===================================
[31m[1m__________________________________ test_add2 ___________________________________[0m
tp = <class ‘pytest_assume.plugin.FailedAssumption‘>, value = None, tb = None
[94mdef[39;49;00m [92mreraise[39;49;00m(tp, value, tb=[94mNone[39;49;00m):
[94mtry[39;49;00m:
[94mif[39;49;00m value [95mis[39;49;00m [94mNone[39;49;00m:
value = tp()
[94mif[39;49;00m value.__traceback__ [95mis[39;49;00m [95mnot[39;49;00m tb:
> [94mraise[39;49;00m value.with_traceback(tb)
[1m[31mE pytest_assume.plugin.FailedAssumption: [0m
[1m[31mE 2 Failed Assumptions:[0m
[1m[31mE [0m
[1m[31mE plug/more_pytest_assume.py:5: AssumptionFailure[0m
[1m[31mE >> pytest.assume(1 + 3 == 3)[0m
[1m[31mE AssertionError: assert False[0m
[1m[31mE [0m
[1m[31mE plug/more_pytest_assume.py:7: AssumptionFailure[0m
[1m[31mE >> pytest.assume(2 + 5 == 9)[0m
[1m[31mE AssertionError: assert False[0m
[1m[31m../../../.local/lib/python3.6/site-packages/six.py[0m:702: FailedAssumption
=========================== short test summary info ============================
FAILED plug/more_pytest_assume.py::test_add2 - pytest_assume.plugin.FailedAss...
[31m============================== [31m[1m1 failed[0m[31m in 0.14s[0m[31m ===============================[0m
应用场景
分布式执行用例设计原则
# !pip3 install pytest-xdist -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Collecting pytest-xdist
Downloading http://pypi.doubanio.com/packages/7c/8c/7f93c1d82f25a69a1c6e68189b9cf5ddce08dcaefdbd913d328b0234e13b/pytest_xdist-1.31.0-py2.py3-none-any.whl
Collecting pytest>=4.4.0 (from pytest-xdist)
Downloading http://pypi.doubanio.com/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 25.6MB/s ta 0:00:01
[?25hCollecting execnet>=1.1 (from pytest-xdist)
Downloading http://pypi.doubanio.com/packages/d3/2e/c63af07fa471e0a02d05793c7a56a9f7d274a8489442a5dc4fb3b2b3c705/execnet-1.7.1-py2.py3-none-any.whl
Collecting pytest-forked (from pytest-xdist)
Downloading http://pypi.doubanio.com/packages/03/1e/81235e1fcfed57a4e679d34794d60c01a1e9a29ef5b9844d797716111d80/pytest_forked-1.1.3-py2.py3-none-any.whl
Collecting six (from pytest-xdist)
Downloading http://pypi.doubanio.com/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting more-itertools>=4.0.0 (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 49.0MB/s ta 0:00:01
[?25hCollecting pluggy<1.0,>=0.12 (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting wcwidth (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting packaging (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 15.7MB/s ta 0:00:01 73% |███████████████████████▌ | 61kB 30.9MB/s eta 0:00:01
[?25hCollecting attrs>=17.4.0 (from pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting apipkg>=1.4 (from execnet>=1.1->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/67/08/4815a09603fc800209431bec5b8bd2acf2f95abdfb558a44a42507fb94da/apipkg-1.5-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest>=4.4.0->pytest-xdist)
Downloading http://pypi.doubanio.com/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 33.0MB/s ta 0:00:01
[?25hInstalling collected packages: more-itertools, zipp, importlib-metadata, pluggy, wcwidth, pyparsing, six, packaging, py, attrs, pytest, apipkg, execnet, pytest-forked, pytest-xdist
Successfully installed apipkg-1.5 attrs-19.3.0 execnet-1.7.1 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 pytest-forked-1.1.3 pytest-xdist-1.31.0 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
xdist的分布式类似于一主多从的结构,master机负责下发命令,控制slave机;slave机根据master机的命令执行特定测试任务
在xdist中,主是master,从是workers
大致原理:
注意:所以为什么上面通过分布式测试的结果截图是没有输出用例的print内容,因为主机并不执行测试用例,pycharm相当于一个master
--dist-mode选项
each:master将完整的测试索引列表分发到每个worker
load:master将大约25%的测试用例以轮询的方式分发到各个worker,剩余的测试用例则会等待workers执行完测试用例以后再分发
注意:可以使用 pytest_xdist_make_scheduler 这个hook来实现自定义测试分发逻辑。
pytest-xdist默认是无序执行的,可以通过 --dist 参数来控制顺序
--dist=loadscope
--dist=loadfile
按照同一个文件名来分组,然后将每个测试组发给可以执行的worker,确保同一个组的测试用例在同一个进程中执行
pytest-xdist是让每个worker进程执行属于自己的测试用例集下的所有测试用例
这意味着在不同进程中,不同的测试用例可能会调用同一个scope范围级别较高(例如session)的fixture,该fixture则会被执行多次,这不符合scope=session的预期
解决方案:虽然pytest-xdist没有内置的支持来确保会话范围的夹具仅执行一次,但是可以通过使用锁定文件进行进程间通信来实现。
import pytest
from filelock import FileLock
@pytest.fixture(scope="session")
def login():
print("====登录功能,返回账号,token===")
with FileLock("session.lock"):
name = "testyy"
token = "npoi213bn4"
# web ui自动化
# 声明一个driver,再返回
# 接口自动化
# 发起一个登录请求,将token返回都可以这样写
yield name, token
print("====退出登录!!!====")
"""测试项目架构"""
!tree plug/pytest_xdist/
[01;34mplug/pytest_xdist/[00m
├── conftest.py
├── test_1.py
├── [01;34mtest_job[00m
│?? ├── conftest.py
│?? └── test_case1.py
├── [01;34mtest_toutiao[00m
│?? └── test_case2.py
├── [01;34mtest_weibo[00m
│?? ├── conftest.py
│?? └── test_case3.py
└── untitled.txt
3 directories, 8 files
"""不使用分布式执行测试用例"""
!pytest -s plug/pytest_xdist/
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: xdist-1.31.0, rerunfailures-9.0, assume-2.2.1, forked-1.1.3, repeat-0.8.0
collected 30 items [0m
plug/pytest_xdist/test_1.py ====登录功能,返回账号,token===
[31mF[0m[31mF[0m[31mF[0m[31mF[0m[31mF[0m
plug/pytest_xdist/test_job/test_case1.py [31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m
plug/pytest_xdist/test_toutiao/test_case2.py ==没有__init__测试用例,我进入头条了== (‘testyy‘, ‘npoi213bn4‘)
[32m.[0m==没有__init__测试用例,我进入头条了== (‘testyy‘, ‘npoi213bn4‘)
[32m.[0m==没有__init__测试用例,我进入头条了== (‘testyy‘, ‘npoi213bn4‘)
[32m.[0m==没有__init__测试用例,我进入头条了== (‘testyy‘, ‘npoi213bn4‘)
[32m.[0m==没有__init__测试用例,我进入头条了== (‘testyy‘, ‘npoi213bn4‘)
[32m.[0m
plug/pytest_xdist/test_weibo/test_case3.py &&& 用户 testyy 返回微博首页 &&&
查看微博热搜 0
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博热搜 1
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博热搜 2
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博热搜 3
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博热搜 4
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博范冰冰 0
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博范冰冰 1
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博范冰冰 2
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博范冰冰 3
[32m.[0m&&& 用户 testyy 返回微博首页 &&&
查看微博范冰冰 4
[32m.[0m====退出登录!!!====
==================================== ERRORS ====================================
[31m[1m______________________ ERROR at setup of test_case2_01[0] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[1] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[2] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[3] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[4] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_02[0] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[1] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[2] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[3] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[4] ______________________[0m
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
[31mE fixture ‘open_51‘ not found[0m
[31m> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id[0m
[31m> use ‘pytest --fixtures [testpath]‘ for help on them.[0m
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
=================================== FAILURES ===================================
[31m[1m_______________________________ test_get_info[0] _______________________________[0m
login = (‘testyy‘, ‘npoi213bn4‘), n = 0
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[1] _______________________________[0m
login = (‘testyy‘, ‘npoi213bn4‘), n = 1
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[2] _______________________________[0m
login = (‘testyy‘, ‘npoi213bn4‘), n = 2
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[3] _______________________________[0m
login = (‘testyy‘, ‘npoi213bn4‘), n = 3
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[4] _______________________________[0m
login = (‘testyy‘, ‘npoi213bn4‘), n = 4
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
=========================== short test summary info ============================
FAILED plug/pytest_xdist/test_1.py::test_get_info[0] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[1] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[2] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[3] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[4] - NameError: name ‘sleep...
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[0]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[4]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[0]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[4]
[31m=================== [31m[1m5 failed[0m, [32m15 passed[0m, [31m[1m10 errors[0m[31m in 15.27s[0m[31m ===================[0m
"""分布式用例执行"""
!pytest -s -n auto plug/pytest_xdist/
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: xdist-1.31.0, rerunfailures-9.0, assume-2.2.1, forked-1.1.3, repeat-0.8.0
gw0 [30][0mm[1m[1m
[31mF[0m[31mF[0m[31mF[0m[31mF[0m[31mF[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
==================================== ERRORS ====================================
[31m[1m______________________ ERROR at setup of test_case2_01[0] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[1] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[2] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[3] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[4] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_02[0] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[1] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[2] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[3] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[4] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
=================================== FAILURES ===================================
[31m[1m_______________________________ test_get_info[0] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 0
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[1] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 1
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[2] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 2
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[3] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 3
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[4] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 4
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
=========================== short test summary info ============================
FAILED plug/pytest_xdist/test_1.py::test_get_info[0] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[1] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[2] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[3] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[4] - NameError: name ‘sleep...
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[0]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[4]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[0]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[4]
[31m=================== [31m[1m5 failed[0m, [32m15 passed[0m, [31m[1m10 errors[0m[31m in 15.96s[0m[31m ===================[0m
"""指定需要多少个CPU来跑用例"""
!pytest -s -n 2 plug/pytest_xdist/
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: xdist-1.31.0, rerunfailures-9.0, assume-2.2.1, forked-1.1.3, repeat-0.8.0
gw0 [30] / gw1 [30][0m1m[1m[1m[1m
[31mF[0m[31mF[0m[31mF[0m[31mF[0m[31mF[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[31mE[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m[32m.[0m
==================================== ERRORS ====================================
[31m[1m______________________ ERROR at setup of test_case2_01[0] ______________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[1] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_01[2] ______________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_02[1] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_01[3] ______________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_02[2] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_01[4] ______________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 6
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_01(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:6
[31m[1m______________________ ERROR at setup of test_case2_02[3] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[4] ______________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
[31m[1m______________________ ERROR at setup of test_case2_02[0] ______________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
file /home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py, line 12
@pytest.mark.parametrize("n", list(range(5)))
def test_case2_02(open_51, n):
E fixture ‘open_51‘ not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, doctest_namespace, login, monkeypatch, pytestconfig, record_property, record_testsuite_property, record_xml_attribute, recwarn, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use ‘pytest --fixtures [testpath]‘ for help on them.
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_job/test_case1.py:12
=================================== FAILURES ===================================
[31m[1m_______________________________ test_get_info[0] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 0
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[1] _______________________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 1
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[2] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 2
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[3] _______________________________[0m
[gw1] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 3
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
[31m[1m_______________________________ test_get_info[4] _______________________________[0m
[gw0] linux -- Python 3.6.9 /usr/bin/python3
login = (‘testyy‘, ‘npoi213bn4‘), n = 4
[37m@pytest[39;49;00m.mark.parametrize([33m"[39;49;00m[33mn[39;49;00m[33m"[39;49;00m, [96mlist[39;49;00m([96mrange[39;49;00m([94m5[39;49;00m)))
[94mdef[39;49;00m [92mtest_get_info[39;49;00m(login, n):
> sleep([94m1[39;49;00m)
[1m[31mE NameError: name ‘sleep‘ is not defined[0m
[1m[31mplug/pytest_xdist/test_1.py[0m:6: NameError
=========================== short test summary info ============================
FAILED plug/pytest_xdist/test_1.py::test_get_info[0] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[1] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[2] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[3] - NameError: name ‘sleep...
FAILED plug/pytest_xdist/test_1.py::test_get_info[4] - NameError: name ‘sleep...
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[0]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[1]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[2]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_01[4]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[3]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[4]
ERROR plug/pytest_xdist/test_job/test_case1.py::test_case2_02[0]
[31m=================== [31m[1m5 failed[0m, [32m15 passed[0m, [31m[1m10 errors[0m[31m in 9.64s[0m[31m ====================[0m
"""pytest-xdist和pytest-html很好的相结合"""
!pytest -s -n auto plug/pytest_xdist/ --html=plug/pytest_xdist/report.html --self-contained-html
[31mERROR: usage: pytest [options] [file_or_dir] [file_or_dir] [...]
pytest: error: unrecognized arguments: --html=plug/pytest_xdist/report.html --self-contained-html
inifile: None
rootdir: /home/ubuntu/MySpace/Python/pytest
[0m
"""安装插件"""
# !pip3 install pytest-html -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com
Collecting pytest-html
Downloading http://pypi.doubanio.com/packages/00/a7/34f195c514d39b4453619b3eb284989e5adb09a2a68ac09ce3779f9b9478/pytest_html-2.1.1-py2.py3-none-any.whl
Collecting pytest>=5.0 (from pytest-html)
Downloading http://pypi.doubanio.com/packages/c7/e2/c19c667f42f72716a7d03e8dd4d6f63f47d39feadd44cc1ee7ca3089862c/pytest-5.4.1-py3-none-any.whl (246kB)
[K 100% |████████████████████████████████| 256kB 49.7MB/s ta 0:00:01
[?25hCollecting pytest-metadata (from pytest-html)
Downloading http://pypi.doubanio.com/packages/ce/8f/d0542e1aa0e23d902ce6acce2790736473da94453a36bdc7829f25734199/pytest_metadata-1.8.0-py2.py3-none-any.whl
Collecting py>=1.5.0 (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/99/8d/21e1767c009211a62a8e3067280bfce76e89c9f876180308515942304d2d/py-1.8.1-py2.py3-none-any.whl (83kB)
[K 100% |████████████████████████████████| 92kB 51.3MB/s ta 0:00:01
[?25hCollecting attrs>=17.4.0 (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/a2/db/4313ab3be961f7a763066401fb77f7748373b6094076ae2bda2806988af6/attrs-19.3.0-py2.py3-none-any.whl
Collecting importlib-metadata>=0.12; python_version < "3.8" (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/ad/e4/891bfcaf868ccabc619942f27940c77a8a4b45fd8367098955bb7e152fb1/importlib_metadata-1.6.0-py2.py3-none-any.whl
Collecting wcwidth (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/f6/d5/1ecdac957e3ea12c1b319fcdee8b6917ffaff8b4644d673c4d72d2f20b49/wcwidth-0.1.9-py2.py3-none-any.whl
Collecting pluggy<1.0,>=0.12 (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/a0/28/85c7aa31b80d150b772fbe4a229487bc6644da9ccb7e427dd8cc60cb8a62/pluggy-0.13.1-py2.py3-none-any.whl
Collecting more-itertools>=4.0.0 (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/72/96/4297306cc270eef1e3461da034a3bebe7c84eff052326b130824e98fc3fb/more_itertools-8.2.0-py3-none-any.whl (43kB)
[K 100% |████████████████████████████████| 51kB 40.3MB/s ta 0:00:01
[?25hCollecting packaging (from pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/62/0a/34641d2bf5c917c96db0ded85ae4da25b6cd922d6b794648d4e7e07c88e5/packaging-20.3-py2.py3-none-any.whl
Collecting zipp>=0.5 (from importlib-metadata>=0.12; python_version < "3.8"->pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/b2/34/bfcb43cc0ba81f527bc4f40ef41ba2ff4080e047acb0586b56b3d017ace4/zipp-3.1.0-py3-none-any.whl
Collecting six (from packaging->pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting pyparsing>=2.0.2 (from packaging->pytest>=5.0->pytest-html)
Downloading http://pypi.doubanio.com/packages/8a/bb/488841f56197b13700afd5658fc279a2025a39e22449b7cf29864669b15d/pyparsing-2.4.7-py2.py3-none-any.whl (67kB)
[K 100% |████████████████████████████████| 71kB 39.9MB/s ta 0:00:01
[?25hInstalling collected packages: py, attrs, zipp, importlib-metadata, wcwidth, pluggy, more-itertools, six, pyparsing, packaging, pytest, pytest-metadata, pytest-html
Successfully installed attrs-19.3.0 importlib-metadata-1.6.0 more-itertools-8.2.0 packaging-20.3 pluggy-0.13.1 py-1.8.1 pyparsing-2.4.7 pytest-5.4.1 pytest-html-2.1.1 pytest-metadata-1.8.0 six-1.14.0 wcwidth-0.1.9 zipp-3.1.0
注意事项:
"""在当前目录下创建一个report.html的测试报告"""
!pytest --html=report.html
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: xdist-1.31.0, rerunfailures-9.0, html-2.1.1, assume-2.2.1, forked-1.1.3, metadata-1.8.0, repeat-0.8.0
collected 39 items / 1 error / 38 selected [0m
==================================== ERRORS ====================================
[31m[1m_________________ ERROR collecting plug/pytest_xdist/test_1.py _________________[0m
[31mimport file mismatch:
imported module ‘test_1‘ has this __file__ attribute:
/home/ubuntu/MySpace/Python/pytest/conftest/test_1.py
which is not the same as the test file we want to collect:
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_1.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules[0m
-- generated html file: file:///home/ubuntu/MySpace/Python/pytest/report.html --
=========================== short test summary info ============================
ERROR plug/pytest_xdist/test_1.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
[31m=============================== [31m[1m1 error[0m[31m in 0.23s[0m[31m ===============================[0m
"""css是独立的,分享报告的时候样式会丢失,为了更好的分享发邮件展示报告,把css样式合并到html里"""
!pytest --html=report.html --self-contained-html
[1m============================= test session starts ==============================[0m
platform linux -- Python 3.6.9, pytest-5.4.1, py-1.8.1, pluggy-0.13.1
rootdir: /home/ubuntu/MySpace/Python/pytest
plugins: xdist-1.31.0, rerunfailures-9.0, html-2.1.1, assume-2.2.1, forked-1.1.3, metadata-1.8.0, repeat-0.8.0
collected 39 items / 1 error / 38 selected [0m
==================================== ERRORS ====================================
[31m[1m_________________ ERROR collecting plug/pytest_xdist/test_1.py _________________[0m
[31mimport file mismatch:
imported module ‘test_1‘ has this __file__ attribute:
/home/ubuntu/MySpace/Python/pytest/conftest/test_1.py
which is not the same as the test file we want to collect:
/home/ubuntu/MySpace/Python/pytest/plug/pytest_xdist/test_1.py
HINT: remove __pycache__ / .pyc files and/or use a unique basename for your test file modules[0m
-- generated html file: file:///home/ubuntu/MySpace/Python/pytest/report.html --
=========================== short test summary info ============================
ERROR plug/pytest_xdist/test_1.py
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
[31m=============================== [31m[1m1 error[0m[31m in 0.17s[0m[31m ===============================[0m
原文:https://www.cnblogs.com/crisimple/p/12906743.html