Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mock exception raised in function using Pytest

I have the following function and it is a generic function which will make API call based on the input hostname and data. It will construct http request to make API and will return the response. This function will throw four types of exception(invalid URL, timeout, auth error and status check). How can I Mcok and Test the exception raised in API call using pytest? Which will be the best method to test the exceptions raised from API call?

import ssl
import urllib
import urllib.request
import urllib.error
import xml
import xml.etree.ElementTree as ET

def call_api(hostname, data):
    '''Function to make API call
    '''
    # Todo:
    # Context to separate function?
    # check response for status codes and return reponse.read() if success
    #   Else throw exception and catch it in calling function
    error_codes = {
         "1": "Unknown command",
         "6": "Bad Xpath",
         "7": "Object not present",
         "8": "Object not unique"
     }
    url = "http://" + hostname + "/api"
    encoded_data = urllib.parse.urlencode(data).encode('utf-8')
    try:
        response = urllib.request.urlopen(url, data=encoded_data, 
timeout=10).read()
        root = ET.fromstring(response)
        if root.attrib.get('status') != "success":
            Errorcode = root.attrib.get('code')
            raise Exception(pan_error_codes.get(Errorcode, "UnknownError"), 
response)
        else:
            return response
    except urllib.error.HTTPError as e:
        raise Exception(f"HttpError: {e.code} {e.reason} at {e.url}", None)
    except urllib.error.URLError as e:
       raise Exception(f"Urlerror: {e.reason}", None)

If i call this function

def create_key(hostname, username, password):
hostname = 'myhost ip'
data = {
    'type': 'keygen',
    'username': username,
    'password': password
}
username = 'myuser'
password = 'password'
response = call_api(hostname, data)
return response

i will get a response like following

b"<response status = 'success'><result><key>mykey</key></result></response>"
like image 293
Abheena Ps Avatar asked Jun 21 '18 09:06

Abheena Ps


1 Answers

You can mock error raising via side_effect parameter:

Alternatively side_effect can be an exception class or instance. In this case the exception will be raised when the mock is called.

In your case, this can be used like this (assuming call_api is defined in module foo):

import pytest
from unittest.mock import patch

def test_api():
    with patch('foo.call_api', side_effect=Exception('mocked error')):
        with pytest.raises(Exception) as excinfo:
            create_key('localhost:8080', 'spam', 'eggs')
        assert excinfo.value.message == 'mocked error' 
like image 166
hoefling Avatar answered Sep 20 '22 09:09

hoefling