diff --git a/tests/helpers.py b/tests/helpers.py index 161b793..d21d6c6 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -2,7 +2,7 @@ from __future__ import annotations import asyncio import unittest.mock -from typing import Any, ClassVar, Generic, TYPE_CHECKING, TypeVar +from typing import Any, Generic, TYPE_CHECKING, TypeVar from typing_extensions import ParamSpec @@ -70,7 +70,7 @@ class UnpropagatingMockMixin(Generic[T_Mock]): _mock_sealed: bool _extract_mock_name: Callable[[], str] - def _get_child_mock(self, **kwargs: object) -> T_Mock: + def _get_child_mock(self, **kwargs) -> T_Mock: """Make :attr:`.child_mock_type`` instances instead of instances of the same class. By default, this method creates a new mock instance of the same original class, and passes @@ -84,12 +84,12 @@ class UnpropagatingMockMixin(Generic[T_Mock]): obj_name = f"{mock_name}.{kwargs['name']}" if "name" in kwargs else f"{mock_name}()" raise AttributeError(f"Can't access {obj_name}, mock is sealed.") - # Propagate any other children as the `child_mock_type` instances + # Propagate any other children as simple `unittest.mock.Mock` instances # rather than `self.__class__` instances return self.child_mock_type(**kwargs) -class CustomMockMixin(UnpropagatingMockMixin[T_Mock], Generic[T_Mock]): +class CustomMockMixin(UnpropagatingMockMixin): """Provides common functionality for our custom mock types. * Stops propagation of same ``spec_set`` restricted mock in child mocks @@ -97,16 +97,9 @@ class CustomMockMixin(UnpropagatingMockMixin[T_Mock], Generic[T_Mock]): * Allows using the ``spec_set`` attribute as class attribute """ - spec_set: ClassVar[object] = None + spec_set = None - def __init__(self, **kwargs: object): - # If `spec_set` is explicitly passed, have it take precedence over the class attribute. - # - # Although this is an edge case, and there usually shouldn't be a need for this. - # This is mostly for the sake of completeness, and to allow for more flexibility. + def __init__(self, **kwargs): if "spec_set" in kwargs: - spec_set = kwargs.pop("spec_set") - else: - spec_set = self.spec_set - - super().__init__(spec_set=spec_set, **kwargs) # pyright: ignore[reportCallIssue] # Mixin class, this __init__ is valid + self.spec_set = kwargs.pop("spec_set") + super().__init__(spec_set=self.spec_set, **kwargs) # type: ignore # Mixin class, this __init__ is valid diff --git a/tests/test_helpers.py b/tests/test_helpers.py deleted file mode 100644 index 194cf22..0000000 --- a/tests/test_helpers.py +++ /dev/null @@ -1,58 +0,0 @@ -from unittest.mock import MagicMock, Mock - -from tests.helpers import CustomMockMixin, UnpropagatingMockMixin, synchronize - - -def test_synchronize(): - """Test the :func:`synchronize` helper function.""" - - async def test_func(x: int) -> int: - if x == 5: - return 10 - return 0 - - assert synchronize(test_func)(5) == 10 - assert synchronize(test_func)(6) == 0 - - -def test_unpropagating_mock_mixin(): - """Test the :class:`UnpropagatingMockMixin` helper class. - - Mocks that inherit from this mixin should not propagate themselves when new attributes are accessed. - Instead, a general mock (of the generic type) should be returned. By default, this is a :class:`MagicMock`. - """ - - class MyUnpropagatingMock(UnpropagatingMockMixin[MagicMock], Mock): ... - - x = MyUnpropagatingMock(spec_set=str) - - # Test that the `spec_set` works as expected - assert hasattr(x, "removesuffix") - assert not hasattr(x, "notastringmethod") - - unpropagated_mock = x.removesuffix() - - # Test that the resulting mock behaves without spec_set - assert hasattr(unpropagated_mock, "removesuffix") - assert hasattr(unpropagated_mock, "notastringmethod") - - -def test_custom_mock_mixin(): - """Test the :class:`CustomMockMixin` helper class. - - This class is very similar to :class:`UnpropagatingMockMixin`, with the only difference being that it - supports setting ``spec_set`` as a class variable. - """ - - class MyCustomMock(CustomMockMixin[MagicMock], Mock): # pyright: ignore[reportUnsafeMultipleInheritance] - spec_set = str - - # Test that the mock really has the `spec_set` of `str` by default - x = MyCustomMock() - assert hasattr(x, "removesuffix") - assert not hasattr(x, "notastringmethod") - - # Explicitly setting `spec_set` on __init__ should take precedence - y = MyCustomMock(spec_set=int) - assert not hasattr(y, "removesuffix") - assert hasattr(y, "to_bytes")