Skip to content

Commit

Permalink
Finish writing tests (#47)
Browse files Browse the repository at this point in the history
* Attempt to automatically upload code coverage to Code Cov IO

* Dictating which shell to us so we can run new command to upload coverage to code cov

* Testing Peek returning the first element and the iterator

* Testing None is returned if StopIteration is raised when calling next in peek

* attempted to test init to prove debugging worked, skipping for now as dependency injection is failing.

* Testing helper_get_public_channel_ids returns channel ids when received

* Testing helper_get_public_channel_ids returns empty list channel ids when received none

* Testing helper_get_private_channel_ids both with data and when none is found

* Wrote tests for helper_get_user_names to ensure works when returning list of data or empty list when none is found

* Tested helper_get_users_in_channel but also modified old tests to help pass again with the new channels_list modification needed for this test

* no users now in this test for coverage

* testing helper_user_name_to_user_id both with a response mapping username to userid and failure to do so

* tested helper_user_name_to_user_id both when data is returned and when no match is found

* added badge for mater branch to readme

* Wrote tests for helper_user_id_to_user_name which should be the majority of the simple_slack_bot_class

* Wrote first test for SlackRequest to prove initializer stores its arguments

* Wrote tests for type property both when data is found and when it isn't

* Factored out common property code in SlackRequest

* refactored tests to match refactoring of the get method that all the properties use

* Finished all property tests for SlackReqest

* Moved common mock into its own package for multiple test files to use

* testing SlackRequest write when exception is thrown

* test SlackRequest str

* generating coverage for all files now instead of just simple_slack_bot, added vebose and colors

* Circle ci failed to upload coverage to code cov. Removing verbose and colors to see if this helps

* Added tests for helper_channel_name_to_channel_id
  • Loading branch information
GregHilston authored Aug 24, 2020
1 parent 895f786 commit a642f6b
Show file tree
Hide file tree
Showing 11 changed files with 730 additions and 55 deletions.
11 changes: 8 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
key: deps9-{{ .Branch }}-{{ checksum "requirements_dev.txt" }}

- run:
name: install dependencies
name: Install dependencies
command: |
pip install -r requirements_dev.txt
Expand All @@ -23,6 +23,11 @@ jobs:
- "venv"

- run:
name: test
name: Run tests and generate coverage
command: |
make magic
make test-and-generate-coverage
- run:
name: Upload test coverage to Code Cov
command : |
make upload-coverage-to-codecov
7 changes: 5 additions & 2 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
[run]
include =
# The only file we're interested in generating code coverage for
simple_slack_bot/simple_slack_bot.py
simple_slack_bot/*

[report]
fail_under = 90
show_missing = True
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
PYTHON=python3
.DEFAULT_GOAL := help
SHELL := /bin/bash

.PHONY: help
help: ## This help.
Expand Down Expand Up @@ -28,12 +29,15 @@ security: ## Checks code base and tests for security vulnerability, bad imports

magic: format isort lint type security ## Performs format, isort, lint, type and security in that order.

test: ## Runs the pytest suite.
test: ## Runs the pytest suite
pytest

coverage: ## Runs the pytest suite and generates code coverage.
test-and-generate-coverage: ## Runs the pytest suite and generates code coverage.
coverage run -m pytest && coverage report -m

upload-coverage-to-codecov: ## Uploads the covde coverage to Code Cov IO
bash <(curl -s https://codecov.io/bash)

package: ## Packages up the project.
python3 setup.py sdist bdist_wheel

Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

[![<ORG_NAME>](https://circleci.com/gh/GregHilston/Simple-Slack-Bot.svg?style=svg)](https://app.circleci.com/pipelines/github/GregHilston/Simple-Slack-Bot)

[![codecov](https://codecov.io/gh/GregHilston/Simple-Slack-Bot/branch/master/graph/badge.svg)](https://codecov.io/gh/GregHilston/Simple-Slack-Bot)


Simple Slack Bot makes writing your next Slack bot incredibly easy. By factoring out common functionality all Slack Bots require, you can focus on writing your business logic.


Expand Down
4 changes: 4 additions & 0 deletions pytest.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[pytest]
testpaths = tests
python_files = *.py
python_functions = test_*
31 changes: 9 additions & 22 deletions simple_slack_bot/simple_slack_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,10 +258,8 @@ def helper_get_private_channel_ids(self) -> typing.List[str]:

private_channel_ids: typing.List[str] = []

private_channels = self._python_slackclient.groups_list()["groups"]

for private_channel in private_channels:
private_channels.append(private_channel["id"])
for private_channel in self._python_slackclient.groups_list()["groups"]:
private_channel_ids.append(private_channel["id"])

if len(private_channel_ids) == 0:
logger.warning("got no private channel ids")
Expand All @@ -278,8 +276,7 @@ def helper_get_user_ids(self) -> typing.List[str]:

user_ids = []

users = self._python_slackclient.users_list()["members"]
for user in users:
for user in self._python_slackclient.users_list()["members"]:
user_ids.append(user["id"])

if len(user_ids) == 0:
Expand All @@ -297,8 +294,7 @@ def helper_get_user_names(self) -> typing.List[str]:

user_names = []

users = self._python_slackclient.users_list()["members"]
for user in users:
for user in self._python_slackclient.users_list()["members"]:
user_names.append(user["name"])

if len(user_names) == 0:
Expand All @@ -317,8 +313,7 @@ def helper_get_users_in_channel(self, channel_id: str) -> typing.List[str]:

user_ids = []

channels_list = self._python_slackclient.channels_list()["channels"]
for channel in channels_list:
for channel in self._python_slackclient.channels_list()["channels"]:
if channel["id"] == channel_id:
for user_id in channel["members"]:
user_ids.append(user_id)
Expand All @@ -337,9 +332,7 @@ def helper_channel_name_to_channel_id(self, name: str) -> typing.Union[str, None
:return: id representation of original channel name
"""

channels_list = self._python_slackclient.channels_list()["channels"]

for channel in channels_list:
for channel in self._python_slackclient.channels_list()["channels"]:
if channel["name"] == name:
logger.debug("converted %s to %s", channel["name"], channel["id"])
return channel["id"]
Expand All @@ -354,9 +347,7 @@ def helper_user_name_to_user_id(self, name: str) -> typing.Union[str, None]:
:return: id representation of original user name
"""

users = self._python_slackclient.users_list()["members"]

for user in users:
for user in self._python_slackclient.users_list()["members"]:
if user["name"] == name:
logger.debug("converted %s to %s", name, user["id"])
return user["id"]
Expand All @@ -371,9 +362,7 @@ def helper_channel_id_to_channel_name(self, channel_id: str) -> typing.Union[str
:return: name representation of original channel id
"""

channels_list = self._python_slackclient.channels_list()["channels"]

for channel in channels_list:
for channel in self._python_slackclient.channels_list()["channels"]:
if channel["id"] == channel_id:
logger.debug("converted %s to %s", channel_id, channel["name"])
return channel["name"]
Expand All @@ -388,9 +377,7 @@ def helper_user_id_to_user_name(self, user_id: str) -> typing.Union[str, None]:
:return: name representation of original user id
"""

users_list = self._python_slackclient.users_list()

for user in users_list["members"]:
for user in self._python_slackclient.users_list()["members"]:
if user["id"] == user_id:
logger.debug("converted %s to %s", user_id, user["name"])
return user["name"]
Expand Down
32 changes: 16 additions & 16 deletions simple_slack_bot/slack_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,27 @@ def __init__(self, python_slackclient: WebClient, slack_event: SlackEvent):
self._python_slackclient = python_slackclient
self.slack_event = slack_event

def get(self, key: str, default_value: typing.Any = None) -> typing.Any:
"""Get value for given key if found otherwise return default value.
:param key: The key we're looking for
:param default_value: What to return if we can't find a value for this key
:return: The found value or default value if not found
"""
if key in self.slack_event:
return self.slack_event[key]

logger.warning("could not find %s for slack_event", key)
return default_value

@property
def type(self) -> typing.Union[str, None]:
"""Get the type of event from the underlying SlackEvent.
:return: the type of event, if there is one
"""

if "type" in self.slack_event:
return self.slack_event["type"]

logger.warning("could not find type for slack_event")
return None
return self.get("type")

@property
def subtype(self) -> typing.Union[str, None]:
Expand All @@ -50,11 +59,7 @@ def subtype(self) -> typing.Union[str, None]:
:return: the subtype of event, if there is one
"""

if "subtype" in self.slack_event:
return self.slack_event["subtype"]

logger.warning("could not find subtype for slack_event")
return None
return self.get("subtype")

@property
def channel(self) -> typing.Union[str, None]:
Expand All @@ -65,12 +70,7 @@ def channel(self) -> typing.Union[str, None]:
:return: the channel this SlackEvent originated from, if there is one
"""

channel = ""

if "channel" in self.slack_event:
channel = self.slack_event["channel"]

return channel
return self.get("channel")

@property
def thread_ts(self) -> str:
Expand Down
Empty file added tests/common/__init__.py
Empty file.
52 changes: 52 additions & 0 deletions tests/common/mocks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
class MockPythonSlackclient:
def __init__(
self,
injectable_bool=None,
injectable_public_channels=[],
injectable_private_channels=[],
injectable_user_ids=[],
injectable_user_names=[],
injectable_channel_names=[],
injectable_chat_postMessage_exception=None,
):
self.injectable_bool = injectable_bool
self.injectable_channel_names = injectable_channel_names
self.injectable_public_channels = injectable_public_channels
self.injectable_private_channels = injectable_private_channels
self.injectable_user_ids = injectable_user_ids
self.injectable_user_names = injectable_user_names
self.injectable_chat_postMessage_exception = injectable_chat_postMessage_exception

def rtm_start(self):
return self.injectable_bool

def channels_list(self):
return {
"channels": [
{"id": channel_id, "name": channel_name, "members": self.injectable_user_names}
for channel_id, channel_name, member in zip(
self.injectable_public_channels,
self.injectable_channel_names,
self.injectable_user_names,
)
]
}

def groups_list(self):
return {"groups": [{"id": value} for value in self.injectable_private_channels]}

def users_list(self):
return {
"members": [
{"id": id, "name": name}
for id, name in zip(self.injectable_user_ids, self.injectable_user_names)
]
}

def chat_postMessage(self, channel, text):
self.was_chat_postMessage_called = True
self.channel = channel
self.text = text

if self.injectable_chat_postMessage_exception:
raise self.injectable_chat_postMessage_exception
Loading

0 comments on commit a642f6b

Please sign in to comment.