Pytest:仅测试一个参数化夹具的实例

时间:2020-08-13 12:43:00

标签: python pytest

设置

假设我在conftest.py上定义了测试资源

class ClassifyRequest:
    pass

class OCRRequest:
    pass

@pytest.fixture(params=[ClassifyRequest, OCRRequest])
def api_request(request):
    return request.param()  # return one of the request instances

然后,在test_api.py中,我使用参数化的固定装置来测试服务:

def test_service(api_request):
    response = send_request(api_request)
    assert response.ok()

一切都很好,但是我想测试专用夹具api_request[ClassifyRequest]

@pytest.mark.usefixture("api_request[ClassifyRequest]")
def test_classification():
    # do something with the api_request fixture

问题

为测试功能专门设置参数化夹具的方式是什么?我有两个想法:

  1. 仅使用非参数化夹具。这不可避免地导致样板代码。
  2. 从灯具装饰器中删除显式参数化,并使用间接参数化,例如
    @pytest.mark.parametrize("response_class", ["classify", "ocr"])
    def test_api(api_request):
        # do smth
    
    用字符串替换类参数等于创建两个配置源。如果要添加另一个参数怎么办?我是否需要为其设计一个新的字符串,以及间接在api_request灯具内实例化一个对象?
  3. 除了保留类参数化并将类移到conftest.py之外,这是相同的,因为pytest无法使用import语句从该模块中导入名称。

其他信息

pytest == 6.0.1

3 个答案:

答案 0 :(得分:0)

如果您的夹具所做的只是实例化,我将选择参数化测试,而不是夹具。但是,好吧,如果您仍然必须手动对其进行专业化,则只需添加一个包装器即可使灯具可调用:

import pytest
import types

class ClassifyRequest:
    def __init__(self):
        print("ClassifyRequest ctor")

class OCRRequest:
    def __init__(self):
        print("OCRRequest ctor")

def api_request_wrapper(request):
    return request.param()  # return one of the request instances

@pytest.fixture(params=[ClassifyRequest, OCRRequest])
def api_request(request):
    return api_request_wrapper(request)

def test_classification():
    request = types.SimpleNamespace()
    request.param = ClassifyRequest
    instance = api_request_wrapper(request)

不过,似乎有些怪癖。

答案 1 :(得分:0)

您要实现的目标是创建测试用例过滤规则。最好的方法是通过Pytest中的“ pytest_collection_modifyitems”钩子。

一旦从您提供给Pytest的输入路径中收集了所有测试,就会调用此钩子。

您可以将逻辑放在这个钩子中。

始终将ID与您的参数相关联是一种最佳做法,如下所示:

@pytest.fixture(params=[ClassifyRequest, OCRRequest], 
                ids=['ClassifyRequest', 'OCRRequest'])
def api_request(request):
    return request.param()  # return one of the request instances

有了这个,您的测试用例将生成为test_classification [ClassifyRequest]和test_classification ['OCRRequest']。

如果您正在运行一组特定的测试,并且希望将过滤应用于所有测试,那么-k选项本身就足够了。

但是由于这里只对要应用规则的部分测试有用,因此挂钩定义可以在存在测试的模块中。

答案 2 :(得分:0)

注意:这是一个初步结论,我在pytest Github上创建了issue,以查看社区对此主题的看法。


我认为实现所需专业化的最干净方法是将请求类移至单独的模块,并使用conftest.py来声明仅夹具函数。根据pytest documentation

如果在实施测试期间您意识到要使用多个测试文件中的夹具功能,可以将其移至conftest.py文件中。

如果您想使文件中的测试数据对您的测试可用,那么一种很好的方法是将这些数据加载到夹具中以供测试使用。

通过这种方式,我可以在测试模块中导入类,并通过测试函数间接设置灯具的参数。就我而言,请求类非常容易实例化,因此不需要为每个类都使用单独的夹具,而只需要聚合。但通常,可以为每种资源定义一个夹具,并为一个参数化的夹具定义一个汇总。