[英]Pre-test tasks using pytest markers?
I've got a Python application using pytest. For several of my tests, there are API calls to Elasticsearch (using elasticsearch-dsl-py) that slow down my tests that I'd like to:我有一个使用 pytest 的 Python 应用程序。对于我的几个测试,有 API 次调用 Elasticsearch(使用 elasticsearch-dsl-py),这会减慢我想要的测试:
yield
.yield
时夹具的工作方式一样。 This is mostly inspired by pytest-django where you have to use the django_db
marker in order to make a conn to the database (but they throw an error if you try to connect to the DB, whereas I just don't want a call in the first place, that's all).这主要是受 pytest-django 的启发,你必须使用
django_db
标记才能连接到数据库(但如果你尝试连接到数据库,它们会抛出错误,而我只是不想调用第一名,仅此而已)。
For example:例如:
def test_unintentionally_using_es():
"""I don't want a call going to Elasticsearch. But they just happen. Is there a way to "mock" the call? Or even just prevent the call from happening?"""
@pytest.mark.elastic
def test_intentionally_using_es():
"""I would like for this marker to perform some tasks beforehand (i.e. clear the indices)"""
# To replicate that second test, I currently use a fixture:
@pytest.fixture
def elastic():
# Pre-test tasks
yield something
I think that's a use-case for markers right?我认为这是标记的用例,对吗? Mostly inspired by pytest-django.
主要受 pytest-django 启发。
Your initial approach with having a combination of a fixture and a custom marker is the correct one;您最初结合使用固定装置和自定义标记的方法是正确的; in the code below, I took the code from your question and filled in the gaps.
在下面的代码中,我从你的问题中提取了代码并填补了空白。
Suppose we have some dummy function to test that uses the official elasticsearch
client:假设我们有一些虚拟 function 来测试使用官方
elasticsearch
客户端:
# lib.py
from datetime import datetime
from elasticsearch import Elasticsearch
def f():
es = Elasticsearch()
es.indices.create(index='my-index', ignore=400)
return es.index(
index="my-index",
id=42,
body={"any": "data", "timestamp": datetime.now()},
)
We add two tests, one is not marked with elastic
and should operate on fake client, the other one is marked and needs access to real client:我们添加两个测试,一个没有标记为
elastic
并且应该在假客户端上运行,另一个有标记并且需要访问真实客户端:
# test_lib.py
from lib import f
def test_fake():
resp = f()
assert resp["_id"] == "42"
@pytest.mark.elastic
def test_real():
resp = f()
assert resp["_id"] == "42"
Now let's write the elastic()
fixture that will mock the Elasticsearch
class depending on whether the elastic
marker was set:现在让我们编写
elastic()
fixture,它将根据是否设置了elastic
标记来模拟Elasticsearch
class:
from unittest.mock import MagicMock, patch
import pytest
@pytest.fixture(autouse=True)
def elastic(request):
should_mock = request.node.get_closest_marker("elastic") is None
if should_mock:
patcher = patch('lib.Elasticsearch')
fake_es = patcher.start()
# this is just a mock example
fake_es.return_value.index.return_value.__getitem__.return_value = "42"
else:
... # e.g. start the real server here etc
yield
if should_mock:
patcher.stop()
Notice the usage of autouse=True
: the fixture will be executed on each test invocation, but only do the patching if the test is not marked.请注意
autouse=True
的用法:fixture 将在每次测试调用时执行,但仅在测试未标记时才进行修补。 This presence of the marker is checked via request.node.get_closest_marker("elastic") is None
.通过
request.node.get_closest_marker("elastic") is None
检查标记的存在。 If you run both tests now, test_fake
will pass because elastic
mocks the Elasticsearch.index()
response, while test_real
will fail, assuming you don't have a server running on port 9200.如果您现在运行这两个测试,
test_fake
将通过,因为elastic
Elasticsearch.index()
响应,而test_real
将失败,假设您没有在端口 9200 上运行的服务器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.