I have a test script I am using to validate whether or not my requests to the Slack API (using the Slack SDK for python) are valid or not. If the test fails, the output should be the specific reason for failure, which is automatically returned as a response by the Slack Webclient. To see if my script works, I intentionally used an incorrect API token and the test did indeed fail which is good, but I received the generic response that the request failed, and not the custom message containing the reason for failure.
Here is how my code looks:
import sys
import time
import pytest
from slack_sdk import WebClient, errors
import ssl
slack_token = 'xoxb-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
channel_id = "C00000000"
ssl_context = ssl.create_default_context()
ssl_context.check_hostname = False
ssl_context.verify_mode = ssl.CERT_NONE
client = WebClient(token=slack_token, ssl=ssl_context)
def test_api_call(status=True):
"""
Test which checks whether or not the API
call to conversations_history returns and 'ok'
status. If it fails, the error message will be
returned.
"""
result = client.conversations_history(
channel = channel_id,
inclusive = True,
oldest = str(time.time()-3600),
latest = str(time.time()),
limit = 100
)
assert result["ok"] == status,
f"Expected {status}. Actual status {result['ok']}. Response text {result['error']}"
Here is how the error message is returned by pytest:
test_alerts.py:25:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../.local/share/virtualenvs/new_project-RFzzfWjC/lib/python3.10/site-packages/slack_sdk/web/client.py:2488: in conversations_history
return self.api_call("conversations.history", http_verb="GET", params=kwargs)
../../.local/share/virtualenvs/new_project-RFzzfWjC/lib/python3.10/site-packages/slack_sdk/web/base_client.py:156: in api_call
return self._sync_send(api_url=api_url, req_args=req_args)
../../.local/share/virtualenvs/new_project-RFzzfWjC/lib/python3.10/site-packages/slack_sdk/web/base_client.py:187: in _sync_send
return self._urllib_api_call(
../../.local/share/virtualenvs/new_project-RFzzfWjC/lib/python3.10/site-packages/slack_sdk/web/base_client.py:317: in _urllib_api_call
).validate()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <slack_sdk.web.slack_response.SlackResponse object at 0x101a8d1b0>
def validate(self):
"""Check if the response from Slack was successful.
Returns:
(SlackResponse)
This method returns it's own object. e.g. 'self'
Raises:
SlackApiError: The request to the Slack API failed.
"""
if self.status_code == 200 and self.data and (isinstance(self.data, bytes) or self.data.get("ok", False)):
return self
msg = f"The request to the Slack API failed. (url: {self.api_url})"
> raise e.SlackApiError(message=msg, response=self)
E slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://www.slack.com/api/conversations.history)
E The server responded with: {'ok': False, 'error': 'invalid_auth'}
../../.local/share/virtualenvs/new_project-RFzzfWjC/lib/python3.10/site-packages/slack_sdk/web/slack_response.py:199: SlackApiError
====================================================================== short test summary info ======================================================================
FAILED test_alerts.py::test_api_call - slack_sdk.errors.SlackApiError: The request to the Slack API failed. (url: https://www.slack.com/api/conversations.history)
========================================================================= 1 failed in 1.04s =========================================================================
And the output I want to have when the test fails:
FAILED test_alerts.py::test_api_call - slack_sdk.errors.SlackApiError: Expected True. Actual status False. Response text invalid_auth
========================================================================= 1 failed in 1.04s =========================================================================
And this is how the Slack API documentation shows the response should look when an incorrect API token is provided:
{
'ok': False,
'error': 'invalid_auth'
}
What can I change in my python script in order to output the desired error message rather than the generic one that is being returned because the API request fails?
Please let me know if I need to clarify anything.
The reason why you’re not seeing your error message is because your code never reaches the assert result['ok']...
line.
The Slack SDK that you’re using on the line starting with result = client.conversation_history(
raises a SlackApiError instead of returning the raw query, so you don’t get to interrogate the raw query yourself.
If all you are concerned with is the formatting of the error message, you could catch the error in your test and print out the SDK error message instead, like so (untested)
try:
result = client.conversations_history(
channel = channel_id,
inclusive = True,
oldest = str(time.time()-3600),
latest = str(time.time()),
limit = 100
)
except SlackApiError as e:
raise AssertionError(e.message)
assert result["ok"] == status,
f"Expected {status}. Actual status {result['ok']}. Response text {result['error']}"
However, this is a good pointer that you are trying to test something that in my opinion doesn’t need to be tested. The Slack SDK developers are responsible for testing that when the API token is invalid, they return a SlackApiError. You are using the SDK and so don’t need to be concerned with this.
What you need to be concerned with is how does your code react to receiving a SlackApiError – does it correctly notify the user, end the program, do something else?
The benefit of testing this way is that in an ideal scenario you don’t need to actually need make real a Slack request to test that your code works (which wastes resources and is inconsiderate to Slack servers). In my mind, it’s a good alarm bell that I could structure my code better if I’m in a situation when I’m tempted to send a real request in my tests.
2