Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I simulate connection errors and request timeouts in python unit tests

Suppose my django/flask application pulls in information from API's, how can I test that connection exceptions are caught and handled properly?

So for example here is a function that calls an API:

import requests
def call_the_api():
    url = 'http://httpbin.org/get'
    try:
        req = requests.get(url)
        if req.json().get('errors'):
            logger.warn("API error response")
            return {'request_error': 'api_error_response'}
    except requests.exceptions.ConnectionError:
        logger.warn('ConnectionError')
        return {'request_error': 'ConnectionTimeout'}
    except requests.exception.Timeout:
        logger.warn('API request timed out')
        return {'request_error': 'Timeout'}
    except Exception, ex:
        logger.warn("API request Exception: %s", ex)
        return {'request_error': ex}
    else:
        return req.json()

For testing responses from the API I found mock to be very useful.

def mock_get_request():
    response = requests.get.return_value
    json_file = 'sample_response.json'
    json_file_path = os.path.join(os.path.dirname(__file__), json_file)
    with open(json_file_path, 'r') as f:
        response.content = response.text = f.read()
    response.status_code = 200
    response.encoding = 'utf-8'
    response.json = lambda: json.loads(response.content.decode(response.encoding))
    response.url = u'%s' % args[0]
    return response

class TestSuitabilityFunctions(TestCase):
    def test_call_the_api(self):
        requests.get = MagicMock(side_effect=mock_get_request)
        resp = call_the_api()
        self.assertEqual(resp.get('url'), "http://httpbin.org/get")

So my question is how would I go about simulating a connection timeout or error?

like image 982
Tom Avatar asked Jan 02 '14 15:01

Tom


1 Answers

Untested code but...

def connection_error():
    raise requests.exceptions.ConnectionError

class TestSuitabilityFunctions(TestCase):
    @patch.object(module_that_youre_testing, "requests")
    def test_connection_error(self, mock_requests):
        mock_requests.get = MagicMock(side_effect=connection_error)
        with self.assertRaises(requests.exceptions.ConnectionError) as cm:
            resp = call_the_api()
        exception = cm.exception
        self.assertEqual(resp, {'request_error': 'ConnectionTimeout'})

... or similar should do the trick. Off the top of my head I can't remember how assertRaises interacts with errors that are caught. Maybe you don't even need the assertRaises part.

like image 120
ptr Avatar answered Oct 02 '22 08:10

ptr