【问题标题】:py.test: How to generate tests from fixturespy.test:如何从夹具生成测试
【发布时间】:2017-09-02 06:33:43
【问题描述】:

我正在编写一组工具来测试自定义 HTTP 服务器的行为:是否设置了适当的响应代码、标头字段等。我正在使用 pytest 编写测试。

目标是向多个资源发出请求,然后在多个测试中评估响应:每个测试都应测试 HTTP 响应的一个方面。但是,并非每个响应都经过每个测试的测试,反之亦然。

为了避免多次发送相同的 HTTP 请求并重复使用 HTTP 响应消息,我正在考虑使用 pytest 的固定装置,并在不同的 HTTP 响应上运行相同的测试,我想使用 pytest 的生成测试功能。 导入pytest 导入请求

def pytest_generate_tests(metafunc):
    funcarglist = metafunc.cls.params[metafunc.function.__name__]
    argnames = sorted(funcarglist[0])
    metafunc.parametrize(argnames, [[funcargs[name] for name in argnames]
                                    for funcargs in funcarglist])


class TestHTTP(object):
    @pytest.fixture(scope="class")
    def get_root(self, request):
        return requests.get("http://test.com")

    @pytest.fixture(scope="class")
    def get_missing(self, request):
        return requests.get("http://test.com/not-there")

    def test_status_code(self, response, code):
        assert response.status_code == code

    def test_header_value(self, response, field, value):
        assert response.headers[field] == value

    params = {
        'test_status_code': [dict(response=get_root, code=200),
                             dict(response=get_missing, code=404), ],
        'test_header_value': [dict(response=get_root, field="content-type", value="text/html"),
                              dict(response=get_missing, field="content-type", value="text/html"), ],
    }

问题似乎在于定义参数:dict(response=get_root, code=200) 和类似的定义没有实现,我想绑定在夹具和实际函数引用上。

在运行测试时,我得到了这样的错误:

________________________________________________ TestHTTP.test_header_value[content-type-response0-text/html] _________________________________________________

self = <ev-question.TestHTTP object at 0x7fec8ce33d30>, response = <function TestHTTP.get_root at 0x7fec8ce8aa60>, field = 'content-type', value = 'text/html'

    def test_header_value(self, response, field, value):
>       assert response.headers[field] == value
E       AttributeError: 'function' object has no attribute 'headers'

test_server.py:32: AttributeError

我怎样才能说服 pytest 使用fixture 值而不是函数?

【问题讨论】:

    标签: python pytest generated-code fixture


    【解决方案1】:

    无需从夹具生成测试,只需参数化夹具并为其返回的值编写常规测试:

    import pytest
    import requests
    
    
    should_work = [
        {
            "url": "http://test.com",
            "code": 200,
            "fields": {"content-type": "text/html"}
        },
    ]
    
    should_fail = [
        {
            "url": "http://test.com/not-there",
            "code": 404,
            "fields": {"content-type": "text/html"}
        },
    ]
    
    should_all = should_work + should_fail
    
    
    def response(request):
        retval = dict(request.param)  # {"url": ..., "code": ... }
        retval['response'] = requests.get(request.param['url'])
        return retval  # {"reponse": ..., "url": ..., "code": ... }
    
    
    # One fixture for working requests
    response_work = pytest.fixture(scope="module", params=should_work)(response)
    # One fixture for failing requests
    response_fail = pytest.fixture(scope="module", params=should_fail)(response)
    # One fixture for all requests
    response_all = pytest.fixture(scope="module", params=should_all)(response)
    
    
    # This test only requests failing fixture data
    def test_status_code(response_fail):
        assert response_fail['response'].status_code == response_fail['code']
    
    
    # This test all requests fixture data
    @pytest.mark.parametrize("field", ["content-type"])
    def test_header_content_type(response_all, field):
        assert response_all['response'].headers[field] == response_all['fields'][field]
    

    【讨论】:

    • 谢谢你,尼尔斯。但是,此代码将在所有夹具上运行所有测试,这不是我想要的。我想指定应该组合哪些测试和哪些夹具。为了论证,假设您不想检查正常请求的返回码,只检查应该返回 404 的请求。另外,我希望每个测试只检查响应的一个方面,即只执行一个断言。因此,如果缺少一个标头,我应该会收到一个错误,仅针对该标头,而对于其他标头,测试应该通过。
    • 我刚刚意识到,我可以跳过检查key in response 来查看response 对象是否有key,如果有,我可以pytest.skip() 它。
    • 为什么不测试每个请求的返回值呢?对某些条件的特殊处理越少,您犯错误的可能性就越小。
    • 我已将最后一个测试函数更改为接受 field 名称参数,因此每个名称都有一个测试。
    • 我已经更新了答案,以便能够将工作与失败的测试数据区分开来,但我认为您不会有双重请求。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 1970-01-01
    相关资源
    最近更新 更多