0

I'm struggling with Mock a little bit and am in need of some help/understanding.

I've got a Django application that has a middleware file that calls a function to add a queryset to the response (if needed).

The middleware looks like this:

class WidgetMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.
        if resolve(request.path).app_name == "my_app":
            request.full_widgets = has_full_widgets(
                request.user.id
            )
        else:
            pass
        response = self.get_response(request)
        # Code to be executed for each request/response after
        # the view is called.
        return response

I have a view that looks like this:

@login_required
@permission_required("my_app.view_thing", raise_exception=True)
def cart(request, **kwargs):
    if request.full_widgets:
        return redirect("my_app:index")
    # ... rest of view logic ...

The has_full_widgets function lives in a utility file (my_app.utils):

def has_full_widgets(user_id):
    return Widget.objects.filter(user=user_id, full=True)

I'm trying to write a test for that view in such a way that the has_full_widgets function would return a Queryset of widgets - which would trigger the redirect in the view. So I would like to mock the response of that function

I've got a test that looks like this:

class TestCartView(TestCase):
    def setUp(self):
        self.client = Client()
        self.cart_url = reverse("my_app:cart")

        # setup random user without permissions
        self.user_no_perms = Person.objects.create_user(
            username="testusernoperms", password="12345"
        )
        self.user = Person.objects.create_user(
            username="testuser", password="12345"
        )
        permission = Permission.objects.get(codename="view_thing")
        self.user.user_permissions.add(permission)

        # Login super basic user
        self.force_login(self.user)

    def test_mock_middleware_response(self):
        # Mock the has_full_widgets method on the utils module.
        with mock.patch.object(utils, "has_full_widgets", return_value=Widget.objects.all()):

            # Create a request object.
            request = mock.Mock()
            request.user = User.objects.create_user("test_user", "test@email.com", "password")

            # Call the cart view.
            cart(request)

            # Assert that the request.full_widgets attribute is the queryset that was returned by the middleware.
            assert request.full_widgets == Widget.objects.all()

            # Assert that the middleware's has_full_widgets method was called.
            utils.has_full_widgets.assert_called_once_with(request.user.id)

I am getting the following error:

AssertionError: assert <Mock name='mock.full_widgets' id='4512588288'> == <QuerySet [<Widget: 1>, <Widget: 2>, <Widget: 3>, ...

Am I going about this all wrong? My knowledge on mock is very basic at this point and I'm trying to learn - so any and all help is appreciated.

Hanny
  • 580
  • 3
  • 16
  • 44
  • In my opinion one of the problems is that by the instruction `mock.patch.object(utils, "has_full_widgets", ...)` you are *patching* the name `utils.has_full_widgets` present in the namespace of the test file, but the function `has_full_widgets` is called by the method `__call__` of the class `WidgetMiddleware` by a different name that you don't patch. – frankfalse Jul 12 '23 at 12:54
  • See [this link](https://docs.python.org/3/library/unittest.mock.html#where-to-patch) to study "Where to patch()"; [this link](https://stackoverflow.com/questions/75766274/patching-in-unit-tests-does-not-work-actual-method-is-being-called/75766618#75766618) is an example about the topic Where to patch. – frankfalse Jul 12 '23 at 13:12

0 Answers0