-
Notifications
You must be signed in to change notification settings - Fork 41
Open
Description
I have a series of Mock classes for my testing module, based on this:
https://github.com/python-discord/bot/blob/master/tests/helpers.py
But I'm using asynctest because I'm using Python 3.6
Base classes:
class CustomMockMixin:
discord_id = itertools.count(0)
spec_set = None
def __init__(self, *args, **kwargs):
name = kwargs.pop('name', None) # `name` has special meaning for Mock classes, so we need to set it manually.
super().__init__(*args, spec_set=self.spec_set, **kwargs)
if name:
self.name = name
def _get_child_mock(self, *args, **kwargs):
"""This method by default returns an instance of the same class for any attribute or method of the class.
This would cause MockBot, for instance, to return another instance of MockBot when using ``bot.get_guild``.
This overwrites the original logic to return MagicMock objects by default, and CoroutineMocks for names defined
in ``_spec_coroutines``"""
_new_name = kwargs.get("_new_name")
if _new_name in self.__dict__['_spec_coroutines']:
return asynctest.CoroutineMock(*args, **kwargs)
_type = type(self)
if issubclass(_type, asynctest.MagicMock) and _new_name in asynctest.mock.async_magic_coroutines:
klass = asynctest.CoroutineMock
elif issubclass(_type, asynctest.CoroutineMock):
klass = asynctest.MagicMock
elif not issubclass(_type, unittest.mock.CallableMixin):
# noinspection PyTypeHints
if issubclass(_type, unittest.mock.NonCallableMagicMock):
klass = asynctest.MagicMock
elif issubclass(_type, asynctest.NonCallableMock):
klass = asynctest.Mock
else:
klass = asynctest.MagicMock
# noinspection PyUnboundLocalVariable
return klass(*args, **kwargs)
class HashableMixin(discord.mixins.EqualityComparable):
"""
Mixin that provides similar hashing and equality functionality as discord.py's `Hashable` mixin.
Note: discord.py`s `Hashable` mixin bit-shifts `self.id` (`>> 22`); to prevent hash-collisions
for the relative small `id` integers we generally use in tests, this bit-shift is omitted.
"""
def __hash__(self):
return self.idAnd this is the specific class I'm struggling with:
class MockRole(CustomMockMixin, asynctest.MagicMock, ColourMixin, HashableMixin):
spec_set = discord.Role
def __init__(self, *args, **kwargs):
default_kwargs = {
'id': next(self.discord_id),
'name': 'role',
'position': 1,
'colour': discord.Colour(0xdeadbf),
'permissions': discord.Permissions(),
}
super().__init__(*args, **collections.ChainMap(kwargs, default_kwargs))
if 'mention' not in kwargs:
self.mention = f'&{self.name}'
def __str__(self):
return f"<{self.mention}>"Needless to say, I'm over 100 test cases in with this, and I had already noticed that __str__ was not working as expected, but now I noticed that __hash__ isn't, and this affects my tests' equality checks.
If I call the methods explicitly stating the class, they work (even calling the parent's classes methods)
>>> role = MockRole(name="Premium", id=3)
>>> str(role )
'<MockRole spec_set=\'Role\' id=\'2508777936776\'>'
>>> MockRole.__str__(role )
'<&Premium>'
>>> hash(role )
-9223371880056154760
>>> MockRole.__hash__(role )
5I'm not sure if this is part of my implementation or part of the library.
Metadata
Metadata
Assignees
Labels
No labels