slackapi / python-slack-sdk

Slack Developer Kit for Python
https://slack.dev/python-slack-sdk/
MIT License
3.82k stars 838 forks source link

Writing unit tests for an app using this SDK #1188

Open devangmehta123 opened 2 years ago

devangmehta123 commented 2 years ago

I have seen mentions of unit tests in some issues like this one: https://github.com/slackapi/python-slack-sdk/issues/1052

But the documentation does not mention how we can write unit tests in our code if we integrate the slack sdk in our code base.

We use pytest along with moto3 to mock AWS APIs, for example. Is there something similar we can do for this slack sdk or do we have to make our own fixtures to make the unit tests work?

seratch commented 2 years ago

Hi @devangmehta123, thanks for writing in!

At this moment, there is no built-in support for testing your code using this SDK.

As for the unit tests verifying the behavior of this SDK itself spins up a mock HTTP server with fixture data this way: https://github.com/slackapi/python-slack-sdk/tree/v3.15.2/tests/slack_sdk/web If you are fine with this approach, please feel free to reuse the mock server implementation for your tests.

For the future, we are thinking of some better testing support for this low-level SDK and Bolt framework. The moto library is an amazing tool! I like it too. That being said, our forthcoming testing support for this SDK would be a bit simpler. Simulating the whole Slack platform is relatively complex. I cannot tell when the new module will be available yet but I myself already started early prototyping for it.

I'm sorry for providing no clear answer at this moment. I hope this helps!

devangmehta123 commented 2 years ago

Thanks @seratch , keep us all posted on the prototype.

I am actually quite happy to use your mock HTTP server for the tests. If that could be made general purpose for unit tests, that could work.

I have seen that approach used for database instances before and the only issue sometimes is the time it takes to start up and tear it down.

github-actions[bot] commented 2 years ago

👋 It looks like this issue has been open for 30 days with no activity. We'll mark this as stale for now, and wait 10 days for an update or for further comment before closing this issue out. If you think this issue needs to be prioritized, please comment to get the thread going again! Maintainers also review issues marked as stale on a regular basis and comment or adjust status if the issue needs to be reprioritized.

ryanandonian commented 1 year ago

Hey @devangmehta123 , I know this thread is over a year old, but I just wanted to chime in since I came here from Google looking for exactly the same piece of information. What I believe you were looking for was the same as me- a way to mock responses (similarly to how you can with responses or respx) but specifically for the slack_sdk API calls?

The gist of it is I had to patch (using unittest.patch) urllib.request.urlopen calls, since the Slack SDK uses that under the hood. It's a little nasty, but this works out for me and it properly leverages the rest of the slack_sdk internals (like raising SlackApiError,SlackRequestError, retries, etc)

@pytest.fixture
def mock_slack_api_token_revoked_response():
    """Mocks a Slack API request to /api/users.profile.set and returns a "Token Revoked" payload

    Slack SDK uses urllib, so this is a bit hairy
    {'ok': False, 'error': 'token_revoked'}
    """
    with patch("slack_sdk.web.base_client.urlopen") as mock_urllib_open:
        mock_io_reader = MagicMock()
        mock_io_response = MagicMock()
        mock_io_reader.read.return_value = mock_io_response
        mock_io_response.decode.return_value = json.dumps({"ok": False, "error": "token_revoked"})
        mock_urllib_open.return_value = mock_io_reader
        yield mock_urllib_open

I'm sure there's a better way to do this, but this worksâ„¢ and has been really useful for testing certain error cases in my app which call the Slack API.

gabrieljoelc commented 4 months ago

i ended up using httpretty:

httpretty.register_uri(
    httpretty.POST,
    "https://www.slack.com/api/chat.postMessage",
    body=httpretty.Response(
        body=json.dumps(
            {
                "ok": True,
                "ts": "12345.678",
            }
        )
    ),
)
iamrajjoshi commented 2 weeks ago

Howdy! Us folks at Sentry.io are currently in the process of using the the Slack SDK for our Slack Bot. As part of the change, we would like to create a better testing suite. Ideally we would hit Slack's api or return mocked/ (preferably) cached responses from Slack. Are there any suggestions on how we can make this happen?

ryanandonian commented 1 week ago

Howdy! Us folks at Sentry.io are currently in the process of using the the Slack SDK for our Slack Bot. As part of the change, we would like to create a better testing suite. Ideally we would hit Slack's api or return mocked/ (preferably) cached responses from Slack. Are there any suggestions on how we can make this happen?

@iamrajjoshi If it's for non-End-to-End testing, could the solution that I or @gabrieljoelc posted help with that? That way you don't actually send http requests to Slack itself. My post patches the low level urllib (if you're reducing dependencies), while Gabriel's uses httpretty to patch it in a much more user-friendly way.

ygalblum commented 22 hours ago

Hi, I also got here looking for a mock server. I found this: https://github.com/Skellington-Closet/slack-mock. But, IIUC this is JS specific.

I started playing around with running a mock server as a prerequisite for the test and setting the base_url of the WebClient. The repo is https://github.com/ygalblum/slack-server-mock and I have a small test to show how this can be used: https://github.com/ygalblum/slack-server-mock/blob/main/test/test_echo.py.

I'd love to get any feedback.