1、安装 命令行pip install pytest pycharm安装 下载pytest包,python setup.py install
2、start 先创建一个简单的用例: def func(x): return x + 1 def test_answer(): assert func(3) == 5 注意:用例的名字必须是test开头,如果写在类里面则需要类以Test开头命名: 查看下述代码运行结果说明上面的解释: 代码:
?
def func(x):
return x + 1
def testanswer():
assert func(3) == 4
def add_test():
assert 3-1==2
class A:
def test_div( self ):
assert 9/3==3
class TestA:
def test_x( self ):
assert 3*6==18
def ddf( self ):
assert 1==1
结果
C:\Users\18566\Desktop\APPAutoTest\pytest_leran>pytest -v
Test session starts (platform: win32, Python 3.8.1, pytest 5.4.3, pytest-sugar 0.9.4)
cachedir: .pytest_cache
metadata: {'Python': '3.8.1', 'Platform': 'Windows-10-10.0.18362-SP0', 'Packages': {'pytest': '5.4.3', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.8.16', 'assume': '2.2.1', 'cov':
'2.10.0', 'emoji': '0.2.0', 'forked': '1.2.0', 'html': '2.1.1', 'metadata': '1.10.0', 'ordering': '0.6', 'repeat': '0.8.0', 'rerunfailures': '9.0', 'sugar': '0.9.4', 'timeout': '1.4.1', 'xdist': '1.33.0
'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_202'}
rootdir: C:\Users\18566\Desktop\APPAutoTest\pytest_leran
plugins: allure-pytest-2.8.16, assume-2.2.1, cov-2.10.0, emoji-0.2.0, forked-1.2.0, html-2.1.1, metadata-1.10.0, ordering-0.6, repeat-0.8.0, rerunfailures-9.0, sugar-0.9.4, timeout-1.4.1, xdist-1.33.0
collecting ...
test_sample.py::testanswer ? 50% █████
test_sample.py::TestA.test_x ? 100% █████
█████
Results (0.18s):
2 passed
查看用例只收集了test开头的用例和Test开头的类(类里面也是查找test开头的方法)的用例。 100%显示已经执行完成所有的用例。 运行方式可以直接在pycharm里面或者IDE等工具进入terminal执行pytest可以直接找到符合命名规则的用例并执行。 指定测试用例文件则pytest 文件名 每个收集的测试都分配有一个唯一的nodeid名称,该名称由模块文件名后跟说明符(例如类名,函数名和参数化参数)组成,并用::字符分隔 指定测试文件具体的测试函数则 pytest 文件名::测试函数名 指定测试文件具体的测试类 pytest 文件名::类名 指定测试文件具体的测试方法 pytest 文件名::类名::方法名 如果不指定则默认在当前目录查看所有符合的用例。 没有特殊指定,以test_.py或者_test.py的文件都会被作为测试用例文件。
2.1 pytest遇到失败直接停止 pytest -x 遇到失败直接停止
2.2 pytest遇到失败停止设置失败次数 pytest --maxfail==2 遇到2次失败则停止
2.3 pytest通过关键字表达式运行测试 pytest -k “Myclass and not method” 运行myClass的类且不运行method名字的方法的 这个myclass和method的名字不区分大小写 上面的示例将运行,TestMyClass.test_something 但不会运行TestMyClass.test_method_simple
2.4pytest通过标记表达式运行测试 pytest -m slow 将运行用@pytest.mark.slow装饰器装饰的所有测试
2.5 pytest带参数运行输出 详细的结果 pytest -r 在测试会话结束时显示“简短的测试摘要信息”,从而使得在大型测试套件中轻松获得所有失败,跳过,xfails等的清晰画面 -r选项后面接受多个字符 适配的字符有: 这是可以使用的可用字符的完整列表:
f -失败
E -错误
s -跳过
x -xfailed
X -xpass
p -通过
P -通过输出
a -除 pP
A -全部
N-无,可用于不显示任何内容(fE默认设置)
比如: 仅查看失败和跳过的测试:pytest -rfs 仅查看所有通过的测试:pytest -rp
2.6 分析测试执行持续时间 获取最慢的10个测试持续时间的列表: pytest --durations=10 默认情况下,除非-vv(打印详细信息)在命令行传递,否则pytest不会显示太短执行的执行时间,比如<0.01s.
2.7 从Python代码中调用pytest 上述介绍了一部分命令参数,但是都是直接在命令行执行的。在python中执行则需要导入pytest,然后用pytest.main()函数执行。 传递参数则是向main传入一个列表,如下格式: pytest.main(["-v","-s",“class::fucntion”])
3 pytest fixtures不加参数调用 pytest fixture是对setup和teardown的提升。 之前unittest setup和teardown是针对测试用例前准备环境和测试用例执行后销毁环境,或者是setup_class和teardown_class。 fixtures可以声明是在test的函数、模块、类或者整个session生效。 fixtures也可以进行参数化,测试用例通过配置和选项运行fixtures,fixtures可以在不同用例多次调用。 fixtures定义是用装饰器@pytest.fixture 简单例子示例: test_smtpsimple.py ?
```css
import pytest
@pytest.fixture
def smtp_connection():
import smtplib
return smtplib.SMTP("smtp.qiye.163.com", 25, timeout=15)
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
print(response,msg)
assert response == 250
assert 0 # for demo purposes
上述是一种使用fixture的方式,smtp_connection用装饰器@pytest.fixture 在测试用例test_ehlo中调用smtp_connection,这种方式可以在test_ehlo调用smtp_connection的方法或者参数等. 当运行pytest时会自动去找@pytest.fixture装饰器装饰的函数 运行结果如下: ?
C:\Users\18566\Desktop\APPAutoTest\pytest_leran>pytest -vv
Test session starts (platform: win32, Python 3.8.1, pytest 5.4.3, pytest-sugar 0.9.4)
cachedir: .pytest_cache
metadata: {'Python': '3.8.1', 'Platform': 'Windows-10-10.0.18362-SP0', 'Packages': {'pytest': '5.4.3', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.8.16', 'assume': '2.2.1', 'cov':
'2.10.0', 'emoji': '0.2.0', 'forked': '1.2.0', 'html': '2.1.1', 'metadata': '1.10.0', 'ordering': '0.6', 'repeat': '0.8.0', 'rerunfailures': '9.0', 'sugar': '0.9.4', 'timeout': '1.4.1', 'xdist': '1.33.0
'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_202'}
rootdir: C:\Users\18566\Desktop\APPAutoTest\pytest_leran
plugins: allure-pytest-2.8.16, assume-2.2.1, cov-2.10.0, emoji-0.2.0, forked-1.2.0, html-2.1.1, metadata-1.10.0, ordering-0.6, repeat-0.8.0, rerunfailures-9.0, sugar-0.9.4, timeout-1.4.1, xdist-1.33.0
collecting ...
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― test_ehlo ―
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
smtp_connection = <smtplib.SMTP object at 0x000001AEA239A580>
def test_ehlo(smtp_connection):
response, msg = smtp_connection.ehlo()
print(response,msg)
assert response == 250
> assert 0 # for demo purposes
E assert 0
test_sample.py:36: AssertionError
------------------------------------------------------------------------------------------ Captured stdout call ------------------------------------------------------------------------------------------
250 b'proxy-sm-thq-2.hmbj.internal\nPIPELINING\n8BITMIME\nAUTH=LOGIN PLAIN\nAUTH PLAIN LOGIN\nSTARTTLS'
test_sample.py::test_ehlo ? 100% █████
█████
======================================================================================== short test summary info =========================================================================================
FAILED test_sample.py::test_ehlo - assert 0
Results (0.97s):
1 failed
- test_sample.py:32 test_ehlo
上述使用assert进行了断言,从运行结果可知可以进行多个断言,如果某一个断言出错,则判断这个用例结果是fail. 解读整个过程: 1、pytest运行先去运行符合规则的用例,test***,这个例子是test_ehlo 2、test用例函数形参是smtp_connection,在查找fixture标记的函数时找到定义的fixture函数 3、smtp_connection被调用 4、运行test_ehlo里面的命令,assert 0导致断言失败
这里需要注意的是:如果没有在test形参里面写入fixture的函数名或者是写的是一个不存在的fixture函数名,将会引发错误,并打印一个可用的fixture列表。将上述引用的smtp_connection修改为smtp_connection1运行结果如下: ?
C:\Users\18566\Desktop\APPAutoTest\pytest_leran>pytest -vv
Test session starts (platform: win32, Python 3.8.1, pytest 5.4.3, pytest-sugar 0.9.4)
cachedir: .pytest_cache
metadata: {'Python': '3.8.1', 'Platform': 'Windows-10-10.0.18362-SP0', 'Packages': {'pytest': '5.4.3', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.8.16', 'assume': '2.2.1', 'cov':
'2.10.0', 'emoji': '0.2.0', 'forked': '1.2.0', 'html': '2.1.1', 'metadata': '1.10.0', 'ordering': '0.6', 'repeat': '0.8.0', 'rerunfailures': '9.0', 'sugar': '0.9.4', 'timeout': '1.4.1', 'xdist': '1.33.0
'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_202'}
rootdir: C:\Users\18566\Desktop\APPAutoTest\pytest_leran
plugins: allure-pytest-2.8.16, assume-2.2.1, cov-2.10.0, emoji-0.2.0, forked-1.2.0, html-2.1.1, metadata-1.10.0, ordering-0.6, repeat-0.8.0, rerunfailures-9.0, sugar-0.9.4, timeout-1.4.1, xdist-1.33.0
collecting ...
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― ERROR at setup of test_ehlo ―
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
file C:\Users\18566\Desktop\APPAutoTest\pytest_leran\test_sample.py, line 32
def test_ehlo(smtp_connection1):
E fixture 'smtp_connection1' not found
> available fixtures: __pytest_repeat_step_number, cache, capfd, capfdbinary, caplog, capsys, capsysbinary, cov, doctest_namespace, extra, metadata, monkeypatch, no_cover, pytestconfig, record_prop
erty, record_testsuite_property, record_xml_attribute, recwarn, smtp_connection, testrun_uid, tmp_path, tmp_path_factory, tmpdir, tmpdir_factory, worker_id
> use 'pytest --fixtures [testpath]' for help on them.
C:\Users\18566\Desktop\APPAutoTest\pytest_leran\test_sample.py:32
100% █████
█████
======================================================================================== short test summary info =========================================================================================
FAILED test_sample.py::test_ehlo
Results (0.24s):
1 error
运行结果显示没有找到fixture ‘smtp_connection1’ not found,然后显示了可用的fixture列表 available fixtures。 用pytest --fixtures [testpath]可以显示存在的fixture,并显示每一个fixture的描述,不加testpath则显示当前的目录支持的fixtures,运行结果如下: ?
C:\Users\18566\Desktop\APPAutoTest\pytest_leran>pytest --fixtures
Test session starts (platform: win32, Python 3.8.1, pytest 5.4.3, pytest-sugar 0.9.4)
rootdir: C:\Users\18566\Desktop\APPAutoTest\pytest_leran
plugins: allure-pytest-2.8.16, assume-2.2.1, cov-2.10.0, emoji-0.2.0, forked-1.2.0, html-2.1.1, metadata-1.10.0, ordering-0.6, repeat-0.8.0, rerunfailures-9.0, sugar-0.9.4, timeout-1.4.1, xdist-1.33.0
cache
Return a cache object that can persist state between testing sessions.
cache.get(key, default)
cache.set(key, value)
Keys must be a ``/`` separated value, where the first part is usually the
name of your plugin or application to avoid clashes with other cache users.
Values can be any object handled by the json stdlib module.
capsys
Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``.
The captured output is made available via ``capsys.readouterr()`` method
calls, which return a ``(out, err)`` namedtuple.
``out`` and ``err`` will be ``text`` objects.
capsysbinary
Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``.
The captured output is made available via ``capsysbinary.readouterr()``
method calls, which return a ``(out, err)`` namedtuple.
``out`` and ``err`` will be ``bytes`` objects.
capfd
Enable text capturing of writes to file descriptors ``1`` and ``2``.
The captured output is made available via ``capfd.readouterr()`` method
calls, which return a ``(out, err)`` namedtuple.
``out`` and ``err`` will be ``text`` objects.
capfdbinary
Enable bytes capturing of writes to file descriptors ``1`` and ``2``.
The captured output is made available via ``capfd.readouterr()`` method
calls, which return a ``(out, err)`` namedtuple.
``out`` and ``err`` will be ``byte`` objects.
doctest_namespace [session scope]
Fixture that returns a :py:class:`dict` that will be injected into the namespace of doctests.
pytestconfig [session scope]
Session-scoped fixture that returns the :class:`_pytest.config.Config` object.
Example::
def test_foo(pytestconfig):
if pytestconfig.getoption("verbose") > 0:
...
record_property
Add an extra properties the calling test.
User properties become part of the test report and are available to the
configured reporters, like JUnit XML.
The fixture is callable with ``(name, value)``, with value being automatically
xml-encoded.
Example::
def test_function(record_property):
record_property("example_key", 1)
record_xml_attribute
Add extra xml attributes to the tag for the calling test.
The fixture is callable with ``(name, value)``, with value being
automatically xml-encoded
record_testsuite_property [session scope]
Records a new ``<property>`` tag as child of the root ``<testsuite>``. This is suitable to
writing global information regarding the entire test suite, and is compatible with ``xunit2`` JUnit family.
This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:
.. code-block:: python
def test_foo(record_testsuite_property):
record_testsuite_property("ARCH", "PPC")
record_testsuite_property("STORAGE_TYPE", "CEPH")
``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped.
caplog
Access and control log capturing.
Captured logs are available through the following properties/methods::
* caplog.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
monkeypatch
The returned ``monkeypatch`` fixture provides these
helper methods to modify objects, dictionaries or os.environ::
monkeypatch.setattr(obj, name, value, raising=True)
monkeypatch.delattr(obj, name, raising=True)
monkeypatch.setitem(mapping, name, value)
monkeypatch.delitem(obj, name, raising=True)
monkeypatch.setenv(name, value, prepend=False)
monkeypatch.delenv(name, raising=True)
monkeypatch.syspath_prepend(path)
monkeypatch.chdir(path)
All modifications will be undone after the requesting
test function or fixture has finished. The ``raising``
parameter determines if a KeyError or AttributeError
will be raised if the set/deletion operation has no target.
recwarn
Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions.
See http://docs.python.org/library/warnings.html for information
on warning categories.
tmpdir_factory [session scope]
Return a :class:`_pytest.tmpdir.TempdirFactory` instance for the test session.
tmp_path_factory [session scope]
Return a :class:`_pytest.tmpdir.TempPathFactory` instance for the test session.
tmpdir
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a `py.path.local`_
path object.
.. _`py.path.local`: https://py.readthedocs.io/en/latest/path.html
tmp_path
Return a temporary directory path object
which is unique to each test function invocation,
created as a sub directory of the base temporary
directory. The returned object is a :class:`pathlib.Path`
object.
.. note::
in python < 3.6 this is a pathlib2.Path
-------------------------------------------------------------------------------- fixtures defined from pytest_cov.plugin ---------------------------------------------------------------------------------
no_cover
A pytest fixture to disable coverage.
cov
A pytest fixture to provide access to the underlying coverage object.
-------------------------------------------------------------------------------- fixtures defined from pytest_html.plugin --------------------------------------------------------------------------------
extra
Add details to the HTML reports.
.. code-block:: python
import pytest_html
def test_foo(extra):
extra.append(pytest_html.extras.url('http://www.example.com/'))
------------------------------------------------------------------------------ fixtures defined from pytest_metadata.plugin ------------------------------------------------------------------------------
metadata [session scope]
Provide test session metadata
---------------------------------------------------------------------------------- fixtures defined from pytest_repeat -----------------------------------------------------------------------------------
----------------------------------------------------------------------------------- fixtures defined from xdist.plugin -----------------------------------------------------------------------------------
worker_id [session scope]
Return the id of the current worker ('gw0', 'gw1', etc) or 'master'
if running on the master node.
testrun_uid [session scope]
Return the unique id of the current test.
----------------------------------------------------------------------------- fixtures defined from pytest_leran.test_sample -----------------------------------------------------------------------------
smtp_connection
test_sample.py:27: no docstring available
Results (0.34s):
4 conftest.py+fixture 如果在测试过程中,fixture 函数需要在多个测试文件使用,此时应该把fixture函数写在conftest.py中。这种情况下不需要导入这个fixture到testcase,pytest会自动去发现。 查找fixture顺序是test classes–>test module–>conftest.py–>第三方插件 如何在用例之间共享测试数据: 1、把数据写在fixture里面 2、把数据添加到tests的文件夹,使用插件来帮助实现,插件分别是pytest-datadir或者pytest-datatfiles(后续补充用法)
4.1带参数的fixture 上述的fixture是所有的用例前都会执行,可以通过参数来限制fixture的作用域。 参数scope指定范围 @pytest(scope=“module”) module—fixture在每个测试文件执行前执行一次 class—fixture在每一个测试类执行前执行都执行一次 function–fixture在每个函数或者每个类方法执行前都会执行一次 session–fixture在整个session执行最开始先执行一次 package–理论上是在一个包执行前执行一次,这个没用过,暂时先写这里 举例说明: 三个文件conftest.py test_1.py test_2.py sample.py 内容分别如下: conftest.py ?
import pytest
@pytest.fixture
def fixture1():
pass
print("这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次")
@pytest.fixture(scope="session")
def fixture2():
pass
# print("这个限制范围session")
@pytest.fixture(scope='module')
def fixture3():
pass
# print("这个限制范围是module")
@pytest.fixture(scope="class")
def fixture4():
pass
# print("这个限制范围是class")
@pytest.fixture(scope="function")
def fixture5():
pass
# print("这个限制范围是function")
test_1.py内容如下:
def test1_test1(fixture1,fixture2,fixture3,fixture4,fixture5):
print("test1_test1")
def test2(fixture1,fixture2,fixture3,fixture4,fixture5):
print("test1_test2")
class Test1:
def test1_Test1( self,fixture1,fixture2,fixture3,fixture4,fixture5 ):
print("test1_test1_Test1")
def test2_Test1( self,fixture1,fixture2,fixture3,fixture4,fixture5 ):
print("test1_test1_Test1")
test_2.py内容如下:
def test1(fixture1,fixture2,fixture3,fixture4,fixture5):
print("test1")
def test2(fixture1,fixture2,fixture3,fixture4,fixture5):
print("test2")
class Test1:
def test1_Test1( self,fixture1,fixture2,fixture3,fixture4,fixture5 ):
print("test1_Test1")
def test2_Test1( self,fixture1,fixture2,fixture3,fixture4,fixture5 ):
print("test1_Test1")
sample.py随便写内容即可,按照pytest的执行过滤是不会识别为测试用例。
4.2 不带scope限定范围的fixture示例
首先先验证不带scope,则应该所有识别的用例都会执行一次,修改conftest把该项的print去掉注释:
@pytest.fixture
def fixture1():
print("这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次")
执行pytest结果如下,结果可看到:
C:\Users\18566\Desktop\APPAutoTest\pytest_leran>pytest -vv -s
Test session starts (platform: win32, Python 3.8.1, pytest 5.4.3, pytest-sugar 0.9.4)
cachedir: .pytest_cache
metadata: {'Python': '3.8.1', 'Platform': 'Windows-10-10.0.18362-SP0', 'Packages': {'pytest': '5.4.3', 'py': '1.9.0', 'pluggy': '0.13.1'}, 'Plugins': {'allure-pytest': '2.8.16', 'assume': '2.2.1', 'cov':
'2.10.0', 'emoji': '0.2.0', 'forked': '1.2.0', 'html': '2.1.1', 'metadata': '1.10.0', 'ordering': '0.6', 'repeat': '0.8.0', 'rerunfailures': '9.0', 'sugar': '0.9.4', 'timeout': '1.4.1', 'xdist': '1.33.0
'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_202'}
rootdir: C:\Users\18566\Desktop\APPAutoTest\pytest_leran
plugins: allure-pytest-2.8.16, assume-2.2.1, cov-2.10.0, emoji-0.2.0, forked-1.2.0, html-2.1.1, metadata-1.10.0, ordering-0.6, repeat-0.8.0, rerunfailures-9.0, sugar-0.9.4, timeout-1.4.1, xdist-1.33.0
collecting ... 这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_test1
test_1.py::test1_test1 ? 12% █▍
这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_test2
test_1.py::test2 ? 25% ██▌
这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_test1_Test1
test_1.py::Test1.test1_Test1 ? 38% ███▊
这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_test1_Test1
test_1.py::Test1.test2_Test1 ? 50% █████
这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1
test_2.py::test1 ? 62% █████
█▍ 这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test2
test_2.py::test2 ? 75% █████
██▌ 这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_Test1
test_2.py::Test1.test1_Test1 ? 88% █████
███▊ 这个是不加参数的fixture,没有设置范围,应该所有符合的test*用例都会执行一次
test1_Test1
test_2.py::Test1.test2_Test1 ? 100% █████
█████
Results (0.58s):
8 passed
|