mirror of
https://github.com/zulip/zulip.git
synced 2025-11-14 10:57:58 +00:00
test_example.py: Add new example with mock.patch.
The original mocking example now uses time_machine, so I slimmed down a lot of its comments, and then I created another mocking example so that we still touch on mocking in terms of mock.patch. The new method reinforces the pattern of testing both the sad path and happy path inside the same test.
This commit is contained in:
@@ -5,14 +5,15 @@ import orjson
|
||||
import time_machine
|
||||
from django.utils.timezone import now as timezone_now
|
||||
|
||||
from zerver.actions.realm_settings import do_set_realm_property
|
||||
from zerver.actions.users import do_change_can_create_users, do_change_user_role
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.exceptions import JsonableError, StreamWildcardMentionNotAllowedError
|
||||
from zerver.lib.streams import access_stream_for_send_message
|
||||
from zerver.lib.test_classes import ZulipTestCase
|
||||
from zerver.lib.test_helpers import most_recent_message
|
||||
from zerver.lib.users import is_administrator_role
|
||||
from zerver.models import UserProfile, UserStatus
|
||||
from zerver.models.realms import get_realm
|
||||
from zerver.models import Realm, UserProfile, UserStatus
|
||||
from zerver.models.realms import WildcardMentionPolicyEnum, get_realm
|
||||
from zerver.models.streams import get_stream
|
||||
from zerver.models.users import get_user_by_delivery_email
|
||||
|
||||
@@ -433,13 +434,75 @@ class TestMocking(ZulipTestCase):
|
||||
#
|
||||
# Mocking is generally used in situations where
|
||||
# we want to avoid running original code for reasons
|
||||
# like skipping HTTP requests, saving execution time etc.
|
||||
# like skipping HTTP requests, saving execution time,
|
||||
# or simulating convenient return values.
|
||||
#
|
||||
# Learn more about mocking in-depth at:
|
||||
# https://zulip.readthedocs.io/en/latest/testing/testing-with-django.html#testing-with-mocks
|
||||
def test_wildcard_mentions(self) -> None:
|
||||
cordelia = self.example_user("cordelia")
|
||||
self.login_user(cordelia)
|
||||
self.subscribe(cordelia, "test_stream")
|
||||
|
||||
# Let's explicitly set the policy for sending wildcard
|
||||
# mentions to a stream. If a stream has too many
|
||||
# subscribers, we won't allow any users to spam the stream.
|
||||
do_set_realm_property(
|
||||
cordelia.realm,
|
||||
"wildcard_mention_policy",
|
||||
WildcardMentionPolicyEnum.NOBODY,
|
||||
acting_user=None,
|
||||
)
|
||||
|
||||
# We will try the same message a couple times.
|
||||
# Notice the content includes "@**all**".
|
||||
all_mention = "@**all** test wildcard mention"
|
||||
|
||||
# First, let's test the SAD PATH, where cordelia
|
||||
# tries a wildcard method and gets rejected.
|
||||
#
|
||||
# The following test demonstrates a simple use case
|
||||
# where mocking is helpful in saving test-run time.
|
||||
# Here we use both mock.patch to simulate a return value
|
||||
# and assertRaisesRegex to verify our function raises
|
||||
# an error.
|
||||
with (
|
||||
mock.patch(
|
||||
"zerver.lib.message.num_subscribers_for_stream_id",
|
||||
return_value=Realm.WILDCARD_MENTION_THRESHOLD + 1,
|
||||
),
|
||||
self.assertRaisesRegex(
|
||||
StreamWildcardMentionNotAllowedError,
|
||||
"You do not have permission to use channel wildcard mentions in this channel.",
|
||||
),
|
||||
):
|
||||
self.send_stream_message(
|
||||
sender=cordelia,
|
||||
stream_name="test_stream",
|
||||
content=all_mention,
|
||||
)
|
||||
|
||||
# Verify the message was NOT sent.
|
||||
message = most_recent_message(cordelia)
|
||||
self.assertNotEqual(message.content, all_mention)
|
||||
|
||||
# Now for the HAPPY PATH, we still mock the number of
|
||||
# subscribers, but here we simulate that we are under
|
||||
# the limit. We expect cordelia's message to go through.
|
||||
with mock.patch(
|
||||
"zerver.lib.message.num_subscribers_for_stream_id",
|
||||
return_value=Realm.WILDCARD_MENTION_THRESHOLD - 1,
|
||||
):
|
||||
self.send_stream_message(
|
||||
sender=cordelia,
|
||||
stream_name="test_stream",
|
||||
content=all_mention,
|
||||
)
|
||||
|
||||
# Verify the message WAS sent.
|
||||
message = most_recent_message(cordelia)
|
||||
self.assertEqual(message.content, all_mention)
|
||||
|
||||
|
||||
class TestTimeTravel(ZulipTestCase):
|
||||
def test_edit_message(self) -> None:
|
||||
"""
|
||||
Verify if the time limit imposed on message editing is working correctly.
|
||||
@@ -484,28 +547,15 @@ class TestMocking(ZulipTestCase):
|
||||
# Now that we tested message editing works within the limit,
|
||||
# we want to verify it doesn't work beyond the limit.
|
||||
#
|
||||
# To do that we'll have to wait for the time limit to pass which is
|
||||
# 5 minutes here. Easy, use time.sleep() but mind that it slows down the
|
||||
# test to a great extent which isn't good. This is when mocking comes to rescue.
|
||||
# We can check what the original code does to determine whether the time limit
|
||||
# exceeded and mock that here such that the code runs as if the time limit
|
||||
# exceeded without actually waiting for that long!
|
||||
#
|
||||
# In this case, it is timezone_now, an alias to django.utils.timezone.now,
|
||||
# to which the difference with message-sent-time is checked. So, we want
|
||||
# that timezone_now() call to return `datetime` object representing time
|
||||
# that is beyond the limit.
|
||||
#
|
||||
# Notice how mock.patch() is used here to do exactly the above mentioned.
|
||||
# mock.patch() here makes any calls to `timezone_now` in `zerver.actions.message_edit`
|
||||
# to return the value passed to `return_value` in the its context.
|
||||
# You can also use mock.patch() as a decorator depending on the
|
||||
# requirements. Read more at the documentation link provided above.
|
||||
|
||||
# First, calculate the time we want to travel to, adding
|
||||
# a little buffer of 100 seconds beyond the limit.
|
||||
time_beyond_edit_limit = message_sent_time + timedelta(
|
||||
seconds=MESSAGE_CONTENT_EDIT_LIMIT + 100
|
||||
) # There's a buffer time applied to the limit, hence the extra 100s.
|
||||
)
|
||||
|
||||
# Now use time_machine.travel to simulate that we are in the future.
|
||||
#
|
||||
# See https://pypi.org/project/time-machine/ for more info.
|
||||
with time_machine.travel(time_beyond_edit_limit, tick=False):
|
||||
result = self.client_patch(
|
||||
f"/json/messages/{sent_message_id}", {"content": "I actually want pizza."}
|
||||
|
||||
Reference in New Issue
Block a user