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:
parent
6109bd198a
commit
b4705c2343
|
@ -24,8 +24,6 @@ from unittest import TestCase
|
|||
from typing import List, Dict, Any, Optional, Callable, Tuple
|
||||
from types import ModuleType
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
from zulip_bots.simple_lib import (
|
||||
SimpleStorage,
|
||||
SimpleMessageServer,
|
||||
|
@ -274,115 +272,3 @@ def mock_request_exception():
|
|||
mock_get.side_effect = requests.exceptions.RequestException
|
||||
yield
|
||||
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)
|
||||
|
|
Loading…
Reference in a new issue