python-3.x - 何时使用 pytest 固定装置?
问题描述
我是测试新手,偶然发现了 pytest 固定装置,但我不完全确定何时使用它们以及为什么它们有用。
例如,请看下面的代码:
import pytest
@pytest.fixture
def input_value():
input = 39
return input
def test_divisible_by_3(input_value):
assert input_value % 3 == 0
def test_divisible_by_6(input_value):
assert input_value % 6 == 0
pytest.fixture 这里的作用是什么?为什么我们不能简单地创建一个函数input_value()
并在测试函数中运行该函数?例如:
import pytest
def input_value():
input = 39
return input
def test_divisible_by_3():
assert input_value() % 3 == 0
def test_divisible_by_6():
assert input_value() % 6 == 0
为什么我们不能这样做?使用固定装置有什么用?
解决方案
Pytest Fixtures 和常规函数都可用于构建测试代码并减少代码重复。George Udosen 提供的答案很好地解释了这一点。
但是,OP 专门询问了 apytest.fixture
和常规 Python 函数之间的区别,并且存在许多区别:
Pytest 固定装置的范围
默认情况下,pytest.fixture
为每个引用夹具的测试函数执行 a 。但是,在某些情况下,夹具设置可能在计算上很昂贵或很耗时,例如初始化数据库。为此,pytest.fixture
可以为 a 配置更大的范围。这允许pytest.fixture
在模块中的测试(模块范围)甚至在 pytest 运行的所有测试(会话范围)中重用。以下示例使用模块范围的固定装置来加速测试:
from time import sleep
import pytest
@pytest.fixture(scope="module")
def expensive_setup():
return sleep(10)
def test_a(expensive_setup):
pass # expensive_setup is instantiated for this test
def test_b(expensive_setup):
pass # Reuses expensive_setup, no need to wait 10s
尽管可以通过常规函数调用实现不同的作用域,但作用域固定装置使用起来更愉快。
Pytest Fixtures 基于依赖注入
Pytest 在测试收集阶段注册所有夹具。当测试函数需要一个名称与注册的夹具名称匹配的参数时,Pytest 将注意为测试实例化夹具并将实例提供给测试函数。这是依赖注入的一种形式。
与常规函数相比,优势在于您可以pytest.fixture
按名称引用任何函数,而无需显式导入它。例如,Pytest 带有一个tmp_path
夹具,任何测试都可以使用它来处理临时文件。以下示例取自Pytest 文档:
CONTENT = "content"
def test_create_file(tmp_path):
d = tmp_path / "sub"
d.mkdir()
p = d / "hello.txt"
p.write_text(CONTENT)
assert p.read_text() == CONTENT
assert len(list(tmp_path.iterdir())) == 1
assert 0
用户使用前无需导入tmp_path
,非常方便。
甚至可以在没有测试功能请求的情况下将夹具应用于测试功能(请参阅Autouse fixtures)。
Pytest 夹具可以参数化
与测试参数化非常相似, 夹具参数化允许用户指定夹具的多个“变体”,每个变体具有不同的返回值。使用该夹具的每个测试都将执行多次,每个变体一次。假设您想测试您的所有代码是否都针对 HTTP 和 HTTPS URL 进行了测试,您可能会执行以下操作:
import pytest
@pytest.fixture(params=["http", "https"])
def url_scheme(request):
return request.param
def test_get_call_succeeds(url_scheme):
# Make some assertions
assert True
参数化的夹具将导致每个版本的夹具执行每个引用测试:
$ pytest
tests/test_fixture_param.py::test_get_call_succeeds[http] PASSED [ 50%]
tests/test_fixture_param.py::test_get_call_succeeds[https] PASSED [100%]
======== 2 passed in 0.01s ========
结论
与常规函数调用相比,Pytest 固定装置提供了许多生活质量改进。我建议始终更喜欢 Pytest 固定装置而不是常规功能,除非您必须能够直接调用固定装置。不直接调用 pytest 固定装置,调用将失败。
推荐阅读
- c# - 始终将查询更新零更新到数据库
- c++ - 数组维度的变化导致c++崩溃
- c# - 无法从资源文件中读取本地化键值
- angularjs - AngularJS Html 元素在 Ajax 之后没有正确显示
- selenium - Selenium:无法找到一组匹配的功能
- javascript - JavaScript 语法规则
- nlp - 查找表在 Rasa NLU 的训练数据中不起作用
- asp.net-mvc - mvc.sitemap 中的 2 个节点指的是具有不同参数的 1 个操作,它们未显示在面包屑中
- sql - 当我在 BCP 命令中使用“>”大于字符时该功能不起作用
- django - 如何在select2中显示一棵树?