python中chapter用法_Chapter 2 用法

Chapter 2 用法

2.1 通过python -m pytest调用pytest

这是在2.0版本中新引入的功能。

你可以通过python的解释器,利用命令行来调用测试:

python -m pytest [...]

这种调用方式几乎等同于直接调用pytest [...],但需要注意的是这种通过python来调用的方式同时会将当前目录添加到sys.path

2.2 退出码

pytest有以下6种退出码:

Exit code 0: 找到所有测试用例并测试通过

Exit code 1: 找到测试用例并运行但是部分测试用例运行失败

Exit code 2: 用户中断了测试

Exit code 3: 执行过程中发生了内部错误

Exit code 4: pytest命令行使用错误

Exit code 5: 没有找到任何测试用例

2.3 版本信息,参数名,环境变量的帮助

pytest --version #显示pytest的import的路径

pytest --fixtures #显示内置的函数参数

pytest -h | --help #帮助信息

2.4 第一(N)次测试失败后停止

使用下面的参数可以让测试在第1(N)次测试失败后停止:

pytest -x # 第一次测试失败后停止测试

pytest --maxfail=2 # 第2次测试失败后停止测试

2.5 指定/选择测试用例

Pytest在命令行中支持多种方式来运行和选择测试用例:

对模块中进行测试:

pytest test_mod.py

对文件夹中进行测试:

pytest testing/

通过关键字表达式来进行测试:

pytest -k "MyClass and not method"

这种方式会执行文件名,类名以及函数名与给定的字符串表达式相匹配的测试用例。

上面的用例会执行TestMyClass.test_something但是不会执行TestMyClass.test_method_simple

and not 在这里是表达式,未经过测试

通过节点id来进行测试

每个被选中的测试用例都会被分配一个唯一的nodeid,它由模块文件名和以下说明符组成:参数化的类名、函数名和参数,用::分隔。

可以通过下面的方式运行模块中的指定的测试用例:

pytest test_mod.py::test_func

也可以通过下面这种方式:

pytest test_mod.py::TestClass::test_method

通过标记符来进行测试

pytest -m slow

这种方式会运行所有通过装饰器 @pytest.mark.slow进行装饰的测试用例。

关于标记符请参考marks

通过包来运行

pytest --pyargs pkg.testing

这种方式会导入pkg.testing,并且基于该包所在为止来查找并运行测试用例。

2.6 修改python的traceback的打印

示例:

pytest --showlocals #在tracebacks中显示本地变量

pytest -l #同上

pytest --tb=auto #(默认显示方式)该方式会显示tracebacks的第一条和最后一条的详细信息

#其余的信息会简略显示

pytest --tb=long #详细显示所有的tracebacks

pytest --tb=short #简略显示tracebacks

pytest --tb=line #每个错误只显示一行

pytest --tb=native #以python标准库模式输出

pytest --tb=no #不输出tracebacks

另外还有比--tb=long输出更详细的参数--full-trace。在该参数下,KeyboardInterrupt(Ctrl+C)在中断traceback的输出的时候同时会打印栈信息。 这在测试耗时过长的时候非常有用,使用该组合可以帮助我们找到测试用例挂死在何处。

如果使用默认方式,测试被中断的时候不会有任何栈信息输出(因为KeyboardInterrupt被pytest捕获了),使用该参数可以保证traceback能够显示出来。(这段翻译怪怪的)

详尽的测试报告

这是2.9的新功能。

参数-r可以用来在测试结束后展示一份“测试概要信息”,这使得在大型测试套中获取一份清楚的测试结果(失败,跳过等测试信息)十分简单。

示例:

#test_example.py的内容

import pytest

@pytest.fixture

def error_fixture():

assert 0

def test_ok():

print("ok")

def test_fail():

assert 0

def test_error(error_fixture):

pass

def test_skip():

pytest.skip("skipping this test")

def test_xfail():

pytest.xfail("xfailing this test")

@pytest.mark.xfail(reason="always xfail")

def test_xpass():

pass

C:\>pytest -ra

========================== test session starts ==========================

platform win32 -- Python 3.7.2, pytest-4.2.0, py-1.7.0, pluggy-0.8.1

rootdir: TMPDIR, inifile:

collected 6 items

test_example.py .FEsxX [100%]

========================== ERRORS ==========================

__________________________ ERROR at setup of test_error __________________________

@pytest.fixture

def error_fixture():

> assert 0

E assert 0

test_example.py:5: AssertionError

========================== FAILURES ==========================

__________________________ test_fail __________________________

def test_fail():

> assert 0

E assert 0

test_example.py:11: AssertionError

========================== short test summary info ==========================

SKIPPED [1] C:\test_example.py:18: skipping this test

XFAIL test_example.py::test_xfail

reason: xfailing this test

XPASS test_example.py::test_xpass always xfail

ERROR test_example.py::test_error

FAILED test_example.py::test_fail

=========== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.09 seconds ===========

-r后可以追加一些参数,上面示例中的a表示"除了passes的所有信息"。

可以追加的参数列表如下:

f - failed

E - error

s - skipped

x - xfailed

X - xpassed

p - passed

P - passed with output

a - all except pP

可以同时追加多个参数,如果你想只看"failed"和"skipped"的测试结果,你可以执行:

C:\>pytest -rfs

========================== test session starts ==========================

platform win32 -- Python 3.7.2, pytest-4.2.0, py-1.7.0, pluggy-0.8.1

rootdir: TMPDIR, inifile:

collected 6 items

test_example.py .FEsxX [100%]

========================== ERRORS ==========================

__________________________ ERROR at setup of test_error __________________________

@pytest.fixture

def error_fixture():

> assert 0

E assert 0

test_example.py:5: AssertionError

========================== FAILURES ==========================

__________________________ test_fail __________________________

def test_fail():

> assert 0

E assert 0

test_example.py:11: AssertionError

========================== short test summary info ==========================

FAILED test_example.py::test_fail

SKIPPED [1] C:\test_example.py:18: skipping this test

========================== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.13 seconds ==========================

p可以用来显示pass的测试用例,P会在测试报告中增加一段"PASSES"的信息来显示通过的测试用例:

C:\>pytest -rpP

========================== test session starts ==========================

platform win32 -- Python 3.7.2, pytest-4.2.0, py-1.7.0, pluggy-0.8.1

rootdir: TMPDIR, inifile:

collected 6 items

test_example.py .FEsxX [100%]

========================== ERRORS ==========================

__________________________ ERROR at setup of test_error __________________________

@pytest.fixture

def error_fixture():

> assert 0

E assert 0

test_example.py:5: AssertionError

========================== FAILURES ==========================

__________________________ test_fail __________________________

def test_fail():

> assert 0

E assert 0

test_example.py:11: AssertionError

========================== short test summary info ==========================

PASSED test_example.py::test_ok

========================== PASSES ==========================

__________________________ test_ok __________________________

--------------------------- Captured stdout call ---------------------------

ok

========================== 1 failed, 1 passed, 1 skipped, 1 xfailed, 1 xpassed, 1 error in 0.08 seconds ==========================

2.8 测试失败时自动调用PDB

pytest允许通过命令行使能在测试失败时自动调用python的内置调试工具PDB:

pytest --pdb

这会在每次测试失败(或者发生KeyboardInterrupt)的时候都去调用PDB。通常我们可能只需要在第一次测试失败的时候来调用pdb:

pytest -x --pdb #首次失败的时候调用pdb,然后结束测试进程

pytest --pdb --maxfail=3 #前三次失败的时候调用pdb

注意所有的异常信息都会保存在sys.last_value, sys.last_type和sys.last_traceback中。

在交互使用中,这允许使用任何调试工具进入后期调试。我们也可以手动的访问这些异常信息,如下:

(Pdb) import sys

(Pdb) sys.last_traceback.tb_lineno

1448

(Pdb) sys.last_value

AssertionError('assert 0')

(Pdb) sys.last_type

2.9 测试启动时调用PDB

pytest允许在测试启动时立即调用pdb:

pytest --trace

这会在每个测试开始时立即调用python的pdb。

2.10 设置断点

在代码中使用python的原生接口python import pdb; pdb.set_trace()来设置断点,在pytest中会自动禁用该测试的输出捕获:

*其他测试的输出捕获不会受影响

*先前的测试中已经被捕获的输出会被正常处理

*同一测试中的后续输出不会被捕获,而被转发给sys.stdout。注意即使退出交互式pdb继续运行测试,这一设置依然生效

2.11 使用内置的断点函数

python3.7 引入了内置的断点函数 breakpoint(),pytest支持该函数:

当breakpoint()被调用,并且PYTHONBREAKPOINT是默认值时,pytest将会使用内部自定义的PDB UI, 而不是系统默认的PDB

测试完成后,返回系统默认的PDB UI

当使用--pdb*参数时,breakpoint()和测试异常时都会使用内部自定义的PDB UI

--pdbcls可以用于指定自定义的调试类(这是什么鬼)

2.12 分析测试时间

显示最慢的10个测试步骤:

pytest --durations=10

默认情况下,如果测试时间很短(<0.01s),这里不会显示执行时常,如果需要显示,在命令行中追加-vv参数

2.13 创建 JUnitXML 格式的文件

使用下面的方式可以创建Jekins或者其他的集成测试环境可读的结果文件:

pytest --junitxml=path

path是生成的XML文件

3.1引入的新特性:

可以在pytest的配置文件中设置junit_suite_name属性来配置测试结果XML中的root名称:

[pytest]

junit_suite_name = my_suite

4.0引入的新特性:

Junit XML规范中"time"属性应该是总的测试执行的时间,包含setup和teardown。这也是pytest的默认行为。如果想要只显示测试的时间(call duration),配置junit_duration_report:

[pytest]

junit_duration_report = call

2.13.1 record_property

2.8引入

3.5更新: 因为用户属性并不是对所有的报告都生效,将record_xml_property改名为record_property,不再推荐使用record_xml_property.

如果想要给某个测试添加额外信息,可以使用record_property固件:

def test_function(record_property):

record_property("example_key", 1)

assert True

这会在生成testcase的时候增加一个额外的属性example_key="1"

你也可以将该功能与自定义的标签一起使用:

# conftest.py的内容

def pytest_collection_modifyitems(session, config, items):

for item in items:

for marker in item.iter_markers(name="test_id"):

test_id = marker.args[0]

item.user_properties.append(("test_id", test_id))

在测试用例中:

# test_function.py的内容

import pytest

@pytest.mark.test_id(1501)

def test_function():

assert True

测试结果如下:

注意: record_property尚处于实验阶段,将来可能会有所变化。

同时请注意该特性会中断所有的schema(这是啥)验证,这在某些CI服务器上可能会导致一些问题。

2.13.2 record_xml_attribute

3.4引入

使用record_xml_attribute可以在测试用例中增加额外的xml属性。该固件也可以用来复写已经存在的属性值:

def test_function(record_xml_attribute):

record_xml_attribute("assertions", "REQ-1234")

record_xml_attribute("classname", "custom_classname")

print("hello world")

assert True

与record_property不同,该固件不会新增子节点,而是在testcase的tag里面增加或者覆盖已有的属性:

hello world

注意: record_xml_attribute尚处于实验阶段,将来可能会有所变化。(还有一大串注释,懒得翻译了)

2.13.3 LogXML:add_global_property

3.0引入

如果需要在测试套层面对所有相关的测试用例增加属性,需要使用LogXML.add_global_property

import pytest

@pytest.fixture(scope="session")

def log_global_env_facts(f):

if pytest.config.pluginmanager.hasplugin("junitxml")

my_junit = getattr(pytest.config, "_xml", None)

my_junit.add_global_property("ARCH", "PPC")

my_junit.add_global_property("STORAGE_TYPE", "CEPH")

@pytest.mark.usefixtures(log_global_env_facts.__name__)

def start_and_prepare_env():

pass

class TestMe(object):

def test_foo(self):

assert True

以上代码会在生成xml的时候,在测试套的节点下添加一个属性的节点:

注意: add_global_property尚处于实验阶段,将来可能会有所变化。

2.14 创建resultlog格式文件

很少用,很快就要被移除了。

2.15 将测试结果发送给在线的pastebin

Pastebin是一个用户存储纯文本的web应用。用户可以通过互联网分享文本片段,一般都是源代码。

(没用过这个,不翻了 >

2.16 禁用插件

如果想要在运行时禁用特定的插件,使用 -p以及no:前缀符。

如: 禁止加载doctest插件:

pytest -p no:doctest

2.17 在python代码中运行pytest

2.0引入

你可以在python代码中直接调用pytest:

pytest.main()

这和在命令行中使用pytest是一样的。 这种方式不会抛出SystemExit异常,而会返回exitcode。 通过如下方式可以传入调用参数:

pytest.main(['-x', 'mytestdir'])

你可以在pytest.main中指定额外的插件:

# myinvoke.py的内容

import pytest

class MyPlugin(object):

def pytest_sessionfinish(self):

print("*** test run reporting finishing")

pytest.main(["-qq"], plugins=[MyPlugin()])

运行代码就可以发现MyPlugin被添加到hook里并被调用:

C:\>python myinvoke.py

.FEsxX [100%]*** test run reporting finishing

========================= ERRORS =========================

_____________________ ERROR at setup of test_error _____________________

@pytest.fixture

def error_fixture():

> assert 0

E assert 0

test_example.py:5: AssertionError

========================= FAILURES =========================

_____________________ test_fail _____________________

def test_fail():

> assert 0

E assert 0

test_example.py:11: AssertionError

注意:调用pytest.main()会导入你的测试用例及其所引用的所有的模块。因为python存在模块导入的缓存机制,如果多次调用pytest.main(),后续的调用也不会再刷新这些导入的资源。因此,不建议再同一进程中多次调用pytest.main() (比如重新运行测试).

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值