Python 使用pytest标记进行预测试任务?

Python 使用pytest标记进行预测试任务?,python,pytest,Python,Pytest,我有一个使用pytest的Python应用程序。对于我的几个测试,有使用Elasticsearch dsl py对Elasticsearch的API调用,这会减慢我的测试速度,我想: 防止,除非使用Pytest标记。 如果使用了标记,我希望该标记在测试运行之前执行一些代码。就像如果你使用收益率,固定装置将如何工作。 这主要是受pytest django的启发,在pytest django中,您必须使用django_db标记来连接数据库,但是如果您尝试连接到db,它们会抛出一个错误,而我只是不想首

我有一个使用pytest的Python应用程序。对于我的几个测试,有使用Elasticsearch dsl py对Elasticsearch的API调用,这会减慢我的测试速度,我想:

防止,除非使用Pytest标记。 如果使用了标记,我希望该标记在测试运行之前执行一些代码。就像如果你使用收益率,固定装置将如何工作。 这主要是受pytest django的启发,在pytest django中,您必须使用django_db标记来连接数据库,但是如果您尝试连接到db,它们会抛出一个错误,而我只是不想首先调用,仅此而已

例如:

def测试\u无意中\u使用\u es: 我不想打电话到Elasticsearch。但它们只是发生了。有没有办法模仿这个电话?甚至只是阻止电话的发生? @有弹性的 def测试使用以下工具: 我希望该标记器能够提前执行一些任务,即清除索引 为了复制第二个测试,我目前使用了一个夹具: @pytest.fixture def弹性: 测试前任务 交出某物
我认为这是标记的一个用例,对吗?主要灵感来源于pytest django。

您最初采用的组合夹具和自定义标记的方法是正确的;在下面的代码中,我从您的问题中提取了代码并填补了空白

假设我们要测试一些使用官方客户端的虚拟函数:

我们增加了两个测试,一个没有弹性标记,应该在假客户端上运行,另一个有标记,需要访问真实客户端:

# 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"
现在,让我们编写一个ElasticFixture,它将根据是否设置了elastic标记来模拟Elasticsearch类:

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()

注意autouse=True的用法:夹具将在每次测试调用时执行,但仅在测试未标记时执行修补。通过request.node.get_closest_markerelastic为None检查标记是否存在。如果您现在运行这两个测试,test\u fake将通过,因为elastic模拟Elasticsearch.index响应,而test\u real将失败,前提是您没有在端口9200上运行服务器。

您最初使用夹具和自定义标记组合的方法是正确的;在下面的代码中,我从您的问题中提取了代码并填补了空白

假设我们要测试一些使用官方客户端的虚拟函数:

我们增加了两个测试,一个没有弹性标记,应该在假客户端上运行,另一个有标记,需要访问真实客户端:

# 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"
现在,让我们编写一个ElasticFixture,它将根据是否设置了elastic标记来模拟Elasticsearch类:

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()

注意autouse=True的用法:夹具将在每次测试调用时执行,但仅在测试未标记时执行修补。通过request.node.get_closest_markerelastic为None检查标记是否存在。如果您现在运行两个测试,test\u fake将通过,因为Elasticsearch.index响应会被Elasticsearch模拟,而test\u real将失败,前提是您没有在端口9200上运行服务器。

@pytest.mark.usefixtureselastic?用于模拟Elasticsearch,查看例如:谢谢@hoefling啊,我认为usefixtures装饰器非常适合第二种情况,而不是马克笔。但是,在没有应用标记/固定装置的情况下,我如何防止默认情况下调用ES?我想我现在明白你的意思了,稍后将添加一个答案。@pytest.mark.usefixtureselastic?要模拟elasticsearch,请查看例如:Thank@hoefling啊,我认为usefixtures装饰器非常适合第二种情况,而不是标记。但我如何防止在没有应用标记/装置的情况下默认调用ES?我想我现在明白你的意思了,我将很快添加一个答案。非常高兴有这个答案!!!我从未学会如何正确使用mock和patch。我认为这是一个足以站稳脚跟的好答案,因此被接受。我想我唯一担心的是你在嘲笑一个具体的退货案例。我希望找到一种方法来阻止这些调用,但我认为Elasticsearch模拟库可能会这样做。非常感谢!是的,如果我错了,请纠正我-我想这更像是自我提醒-但是使用Elasticmock库可能意味着不使用他们的装饰程序,而是使用_get_Elasticmock进行修补@acw你也可以只做patcher=patch'lib.Elasticsearch',FakeElasticsearch_get_elasticmock只是一种缓存假客户端以供重用的方法。我同意elasticmock的公共API非常简洁,可以提供更多的模拟可能性。非常高兴有这个答案!!!我从未学会如何正确使用mock和patch。我认为这是一个足以站稳脚跟的好答案,因此被接受。我想我唯一担心的是你在嘲笑一个具体的退货案例。我希望找到一种方法来阻止这些调用,但我认为Elasticsearch模拟库可能会这样做。非常感谢!是的,如果我错了,请纠正我 -我想这更像是对self的一个提示——但是使用Elasticmock库可能意味着不使用他们的装饰程序,而是使用_get_Elasticmock进行修补@acw你也可以只做patcher=patch'lib.Elasticsearch',FakeElasticsearch_get_elasticmock只是一种缓存假客户端以供重用的方法。我同意elasticmock的公共API非常简洁,可以提供更多的模拟可能性。