目录
在测试收集期间忽略路径
你可以通过在命令行上传递--ignore=path
选项来轻松地在收集期间忽略某些测试目录和模块。pytest 允许使用多个 --ignore
选项。以下是一个示例:
tests/
|-- example
| |-- test_example_01.py
| |-- test_example_02.py
| '-- test_example_03.py
|-- foobar
| |-- test_foobar_01.py
| |-- test_foobar_02.py
| '-- test_foobar_03.py
'-- hello
'-- world
|-- test_world_01.py
|-- test_world_02.py
'-- test_world_03.py
现在,如果你使用 --ignore=tests/foobar/test_foobar_03.py --ignore=tests/hello/
调用 pytest,你会看到 pytest 只收集那些不匹配指定模式的测试模块:
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-5.x.y, py-1.x.y, pluggy-0.x.y
rootdir: $REGENDOC_TMPDIR, inifile:
collected 5 items
tests/example/test_example_01.py . [ 20%]
tests/example/test_example_02.py . [ 40%]
tests/example/test_example_03.py . [ 60%]
tests/foobar/test_foobar_01.py . [ 80%]
tests/foobar/test_foobar_02.py . [100%]
========================= 5 passed in 0.02 seconds =========================
在测试收集期间取消选择测试
通过传递 --deselect=item
选项,可以在收集过程中单独取消选择测试。例如,假设 tests/foobar/test_foobar_01.py
包含 test_a
和 test_b
。你可以通过调用 pytest 并使用 --deselect tests/foobar/test_foobar_01.py::test_a
来运行 tests/
目录下的所有测试,但除了 tests/foobar/test_foobar_01.py
中的 test_a
。pytest 允许使用多个 --deselect
选项。
命令行中指定重复路径的处理
pytest 的默认行为是忽略从命令行中指定的重复路径。例如:
pytest path_a path_a
...
collected 1 item
...
在上述命令中,尽管 path_a
被指定了两次,但 pytest 只会收集并运行该路径下的测试一次。
要收集重复的测试,你可以在命令行界面(CLI)上使用--keep-duplicates
选项。以下是一个例子:
pytest --keep-duplicates path_a path_a
...
collected 2 items
...
由于测试收集器主要工作于目录上,但如果你两次指定了同一个测试文件,那么无论是否指定了--keep-duplicates
选项,pytest 都会将其收集两次。这是因为当你直接指定测试文件时,pytest 会将它们视为独立的输入项。以下是一个例子:
pytest test_a.py test_a.py
...
collected 2 items
...
修改目录递归
你可以在项目的根目录下的配置文件(如pytest.ini
)中设置norecursedirs
选项,以指示pytest在递归查找测试时不进入某些特定的目录。例如:
# pytest.ini 文件的内容
[pytest]
norecursedirs = .svn _build tmp*
这将会告诉pytest不要递归进入如.svn
(Subversion版本控制系统目录)、_build
(Sphinx构建目录的常用名称)或任何以tmp
为前缀的目录。
更改命名约定
在pytest中,你可以通过配置文件(如pytest.ini
)来设置不同的命名约定,以自定义pytest如何查找和识别测试文件、测试类和测试函数。以下是如何通过配置python_files
、python_classes
和python_functions
来改变命名约定的一个例子:
# pytest.ini 文件的内容
# 示例 1: 让pytest查找以"check"开头的文件,而不是默认的"test"
[pytest]
python_files = check_*.py
python_classes = Check
python_functions = *_check
这个配置会使得pytest在匹配check_*.py
这个glob模式(通配符模式)的文件中查找测试,在类名以Check
为前缀的类中查找测试,以及在函数名或方法名匹配*_check
模式的函数和方法中查找测试。以下是一个具体的例子来说明这一点:
# check_myapp.py 文件的内容
class CheckMyApp:
def simple_check(self):
pass
def complex_check(self):
pass
测试收集(Test Collection)的结果看起来会像这样:
$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 2 items
<Dir pythoncollection.rst-201>
<Module check_myapp.py>
<Class CheckMyApp>
<Function simple_check>
<Function complex_check>
======================== 2 tests collected in 0.12s ========================
你可以通过在模式之间添加一个空格来检查多个glob模式:
# Example 2: have pytest look for files with "test" and "example"
# content of pytest.ini
[pytest]
python_files = test_*.py example_*.py
注意
python_functions
和 python_classes
选项对于 unittest.TestCase
的测试发现没有影响,因为pytest将测试用例方法的发现委托给了unittest代码。
将命令行参数解释为Python包
你可以使用--pyargs
选项来让pytest尝试将参数解释为Python包名,从而推导出它们的文件系统路径,并运行测试。例如,如果你已经安装了unittest2
,你可以输入:
pytest --pyargs unittest2.test.test_skipping -q
pytest尝试将unittest2.test.test_skipping
解释为Python中的一个包(或模块)路径,并自动找到该包在文件系统上的位置,然后运行该包中的测试。
和其他选项一样,你可以通过在ini
文件中使用addopts选项来使这个更改更加持久化:
# pytest.ini 文件的内容
[pytest]
addopts = --pyargs
现在,简单地调用 pytest NAME
将检查 NAME
是否作为一个可导入的包/模块存在,如果不存在,则将其视为文件系统路径。
找出收集的内容
你可以在不运行测试的情况下,通过以下方式窥探收集到的测试树:
. $ pytest --collect-only pythoncollection.py
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 3 items
<Dir pythoncollection.rst-201>
<Dir CWD>
<Module pythoncollection.py>
<Function test_function>
<Class TestClass>
<Function test_method>
<Function test_anothermethod>
======================== 3 tests collected in 0.12s ========================
自定义测试收集
你可以通过简单地修改pytest
的配置文件(如pytest.ini
),来指示pytest
从每个Python文件中发现测试。
# content of pytest.ini
[pytest]
python_files = *.py
然而在许多项目中,可能会有一个setup.py
文件,这个文件通常不希望被当作测试文件来导入。此外,还可能有只能由特定Python版本导入的文件。对于这样的情况,你可以在conftest.py
文件中动态定义要忽略的文件列表,从而避免这些文件被pytest
作为测试文件收集。
# conftest.py 文件的内容
import sys
collect_ignore = ["setup.py"] # 始终忽略 setup.py
# 根据Python版本动态添加要忽略的文件
if sys.version_info[0] > 2: # 如果Python主版本号大于2(即Python 3及更高版本)
collect_ignore.append("pkg/module_py2.py") # 忽略只能在Python 2中导入的文件
然后如果你有一个这样的模块文件:
# content of pkg/module_py2.py
def test_only_on_python2():
try:
assert 0
except Exception, e:
pass
还有一个setup.py文件,像这样:
# content of setup.py
0 / 0 # will raise exception if imported
如果你使用Python 2解释器运行pytest
,那么pytest
将只会发现找到一个测试,并且会忽略setup.py
文件。
#$ pytest --collect-only
====== test session starts ======
platform linux2 -- Python 2.7.10, pytest-2.9.1, py-1.4.31, pluggy-0.3.1
rootdir: $REGENDOC_TMPDIR, inifile: pytest.ini
collected 1 items
<Module 'pkg/module_py2.py'>
<Function 'test_only_on_python2'>
====== 1 tests found in 0.04 seconds ======
如果使用Python 3解释器运行,则测试文件和setup.py文件将被忽略
$ pytest --collect-only
=========================== test session starts ============================
platform linux -- Python 3.x.y, pytest-8.x.y, pluggy-1.x.y
rootdir: /home/sweet/project
configfile: pytest.ini
collected 0 items
======================= no tests collected in 0.12s ========================
还可以通过向collect_ignore_glob
添加模式来基于Unix shell样式的通配符忽略文件。
以下是一个conftest.py
文件的示例,它会在使用Python 3解释器执行时忽略setup.py
文件以及所有以_py2.py
结尾的文件:
# conftest.py 文件的内容
import sys
collect_ignore = ["setup.py"] # 始终忽略 setup.py 文件
if sys.version_info[0] > 2: # 如果Python主版本号大于2(即Python 3)
collect_ignore_glob = ["*_py2.py"] # 则忽略所有以 _py2.py 结尾的文件
自Pytest 2.6版本以来,用户可以通过将布尔类型的__test__
属性设置为False来阻止pytest发现以Test开头的类作为测试用例。
# Will not be discovered as a test
class TestClass:
__test__ = False