Search code examples
pythonunit-testingmockingpython-mock

Mocking requests/responses, mock object has no attribute 'url'


I'm new to the mocking library and so far it's been giving me trouble. I'm trying to test a Url parsing method that takes a response from an initialUrl which is then parsed in the method. I set autospec=true so I think it should have access to all methods in the requests library (including response.url) I'm trying to mock both get and response though I'm not sure if that's needed?

My getUrl method that takes a response and returns its parsed contents:

def getUrl(response):
    if response.history:
        destination = urllib.parse.urlsplit(response.url)

        baseUrlTuple = destination._replace(path="", query="")
        return urllib.parse.urldefrag(urllib.parse.urlunsplit(baseUrlTuple)).url

    raise RuntimeError("No redirect")

Test method:

def testGetUrl(self):
    initialUrl = 'http://www.initial-url.com'
    expectedUrl = 'http://www.some-new-url.com'

    mock_response = Mock(spec=requests, autospec=True)
    mock_response.status_code = 200
    mock_get = Mock(return_value=mock_response)
    #mock_get.return_value.history = True
    resp = mock_get(self.initialUrl)
    mock_response.history = True
    resultUrl = getBaseUrl(resp)
    self.assertEqual(resultUrl, expectedUrl)

When I run the test, I get

    raise AttributeError("Mock object has no attribute %r" % name)
AttributeError: Mock object has no attribute 'url'

Solution

  • First I would fix the code in your question so that it actually runs.

    You have several options, the easiest being just adding url to the list of attributes you're mocking:

    mock_response.url = <your URL>
    

    But it's also important to understand that you're trying to use the requests library as a specification for the mock, when you should be using requests.Response() if you want the url attribute to be automatically generated. You still have to assign whatever url you want to use to it though, or you'll be comparing a Mock object to an int in your function.

    Take a look at the documentation involving spec if you want to learn more: https://docs.python.org/3/library/unittest.mock-examples.html