pytest05 Marking test functions with attributes

通过使用 pytest.mark 可以轻松地在测试函数上设置元数据。一些内置标记,例如:

  • skip - 总是跳过测试函数
  • skipif - 如果满足某个条件,则跳过测试函数
  • xfail - 如果满足某个条件,则产生“预期失败”结果
  • parametrize 对同一测试函数执行多个调用

很容易创建自定义标记,或将标记应用于整个测试类或模块。这些标记可以被插件使用,也常用于 select tests 在命令行上 -m 选择权。

注解:标记只能用于测试,对 fixtures 没有作用。


注册标记

可以在 pytest.ini 的文件中注册自定义标记,像这样:

1
2
3
4
[pytest]
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
serial

请注意,在 : 后面的是可选描述。

在这个例子中,我们定义了两个标记:slowserialslow 标记有一个描述,告诉其他开发者这个标记是用来标识那些执行速度较慢的测试,并且可以通过 -m "not slow" 命令行参数来排除这些慢速测试。serial 没有描述,但是它的用途可能是为了确保某些测试按照特定的顺序执行。

或者,可以在 pytest_configure 钩子中程序化地注册新的标记,这个函数会在pytest启动时调用,可以用来动态地添加或修改配置:

1
2
3
4
def pytest_configure(config):
config.addinivalue_line(
"markers", "env(name): mark test to run only on named environment"
)

在这个例子中,我们定义了一个 env 标记,它带有一个参数 name,表示测试仅在名为 name 的环境中运行。这种情况下,name 可以是你定义的任何环境名称,例如 productionstaging 等。


使用注册的标记

一旦注册了自定义标记,就可以在测试函数上使用它们。例如:

1
2
3
4
5
6
7
8
9
@pytest.mark.slow
def test_something_slow():
# 这是一个慢速测试
pass

@pytest.mark.serial
def test_needs_serial_execution():
# 这个测试需要按顺序执行
pass

当你运行pytest时,可以使用 -m 参数来选择或排除标记:

1
2
3
4
5
# 运行所有标记为 'slow' 的测试
$ pytest -m slow

# 排除所有标记为 'slow' 的测试
$ pytest -m "not slow"

注册标记可以帮助提高测试的组织性和可读性,同时也能确保只有已知的标记被使用,从而避免错误的标记导致的问题。如果你正在开发一个pytest插件,强烈建议你注册所有使用的标记,以便用户更好地理解你的插件是如何工作的。


如何配置环境名称

配置环境名称通常是通过以下几种方式之一来完成的:

1. 环境变量

你可以设置环境变量来指示当前的环境。例如,在Linux或Unix系统中,你可以设置一个名为ENVENVIRONMENT的环境变量:

1
export ENV=production

然后在应用程序中,你可以通过读取这个环境变量来确定当前的环境:

1
2
import os
current_env = os.getenv('ENV', 'development') # 默认为 development
2. 配置文件

另一种常见的做法是在项目的配置文件中指定环境。例如,在Python项目中,你可以有一个settings.py文件,里面包含了不同的环境配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Config:
DEBUG = False
TESTING = False

class DevelopmentConfig(Config):
DEBUG = True

class TestingConfig(Config):
TESTING = True

class ProductionConfig(Config):
pass

config_by_name = dict(
development=DevelopmentConfig,
testing=TestingConfig,
production=ProductionConfig
)

active_config = config_by_name['development'] # 默认为开发环境

在测试中,你可以通过修改active_config来切换环境:

1
active_config = config_by_name['production']
3. 命令行参数

还可以通过命令行参数来传递环境名称。例如:

1
python app.py --env=production

然后在应用程序中解析这些参数:

1
2
3
4
5
6
7
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--env', default='development')
args = parser.parse_args()

current_env = args.env

在pytest中使用环境名称

在pytest测试中,你可以根据环境名称来决定是否运行某些测试。例如,如果某个特性只在生产环境中生效,你可以标记该测试并仅在生产环境中运行它:

1
2
3
4
@pytest.mark.env('production')
def test_production_only_feature():
# 这个测试只在生产环境中运行
pass

然后,在运行pytest时,你可以使用-m选项来选择性地运行这些标记的测试:

1
pytest -m env='production'

这样,你就可以确保只有在正确的环境下才会运行相关的测试。


在未知标记上引发错误

未注册的标记应用于 @pytest.mark.name_of_the_mark 装饰器将始终发出警告,以避免由于输入错误的名称而静默地执行一些令人惊讶的操作。如前一节所述,你可以通过在你的 pytest.ini 文件中或使用自定义 pytest_configure 钩子来停止警告。

--strict-markers 传递了命令行标志,任何应用于 @pytest.mark.name_of_the_markdecorator的未知标记,将触发一个错误。在项目中,你可以通过添加 --strict-markersaddopts来强制验证 :

1
2
3
4
5
[pytest]
addopts = --strict-markers
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
serial

未注册的标记发出警告

默认情况下,pytest会对未注册的标记发出警告。这样做是为了防止因为拼写错误或其他误操作而导致的标记无效。例如,如果你不小心把slow标记拼写成了slw

1
2
3
@pytest.mark.slw
def test_something():
pass

pytest会识别出slw是一个未知标记,并发出警告。这样做的目的是提醒开发者检查标记是否存在拼写错误或其他问题。

使用 --strict-markers 选项

为了进一步提高标记使用的严格性,pytest提供了一个--strict-markers命令行选项。当启用此选项时,任何未注册的标记都会导致一个错误,而不是仅仅发出警告。这意味着测试将无法运行,直到标记问题得到解决。

例如,如果你在命令行中运行pytest并指定了--strict-markers选项:

1
pytest --strict-markers

如果存在未注册的标记,pytest将显示错误信息,并阻止测试的执行。

pytest.ini 文件中配置

你还可以在pytest.ini文件中配置--strict-markers选项,使其成为项目的默认行为。这样每次运行pytest时都会自动启用严格的标记检查。例如:

1
2
3
4
5
[pytest]
addopts = --strict-markers
markers =
slow: marks tests as slow (deselect with '-m "not slow"')
serial

在这个配置文件中,addopts项设置了默认的命令行选项,使得每次运行pytest时都会启用严格的标记检查。markers项则注册了自定义标记,如slowserial

总结:使用标记可以帮助你更好地管理和运行测试。注册标记可以避免因为拼写错误或输入错误而导致的问题。通过启用--strict-markers选项,可以进一步确保标记使用的准确性。在项目配置文件中设置这些选项可以确保每次运行pytest时都遵循一致的标准。