Mocker.copy fails to copy the adapter

Bug #1639352 reported by brosner
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
requests-mock
Confirmed
Low
Unassigned

Bug Description

I am trying to use django-rest-framework's RequestsClient with requests_mock. This has taken me down quite the rat hole. After reading a ton of the requests_mock code, I've concluded that the best way for me to do this is to essentially exclude the requests being made to http://testserver.

To do this, I create my own mocker instance before decorating my classes:

mocker = requests_mocker.Mocker()
mocker.register_uri(requests_mock.ANY, re.compile(r"^https?://testserver/"), real_http=True)

@mocker
class MyAPITestCase(APITestCase):

    client_class = RequestsClient

    ...

However, this does not work. After digging around, I discovered this is due to Mocker.decorate_class making a copy of itself, but failing to include the adaptor on the copy.

A quick fix for my code is to override `copy`:

class Mocker(requests_mock.Mocker):

    def copy(self):
        m = Mocker(
            kw=self._kw,
            real_http=self._real_http
        )
        m._adapter = self._adapter
        return m

Everything works as expected. I'd love to submit a patch, but I don't have a ton of time to work through all the contribution guidelines for the OpenStack project.

brosner (brosner)
description: updated
Revision history for this message
Jamie Lennox (jamielennox) wrote :

Yea, whilst it made sense at the time i'm regretting putting it under the openstack banner. For what it's worth it uses the gerrit and testing systems, but doesn't fall under any of the contributor agreements or anything.

So I'm happy to fix the case, the concern i have though is that the logic for things like call_count exist on the adapter so I think you would end up not resetting this information per test. I think it would also mean that responses registered in individual tests would be assigned to the global object and available across tests.

This might be something in general that needs to be fixed in using the mocker for a class. Can you check with your solution if call count etc is maintained across tests? If not I will but I won't have much time over the next week or so. What we might be able to do there is do m._adapter = self._adapter.copy() and implement copy on the adapter and all the subsequent matchers.

The pattern I have found myself liking most is http://requests-mock.readthedocs.io/en/latest/fixture.html which creates a new mock for every test, but is defined once per class. This requires some form of testtools base class though, and i don't know what django-rest-framework does there. In general though there is probably something similar you can do to create the mock per-test in one place. I can have a look there at providing some better integration with django-rest-framework, but if you have any ideas/existing test code i'd love to see it.

Changed in requests-mock:
status: New → Confirmed
importance: Undecided → Low
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.