首页 > 解决方案 > Pytest - 多个测试可以共享相同的请求响应吗?

问题描述

我有一个 url 对列表,并为它们创建了这个参数化测试:

url_list = [
    ['example1.com/x', 'example2.com/x'],
    ['example1.com/y', 'example2.com/y'],
    ['example1.com/z', 'example2.com/z'],
    ['example1.com/v', 'example2.com/v'],
    ['example1.com/w', 'example2.com/w'],
]

@pytest.mark.parametrize('url1, url2', url_list)
def test_urls(url1: str, url2: str):
    response1 = requests.get(url1)
    response2 = requests.get(url2)

    assert response1.status_code == response2.status_code

    body1 = response1.json()
    body2 = response2.json()

    for field in ['one', 'two', 'three']:
        assert body1[field] == body2[field]

问题是如果 for 的值'one'不好,我们就不会测试'two'and的值'three'

我正在考虑添加另一个参数化,如下所示:

@pytest.mark.parametrize('field', ['one', 'two', 'three'])
@pytest.mark.parametrize('url1, url2', url_list)
def test_urls(url1: str, url2: str):
    response1 = requests.get(url1)
    response2 = requests.get(url2)

    assert response1.status_code == response2.status_code

    body1 = response1.json()
    body2 = response2.json()

    assert body1[field] == body2[field]

这样做的问题是同一个请求将被执行多次。

我可以使用全局变量来存储测试之间的请求响应,但这感觉很难看。

pytest 中有什么可以帮助我的吗?

还是一种设计模式/一种pythonic方式?

我已经使用 python 几年了,但这是我第一次使用 pytest。

标签: pythonpytest

解决方案


这可以通过使用夹具范围来解决:

Fixtures 在测试首次请求时创建,并根据其范围销毁

普通夹具具有函数范围,但如果您想在同一个文件中重用夹具值,scope="module"或者 scope="class" 可能是最合适的,但其他选项也是可能的。


@pytest.fixture(scope="module")
def response1():
    yield requests.get(url1)

@pytest.fixture(scope="session")
def response2():
    yield requests.get(url2)

def test_responses1(response1, response2):
    assert response1.status_code == response2.status_code

@pytest.mark.parametrize("field", ["one", "two", "three"])
def test_responses2(field, response1, response2):
    body1 = response1.json()
    body2 = response2.json()
    assert body1[field] == body2[field]

要验证每个夹具只被调用一次,您可以运行 pytest-s并在每个夹具中打印一些值。IE。重写response1

@pytest.fixture(scope="module")
def response1():
    print("in response1")
    yield requests.get(url1) 

然后运行pytest -s你的测试

编辑:如果网址总是成对出现,我将按以下方式重写代码:

url_pairs = [('url1a', 'url1b'), ('url2a', 'url2b')]

@pytest.fixture(scope="session", params=url_pairs)
def response_pairs(request):
    url_a, url_b = request.param
    yield requests.get(url_a), requests.get(url_b)

def test_responses1(response_pairs):
    response_a, response_b = response_pairs
    assert response_a.status_code == response_b.status_code

@pytest.mark.parametrize("field", ["one", "two", "three"])
def test_responses2(field, response_pairs):
    body_a = response_pairs[0].json()
    body_b = response_pairs[1].json()
    assert body_a[field] == body_b[field]

推荐阅读