py.test:如何从灯具生成测试(py.test: How to generate tests from fixtures)

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

目标是向多个资源发出请求,然后在多个测试中评估响应:每个测试应该测试HTTP响应的单个方面。 但是,并非每个测试都会针对每个测试进行测试,反之亦然。

为了避免多次发送相同的HTTP请求并重用HTTP响应消息,我正在考虑使用pytest的fixture,并在不同的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"), ],
    }
 

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

运行测试时,我遇到了这种错误:

________________________________________________ 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取得夹具值而不是函数?

I'm writing a set of tools to test the behavior of a custom HTTP server: whether it is setting appropriate response codes, header fields etc. I'm using pytest to write tests.

The goal is to make requests to several resources, and then evaluate the response in multiple tests: each test should test a single aspect of the HTTP response. However, not every response is tested with every test and vice-versa.

To avoid sending the same HTTP request multiple time and reuse HTTP responses messages, I'm thinking of using pytest's fixtures, and to run the same tests on different HTTP responses I'd like to use pytest's generate test capabilities. import pytest import requests

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"), ],
    }
 

The problem appears to be in defining params: dict(response=get_root, code=200) and similar definitions do not realize, I'd like to bind on the fixture and on on the actual function reference.

When running tests, I get this kinds of errors:

________________________________________________ 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
 

How may I convince the pytest to take the fixture value instead of the function?

最满意答案

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

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]

No need to generate tests from fixtues, just parameterize your fixture and write regular tests for the values it returns:

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]

更多推荐