2017-04-07 159 views
0

我正在編寫一套工具來測試自定義HTTP服務器的行爲:是否設置適當的響應代碼,頭字段等我使用pytest寫試驗。py.test:如何從燈具生成測試

目標是向多個資源發出請求,然後在多個測試中評估響應:每個測試都應該測試HTTP響應的一個方面。但是,並不是每個響應都會在每次測試中進行測試,反之亦然。

爲了避免多次發送相同的HTTP請求並重復使用HTTP響應消息,我正在考慮使用pytest的fixtures,並在不同的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)和相似的定義不知道,我想在夾具上,而在實際的函數引用綁定。

在運行測試中,我得到這兩種錯誤:

________________________________________________ TestHTTP.test_header_value [內容型response0文本/ 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取夾具的價值,而不是功能?

回答

1

無需生成fixtues測試,只是參數的夾具和編寫正測試爲它返回的值:

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] 
+0

謝謝你,尼爾斯。但是,這段代碼將運行所有燈具的所有測試,這不是我所期望的。我想指定哪些測試和哪些燈具應該組合。爲了辯論的緣故,假設你不想檢查正常請求上的返回碼,只檢查返回404的返回碼。另外,我希望每個測試只檢查響應的一個方面,也就是說,只執行一個斷言。所以,如果缺少一個頭文件,我應該只會得到一個錯誤,而對於其他頭文件,測試應該通過。 – David

+0

我剛剛意識到,我可以用'key in response'來跳過檢查以查看'response'對象是否有'key',如果是,我可以'pytest.skip()'它。 – David

+0

爲什麼不測試每個請求的返回值?對特定條件的不太特別的處理,你犯錯誤的可能性就越小。 –