1

I'm writing unit tests for a requests library. For most of my libraries, I run a .content.decode('utf-8') on the response to get to the actual text. However when I'm mocking this response from the api call, how do I mock a response object which is received by the requests call? is there a requests.content.encode('utf-8',data)) look alike process which can actually mock the response coming in (in encoded format) from the API call, and then I decode that object.

sample code:

def sample_fct(self, endpoint): try: request = requests.post (endpoint, verify=False) except requests.exceptions.RequestException as e: raise return request def get_something(self,test): try: response = self.sample_fct(test) resp_text = response_bare.content.decode('utf-8') print resp_text except: raise 

So for instance, if I wanted to unit test the get_something function, I need to mock the sample_fct function. to do this, i would have to set the sample_fct.return_value to a request object that it is returning.

So how do I create that object.

5
  • 1
    Have you check the packages requests-mock? It is very useful when mocking requests calls. Commented Nov 14, 2018 at 21:50
  • Can we see an example of your current mocking? I can write up a better example of how it should look if I have a starting point. Essentially you'd just assign the response (or a portion of a mocked response) to an already encoded value. You can either do that with raw bytes like this: b'\xE2\x98\xBA' or by starting with the encoded string and call encode like this: '☺'.encode('utf-8') Commented Nov 15, 2018 at 12:07
  • What should requests.content.encode('utf-8',data)) do? Commented Nov 15, 2018 at 14:21
  • @wholevinski added a sample Commented Nov 15, 2018 at 21:03
  • 2
    You can assign arbitrary attributes to a Mock, so it'd be something like: mock_fct_return = mock.Mock(content=b'some content you want to decode') Commented Nov 15, 2018 at 21:52

1 Answer 1

1

Here's how you can mock the response like I was saying above. Note that I took some liberties to make your code and my test actually work. They are included in comments:

"""request_module.py""" import requests class SomeClass(object): """I put these in a class, since you had self as your first arg""" def sample_fct(self, endpoint): try: request = requests.post (endpoint, verify=False) except requests.exceptions.RequestException as e: raise return request def get_something(self, test): try: response = self.sample_fct(test) resp_text = response.content.decode('utf-8') # Changed to return the value instead of print it return resp_text except: raise 

You can see in the test how I assign the return value of your mocked sample_fct to an arbitrary Mock object. That object can have arbitrary attributes assigned to it, which can aid in testing for return values that may be many attribute levels deep.

"""test_request_module.py""" import unittest import unittest.mock as mock from request_module import SomeClass class TestRequests(unittest.TestCase): @mock.patch('request_module.SomeClass.sample_fct') def test_get_something(self, mock_sample_fct): mock_sample_fct.return_value = mock.Mock(content=b'some content you want to decode \xE2\x98\xBA') # Testing that your decoded value is returned some_class = SomeClass() result = some_class.get_something('some_test_value') # Note the decoded smiley face self.assertEqual('some content you want to decode ☺', result) 

Note that you can also assign attributes of attributes on a Mock. So if your caller is expecting something like request.attributes.nested_attributes.value, you could do something like this and Mock will allow it:

mock_ret = mock.Mock() mock_ret.request.attributes.nested_attributes.value = 'deep attr value' 
Sign up to request clarification or add additional context in comments.

2 Comments

Just a follow up question.. the .content.decode, which library is that from? I thought it was from the requests library.. but it turns out it isn't? (I didnt import requests, and was still able to use content.decode
.content is an attribute on the response object coming back from the requests library. .decode is a function on strings. .content is in raw byte form, so using decode will take those bytes and turn them back into the intended representation (perhaps a UTF8 smiley face like above). Whenever you see a u before a string in python 2.7, that's a unicode string; the default strings in python 3 are already unicode. I could go on for awhile about this; I'd recommend checking out: stackoverflow.com/questions/15092437/python-encoding-utf-8

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.