我正在努力理解这里提供的示例,并对其进行仿真,使其适用于post
方法,而不是get
方法。
当我测试response.status_code == 200
时,一切都很好。如何在不重复代码的情况下测试多个响应状态代码(如这里所示)?我知道一个人需要使用固定装置,我该如何利用它们?
这就是我现在的处境。
app.py
from typing import Dict, Union
from urllib.error import HTTPError
import requests
import structlog
logger = structlog.get_logger()
def get_access_token(
url: str, client_id: str, client_secret: str, grant_type: str
) -> Union[Dict[str, Union[str, int]], None]:
try:
r = requests.post(
url,
data={"grant_type": grant_type},
auth=(client_id, client_secret),
verify=True,
)
logger.info("Fetching token status code", status_code=r.status_code)
except HTTPError as http_err:
logger.error("HTTP error occurred", http_error=str(http_err))
except Exception as err:
logger.error("Other error occurred", exception=str(err))
else:
# The token expires in 10800 seconds
return r.json()
test_app.py
# contents of test_app.py, a simple test for our API retrieval
from typing import Dict, Union
import pytest
import requests
from app import get_access_token
# custom class to be the mock return value of requests.post()
class MockResponse:
status_code = 200
raise_for_status = None
@staticmethod
def json() -> Dict[str, Union[str, int]]:
return {
'access_token': 'fake-access-token',
'token_type': 'fake-token-type',
'expires_in': 10800,
}
@pytest.fixture
def mock_response(monkeypatch):
"""Requests.post() mocked to return json."""
def mock_post(*args, **kwargs):
return MockResponse()
monkeypatch.setattr(requests, "post", mock_post)
# notice our test uses the custom fixture instead of monkeypatch directly
def test_get_access_token_success(mock_response) -> None:
result = get_access_token(
url="https://fakeurl",
client_id="fake-client-id",
client_secret="fake-client-secret",
grant_type="fake-grant-type",
)
assert result['access_token'] == "fake-access-token"
assert result['token_type'] == "fake-token-type"
在@gold_cy的建议后重写app.py
from typing import Dict, Union
import requests
import structlog
logger = structlog.get_logger()
def get_access_token(
url: str,
client_id: str,
client_secret: str,
grant_type: str = 'client_credentials',
) -> Dict[str, Union[str, int]]:
try:
r = requests.post(
url,
data={"grant_type": grant_type},
auth=(client_id, client_secret),
verify=True,
)
logger.info("Fetching token status code", status_code=r.status_code)
r.raise_for_status()
if r.status_code == 200:
# FIXME: The token expires in 10800 seconds
return r.json()
except requests.exceptions.HTTPError as err:
logger.error("HTTP error", request=err.response.text)
raise requests.HTTPError(err)
在不对代码进行过多更改的情况下,并考虑到测试status_code
的假设,您可以让fixture返回一个可以向其中提供status_code
和raise_for_status
的函数,以便初始化MockResponse
类。但是,看看您的令牌代码,您似乎没有使用raise_for_status
。
class MockResponse:
def __init__(self, status_code, raise_for_status):
self.status_code = status_code
self.raise_for_status = raise_for_status
@staticmethod
def json() -> Dict[str, Union[str, int]]:
return {
'access_token': 'fake-access-token',
'token_type': 'fake-token-type',
'expires_in': 10800,
}
@pytest.fixture
def mock_response(monkeypatch):
"""Requests.post() mocked to return json."""
def wrapper(status_code, raise_for_status=None):
def mock_post(*args, **kwargs):
return MockResponse(status_code, raise_for_status)
monkeypatch.setattr(requests, "post", mock_post)
return wrapper
def test_some_random_status_code(mock_response) -> None:
mock_response(301)
result = get_access_token(
url="https://fakeurl",
client_id="fake-client-id",
client_secret="fake-client-secret",
grant_type="fake-grant-type",
)
assert result['access_token'] == "fake-access-token"
platform darwin -- Python 3.8.9, pytest-7.0.1, pluggy-1.0.0
rootdir: ***
plugins: asyncio-0.18.3, hypothesis-6.48.1, mock-3.7.0
asyncio: mode=strict
collected 1 item
tests/test_manager.py 2022-07-11 07:13.35 [info ] Fetching token status code status_code=301
.
========================================= 1 passed in 0.04s =========================================
您可以只检查response.ok
而不是response.status_code == 200
。如果你想检查更多的状态,那么你可以检查它是否在有效范围内。
if response.status_code in range(200, 300):
print("response status is 2xx")
if response.status_code in (200, 201):
pass