pytest-recording简介
pytest-recording是一个pytest插件,可以在测试中记录网络交互。插件基于VCR.py
,VCR.py
是一个用于Python的HTTP交互录制库。通过pytest-recording,可以记录HTTP请求和响应,并在测试中重放这些交互。
安装pytest-recording
使用pip安装:
pip install pytest-recording
注意,pytest-recording
与pytest-vcr
不兼容,因此在安装pytest-recording之前,确保已经卸载了pytest-vcr。
使用pytest-recording
基本用法
pytest-recording提供了一个简单的装饰器@pytest.mark.vcr
,用于标记需要记录网络交互的测试函数。这个装饰器反映了VCR.py的use_cassettes
API:
import pytest
import requests
@pytest.mark.vcr
def test_single():
assert requests.get("http://httpbin.org/get").text == '{"get": true}'
pytest-recording将记录对http://httpbin.org/get
的GET请求和响应,并将它们保存到一个YAML文件中(默认情况下,该文件位于cassettes/{module_name}/test_single.yaml
)。在后续运行中,这个请求将被重放,而不会实际发送到网络。
使用默认磁带
有时候,可能希望多个测试函数共享同一个网络交互记录。这时,可以使用@pytest.mark.default_cassette
装饰器来指定一个默认磁带文件。
@pytest.mark.default_cassette("example.yaml")
@pytest.mark.vcr
def test_default():
assert requests.get("http://httpbin.org/get").text == '{"get": true}'
所有使用了@pytest.mark.default_cassette("example.yaml")
和@pytest.mark.vcr
装饰器的测试函数都将共享同一个名为example.yaml
的磁带文件。
结合多个磁带
除了使用默认磁带外,你还可以为单个测试函数指定多个磁带文件。这些磁带文件将被合并使用。
@pytest.mark.vcr("/path/to/ip.yaml", "/path/to/get.yaml")
def test_multiple():
assert requests.get("http://httpbin.org/get").text == '{"get": true}'
assert requests.get("http://httpbin.org/ip").text == '{"ip": true}'
在这个示例中,test_multiple
函数将使用ip.yaml
和get.yaml
这两个磁带文件。当对http://httpbin.org/get
发起请求时,将使用get.yaml
中的记录;当对http://httpbin.org/ip
发起请求时,将使用ip.yaml
中的记录。
断言调用/响应
你还可以基于磁带中的调用/响应来做出断言。这可以通过将vcr
对象作为测试函数的参数来实现。
@pytest.mark.vcr
def test_call_count(vcr):
assert requests.get("http://httpbin.org/get").text == '{"get": true}'
assert requests.get("http://httpbin.org/ip").text == '{"ip": true}'
assert vcr.play_count == 2
在这个示例中,vcr
对象包含了磁带中的所有调用和响应信息。我们可以通过vcr.play_count
来断言有多少个交互被重放了。
配置pytest-recording
pytest-recording提供了多种配置选项,以满足不同的测试需求。
录制模式
pytest-recording默认使用none
录制模式,防止不经意的网络请求。要允许网络请求,需要通过--record-mode
CLI选项来指定一个不同的录制模式(如once
)。
pytest --record-mode=once
VCR支持4种录制模式:once、new_episodes、none、all
vcr_config fixture
可以通过vcr_config
fixture来提供录制配置。这个fixture可以具有任何作用域(session、package、module或function),并返回一个字典,该字典将直接传递给VCR.use_cassettes。
@pytest.fixture(scope="module")
def vcr_config():
return {
"ignore_localhost": True,
"filter_headers": ["authorization"]
}
为整个模块指定了一些VCR配置选项。这些选项将应用于所有使用了@pytest.mark.vcr
装饰器的测试函数。
合并配置
对于颗粒度更细的控制,可以将关键字参数传递给单个@pytest.mark.vcr
装饰器。这些参数将与通过vcr_config
fixture提供的配置合并成一个字典。合并时,具有更窄作用域(如function)的配置将覆盖具有更广作用域(如session)的配置。
@pytest.mark.vcr(filter_query_parameters=["api_key"])
def test_with_additional_config():
# ...
test_with_additional_config
函数将使用通过vcr_config
fixture提供的配置,但filter_query_parameters
选项将被覆盖为["api_key"]
。
重写记录模式
pytest-recording支持重写磁带的功能。这意味着你可以从头开始创建一个新的磁带文件,而不是在现有磁带文件上添加新的条目。然而,这个功能目前只适用于默认磁带文件,而不适用于额外的磁带文件。
可以通过命令行选项或vcr_config
fixture来启用重写记录模式:
pytest --rewrite-recording
或者:
@pytest.fixture(scope="module")
def vcr_config():
return {
"record_mode": "rewrite"
}
阻塞网络访问
为了增加测试的可靠性,可以阻塞网络访问。这样,即使测试代码尝试发起网络请求,这些请求也会被阻止。可以通过@pytest.mark.block_network
装饰器或--block-network
命令行选项来阻塞网络访问。
@pytest.mark.block_network
def test_with_blocked_network():
# ...
或者:
pytest --block-network
请注意,如果启用了VCR.py录制功能,那么对于使用了@pytest.mark.vcr
装饰器的测试函数来说,网络访问将不会被阻塞。
还可以允许访问指定的主机:
pytest --block-network --allow-hosts=example.com
或者通过vcr_config
fixture来指定允许访问的主机:
@pytest.fixture(scope="module")
def vcr_config():
return {
"allow_hosts": ["example.com"]
}
高级用法和钩子函数
pytest-recording还提供了一些高级用法和钩子函数,以满足更复杂的测试需求。
自定义匹配器、持久化器等
你可以通过pytest_recording_configure
钩子函数来获取VCR实例,并注册自定义的匹配器、持久化器等。
def pytest_recording_configure(config, vcr):
# 注册自定义匹配器、持久化器等
pass
禁用VCR.py集成
在某些情况下,你可能希望完全禁用VCR.py集成。这时,你可以通过--disable-recording
命令行选项来实现。
pytest --disable-recording