如何模拟使多个 POST 和 GET 请求都需要不同响应数据的方法?
How do I Mock a method that makes multiple POST and GET request all requiring different response data?
我查看了 How to mock REST API 并阅读了答案,但我似乎仍然无法理解如何处理执行多个 GET 和 [=56= 的方法] 要求。下面是我的一些代码。
我有一个class,UserAliasGroups()
。它的 __init__()
方法执行 requests.post()
以登录到外部 REST API。我在我的单元测试中对这段代码进行了处理,以处理登录模拟,它按预期工作。
@mock.patch('aliases.user_alias_groups.requests.get')
@mock.patch('aliases.user_alias_groups.requests.post')
def test_user_alias_groups_class(self, mock_post, mock_get):
init_response = {
'HID-SessionData': 'token==',
'errmsg': '',
'success': True
}
mock_response = Mock()
mock_response.json.return_value = init_response
mock_response.status_code = status.HTTP_201_CREATED
mock_post.return_value = mock_response
uag = UserAliasGroups(auth_user='TEST_USER.gen',
auth_pass='FakePass',
groups_api_url='https://example.com')
self.assertEqual(uag.headers, {'HID-SessionData': 'token=='})
我还定义了几个方法,如 obtain_request_id()
、has_group_been_deleted()
、does_group_already_exists()
等。我还定义了一个名为 create_user_alias_group()
的方法,它调用 obtain_request_id()
、has_group_been_deleted()
、does_group_already_exists()
和其他方法。
我的单元测试中也有代码模拟对 REST 的 GET 请求 API 来测试我的 has_group_been_deleted()
方法,如下所示:
has_group_been_deleted_response = {
'error_code': 404,
'error_message': 'A group with this ID does not exist'
}
mock_response = Mock()
mock_response.json.return_value = has_group_been_deleted_response
mock_response.status_code = status.HTTP_404_NOT_FOUND
mock_get.return_value = mock_response
现在我可以回答我的问题了。以下是我的代码的相关部分。
class UserAliasGroups:
def __init__(
self,
auth_user=settings.GENERIC_USER,
auth_pass=settings.GENERIC_PASS,
groups_api_url=settings.GROUPS_API_URL
):
""" __init__() does the login to groups. """
self.auth_user = auth_user
self.auth_pass = auth_pass
self.headers = None
self.groups_api_url = groups_api_url
# Initializes a session with the REST API service. Each login session times out after 5 minutes of inactivity.
self.login_url = f'{self.groups_api_url}/api/login'
response = requests.post(self.login_url, json={}, headers={'Content-type': 'application/json'},
auth=(auth_user, auth_pass))
if response.status_code is not 201:
try:
json = response.json()
except:
json = "Could not decode json."
raise self.UserAliasGroupsException(f"Error: User {self.auth_user}, failed to login into "
f"{self.login_url} {json}")
response_json = response.json()
self.headers = {'HID-SessionData': response_json['HID-SessionData']}
def obtain_request_id(self, request_reason):
payload = {'request_reason': request_reason}
url = f'{self.groups_api_url}/api/v1/session/requests'
response = requests.post(url=url, json=payload, headers=self.headers)
if response.status_code is not status.HTTP_200_OK:
try:
json = response.json()
except:
json = "Could not decode json."
msg = f'obtain_request_id() Error url={url} {response.status_code} {json}.'
raise self.UserAliasGroupsException(msg)
request_id = response.json().get('request_id')
return request_id
def has_group_been_deleted(self, group_name):
url = f'{self.groups_api_url}/api/v1/groups/{group_name}/attributes/RESATTR_GROUP_DELETED_ON'
response = requests.get(url=url, headers=self.headers)
return response.status_code == status.HTTP_200_OK
def does_group_already_exists(self, group_name):
url = f'{self.groups_api_url}/api/v1/groups/{group_name}'
response = requests.get(url=url, headers=self.headers)
if response.status_code is status.HTTP_200_OK:
# check if the group has been "deleted".
return not self.has_group_been_deleted(group_name=group_name)
return False
def create_user_alias_group(
self,
... long list of params omitted for brevity ...
):
if check_exists:
# Check if group already exists or not.
if self.does_group_already_exists(group_name):
msg = f'Cannot create group {group_name}. Group already exists.'
raise self.UserAliasGroupsException(msg)
... more code omitted for brevity ...
我的问题是如何编写单元测试来处理对 requests.post()
和 request.get()
的多次调用,所有这些调用都会导致我的 create_user_alias_group()
方法中出现不同的响应?
我想在我的单元测试中调用 create_user_alias_group()
,所以我必须弄清楚如何模拟多个 requests.get()
和 requests.post()
调用。
我有没有像这样使用多个装饰器:
@mock.patch('aliases.user_alias_groups.obtain_request_id.requests.post')
@mock.patch('aliases.user_alias_groups.does_group_already_exists.requests.get')
@mock.patch('aliases.user_alias_groups.has_group_been_deleted.requests.get')
def test_user_alias_groups_class(self, mock_post, mock_get):
...
?
感谢您查看我的长问题:)
您可以使用 mock.side_effect
,它接受一个可迭代对象。那么不同的调用将return不同的值:
mock = Mock()
mock.side_effect = ['a', 'b', 'c']
这样第一次调用 mock returns "a"
,然后是下一个 "b"
等等。 (在您的情况下,您将设置 mock_get.side_effect
)。
我查看了 How to mock REST API 并阅读了答案,但我似乎仍然无法理解如何处理执行多个 GET 和 [=56= 的方法] 要求。下面是我的一些代码。
我有一个class,UserAliasGroups()
。它的 __init__()
方法执行 requests.post()
以登录到外部 REST API。我在我的单元测试中对这段代码进行了处理,以处理登录模拟,它按预期工作。
@mock.patch('aliases.user_alias_groups.requests.get')
@mock.patch('aliases.user_alias_groups.requests.post')
def test_user_alias_groups_class(self, mock_post, mock_get):
init_response = {
'HID-SessionData': 'token==',
'errmsg': '',
'success': True
}
mock_response = Mock()
mock_response.json.return_value = init_response
mock_response.status_code = status.HTTP_201_CREATED
mock_post.return_value = mock_response
uag = UserAliasGroups(auth_user='TEST_USER.gen',
auth_pass='FakePass',
groups_api_url='https://example.com')
self.assertEqual(uag.headers, {'HID-SessionData': 'token=='})
我还定义了几个方法,如 obtain_request_id()
、has_group_been_deleted()
、does_group_already_exists()
等。我还定义了一个名为 create_user_alias_group()
的方法,它调用 obtain_request_id()
、has_group_been_deleted()
、does_group_already_exists()
和其他方法。
我的单元测试中也有代码模拟对 REST 的 GET 请求 API 来测试我的 has_group_been_deleted()
方法,如下所示:
has_group_been_deleted_response = {
'error_code': 404,
'error_message': 'A group with this ID does not exist'
}
mock_response = Mock()
mock_response.json.return_value = has_group_been_deleted_response
mock_response.status_code = status.HTTP_404_NOT_FOUND
mock_get.return_value = mock_response
现在我可以回答我的问题了。以下是我的代码的相关部分。
class UserAliasGroups:
def __init__(
self,
auth_user=settings.GENERIC_USER,
auth_pass=settings.GENERIC_PASS,
groups_api_url=settings.GROUPS_API_URL
):
""" __init__() does the login to groups. """
self.auth_user = auth_user
self.auth_pass = auth_pass
self.headers = None
self.groups_api_url = groups_api_url
# Initializes a session with the REST API service. Each login session times out after 5 minutes of inactivity.
self.login_url = f'{self.groups_api_url}/api/login'
response = requests.post(self.login_url, json={}, headers={'Content-type': 'application/json'},
auth=(auth_user, auth_pass))
if response.status_code is not 201:
try:
json = response.json()
except:
json = "Could not decode json."
raise self.UserAliasGroupsException(f"Error: User {self.auth_user}, failed to login into "
f"{self.login_url} {json}")
response_json = response.json()
self.headers = {'HID-SessionData': response_json['HID-SessionData']}
def obtain_request_id(self, request_reason):
payload = {'request_reason': request_reason}
url = f'{self.groups_api_url}/api/v1/session/requests'
response = requests.post(url=url, json=payload, headers=self.headers)
if response.status_code is not status.HTTP_200_OK:
try:
json = response.json()
except:
json = "Could not decode json."
msg = f'obtain_request_id() Error url={url} {response.status_code} {json}.'
raise self.UserAliasGroupsException(msg)
request_id = response.json().get('request_id')
return request_id
def has_group_been_deleted(self, group_name):
url = f'{self.groups_api_url}/api/v1/groups/{group_name}/attributes/RESATTR_GROUP_DELETED_ON'
response = requests.get(url=url, headers=self.headers)
return response.status_code == status.HTTP_200_OK
def does_group_already_exists(self, group_name):
url = f'{self.groups_api_url}/api/v1/groups/{group_name}'
response = requests.get(url=url, headers=self.headers)
if response.status_code is status.HTTP_200_OK:
# check if the group has been "deleted".
return not self.has_group_been_deleted(group_name=group_name)
return False
def create_user_alias_group(
self,
... long list of params omitted for brevity ...
):
if check_exists:
# Check if group already exists or not.
if self.does_group_already_exists(group_name):
msg = f'Cannot create group {group_name}. Group already exists.'
raise self.UserAliasGroupsException(msg)
... more code omitted for brevity ...
我的问题是如何编写单元测试来处理对 requests.post()
和 request.get()
的多次调用,所有这些调用都会导致我的 create_user_alias_group()
方法中出现不同的响应?
我想在我的单元测试中调用 create_user_alias_group()
,所以我必须弄清楚如何模拟多个 requests.get()
和 requests.post()
调用。
我有没有像这样使用多个装饰器:
@mock.patch('aliases.user_alias_groups.obtain_request_id.requests.post')
@mock.patch('aliases.user_alias_groups.does_group_already_exists.requests.get')
@mock.patch('aliases.user_alias_groups.has_group_been_deleted.requests.get')
def test_user_alias_groups_class(self, mock_post, mock_get):
...
?
感谢您查看我的长问题:)
您可以使用 mock.side_effect
,它接受一个可迭代对象。那么不同的调用将return不同的值:
mock = Mock()
mock.side_effect = ['a', 'b', 'c']
这样第一次调用 mock returns "a"
,然后是下一个 "b"
等等。 (在您的情况下,您将设置 mock_get.side_effect
)。