bot tests: Remove BotTestCase.

All of the functionality of BotTestCase was either directly
moved to StubBotTestCase or replaced by similar functions,
and all bots have been ported to StubBotTestCase.
This commit is contained in:
Steve Howell 2017-12-11 08:08:55 -06:00 committed by showell
parent 6109bd198a
commit b4705c2343

View file

@ -24,8 +24,6 @@ from unittest import TestCase
from typing import List, Dict, Any, Optional, Callable, Tuple from typing import List, Dict, Any, Optional, Callable, Tuple
from types import ModuleType from types import ModuleType
from copy import deepcopy
from zulip_bots.simple_lib import ( from zulip_bots.simple_lib import (
SimpleStorage, SimpleStorage,
SimpleMessageServer, SimpleMessageServer,
@ -274,115 +272,3 @@ def mock_request_exception():
mock_get.side_effect = requests.exceptions.RequestException mock_get.side_effect = requests.exceptions.RequestException
yield yield
assert_mock_called(mock_get) assert_mock_called(mock_get)
class BotTestCase(StubBotTestCase):
"""Test class for common Bot test helper methods"""
bot_name = '' # type: str
def setUp(self):
# type: () -> None
# Mocking ExternalBotHandler
self.patcher = patch('zulip_bots.lib.ExternalBotHandler', autospec=True)
self.MockClass = self.patcher.start()
self.mock_bot_handler = self.MockClass(None, None, None, None)
self.mock_client = MagicMock()
self.mock_client.get_storage.return_value = {'result': 'success', 'storage': {}}
self.mock_client.update_storage.return_value = {'result': 'success'}
self.mock_bot_handler.storage = StateHandler(self.mock_client)
self.message_handler = get_bot_message_handler(self.bot_name)
def tearDown(self):
# type: () -> None
self.patcher.stop()
def initialize_bot(self):
# type: () -> None
self.message_handler.initialize(self.mock_bot_handler)
def check_expected_responses(self, expectations, expected_method='send_reply',
email="foo_sender@zulip.com", recipient="foo", subject="foo",
sender_id=0, sender_full_name="Foo Bar", type="all"):
# type: (List[Tuple[str, Any]], str, str, str, str, int, str, str) -> None
# To test send_message, Any would be a Dict type,
# to test send_reply, Any would be a str type.
if type not in ["private", "stream", "all"]:
logging.exception("check_expected_response expects type to be 'private', 'stream' or 'all'")
private_message_template = {'type': "private", 'display_recipient': recipient,
'sender_email': email, 'sender_id': sender_id,
'sender_full_name': sender_full_name}
stream_message_template = {'type': "stream", 'display_recipient': recipient,
'subject': subject, 'sender_email': email, 'sender_id': sender_id,
'sender_full_name': sender_full_name}
message_templates = []
if type in ["private", "all"]:
message_templates.append(private_message_template)
if type in ["stream", "all"]:
message_templates.append(stream_message_template)
initial_storage = deepcopy(self.mock_bot_handler.storage)
for message_template in message_templates:
# A new copy of the StateHandler is used for every new conversation with a
# different base template. This avoids type="all" failing if the created state
# of a prior conversation influences the current one.
self.mock_bot_handler.storage = deepcopy(initial_storage)
for m, r in expectations:
# For calls with send_reply, r is a string (the content of a message),
# so we need to add it to a Dict as the value of 'content'.
# For calls with send_message, r is already a Dict.
message = dict(message_template, content = m)
response = {'content': r} if expected_method == 'send_reply' else r
self.assert_bot_responses(message, (response, expected_method))
def call_request(self, message, *responses):
# type: (Dict[str, Any], *Tuple[Dict[str, Any], str]) -> None
# Mock BotHandler; get instance
instance = self.MockClass.return_value
# Send message to the bot
try:
self.message_handler.handle_message(message, self.mock_bot_handler)
except KeyError as key_err:
raise Exception("Message tested likely required key {}.".format(key_err))
# Determine which messaging functions are expected
send_messages = [call(r[0]) for r in responses if r[1] == 'send_message']
send_replies = [call(message, r[0]['content']) for r in responses if r[1] == 'send_reply']
# Test that call were matching in quantity, and then in details
fail_template = "\nMESSAGE:\n{}\nACTUAL CALLS:\n{}\nEXPECTED:\n{}\n"
functions_to_test = (('send_message', instance.send_message, send_messages),
('send_reply', instance.send_reply, send_replies))
for version, actual, expected in functions_to_test:
assert len(expected) == actual.call_count, (
"Numbers of '{}' called do not match those expected ({} calls, {} expected)" +
fail_template).format(version, actual.call_count, len(expected),
message, actual.call_args_list, expected)
if len(expected) > 0:
try:
actual.assert_has_calls(expected)
except AssertionError:
raise AssertionError(
("Calls to '{}' do not match those expected" +
fail_template).format(version,
message, actual.call_args_list, expected))
actual.reset_mock() # Ensure the call details are reset
@contextmanager
def mock_config_info(self, config_info):
# type: (Dict[str, str]) -> Any
self.mock_bot_handler.get_config_info.return_value = config_info
yield
self.mock_bot_handler.get_config_info.return_value = None
def assert_bot_response(self, message, response, expected_method):
# type: (Dict[str, Any], Dict[str, Any], str) -> None
# Strictly speaking, this function is not needed anymore,
# kept for now for legacy reasons.
self.call_request(message, (response, expected_method))
def assert_bot_responses(self, message, *response_list):
# type: (Dict[str, Any], *Tuple[Dict[str, Any], str]) -> None
self.call_request(message, *response_list)