Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock out custom throttle class for testing in django-rest-framework?

I have a custom throttle class like: (print statements are for debugging :)) in api.throttle.py

print("befor CustomThrottle class")
class CustomThrottle(BaseThrottle):
    def __init__(self):
        super().__init__()
        print("initializing CustomThrottle", self)
        self._wait = 0

    def allow_request(self, request, view):
        print("CustomThrottle.allow_request")
        if request.method in SAFE_METHODS:
            return True
        # some checking here
        if wait > 0:
            self._wait = wait
            return False
        return True

    def wait(self):
        return self._wait

my api.views.py is like:

from api.throttle import CustomThrottle

print("views module")
class SomeView(APIView):
    print("in view")
    throttle_classes = [CustomThrottle]

    def post(self, request, should_exist):
        # some processing
        return Response({"message": "Done."})

and my tests is api/tests/test_views.py:

    @patch.object(api.views.CustomThrottle, "allow_request")
    def test_can_get_confirmation_code_for_registered_user(self, throttle):
        throttle.return_value = True
        response = self.client.post(path, data=data)
        self.assertEqual(
            response.status_code,
            status.HTTP_200_OK,
            "Should be successful",
        )

    @patch("api.views.CustomThrottle")
    def test_learn(self, throttle):
        throttle.return_value.allow_request.return_value = True
        response = self.client.post(path, data=data)
        self.assertEqual(
            response.status_code,
            status.HTTP_200_OK,
            "Should be successful",
        )


the first test passes correctly but still the CustomThrottle class is instantiated but the allow_request method is mocked; the second test shows that neither CustomThrottle class is mocked nor the allow_request method and it fails with status 429 (CustomThrottle has a throttle rate of 2 minutes).

like image 744
Masked Man Avatar asked Nov 07 '22 08:11

Masked Man


1 Answers

After spending some time and testing different scenarios (Putting debug like print statements here and there :) ) I finally found out why it's not working, But it may not be as correct as I think so any better answer is welcome.

I defined list of throttle classes like throttle_classes = [CustomThrottle] so when server starts it's imported and evaluated so there's a reference to the actual and unmocked version of CustomThrottle in my SomeView class and when processing the responses it will use that for instantiation and so my test fails, but when I patch it like patch.object(CustomThrottle, "allow_request") when view actually needs to check throttles it will call something like CustomThrottle().allow_request(...) (pay attention to parentheses for object creation); the object has not a method like allow_request in itself so it searches that in it's class and use the mocked version correctly.

like image 106
Masked Man Avatar answered Nov 12 '22 16:11

Masked Man