Home > Net >  python unittest returning strange __init__ error with requests and exception handling
python unittest returning strange __init__ error with requests and exception handling

Time:07-18

I have basic code that I am using to learn how to write Python unittests. It uses the "jokes" API.

The project is very simple and setup like this:

.
├── README.md
├── app
│   ├── __init__.py
│   ├── __pycache__
│   │   ├── __init__.cpython-39.pyc
│   │   ├── calc.cpython-39.pyc
│   │   ├── joke.cpython-39.pyc
│   │   └── math.cpython-39.pyc
│   ├── calc.py
│   └── joke.py
└── test
    ├── __init__.py
    ├── __pycache__
    │   ├── __init__.cpython-39.pyc
    │   └── test_joke.cpython-39.pyc
    ├── test_calc.py
    └── test_joke.py

the app code:

import requests

'''each time we make the get_joke() , we get a different result
so in order to test the len_joke(), we will mock the get_joke()
the mock will help isolate the len_joke() that is under test,
from its dependency'''

def len_joke():
  joke = get_joke()
  # add temp code for print testing during test call

  return len(joke)


def get_joke():
  url = 'http://api.icndb.com/jokes/random'

  
  try:
    response = requests.get(url, timeout=30)
    response.raise_for_status
  except requests.exceptions.Timeout:
    return "No jokes!"
  except requests.exceptions.ConnectionError:
    pass
  except requests.exceptions.HTTPError as e:
    status_code = e.response.status_code


    # return 'HTTP error was raised'
  else: 
    if response.status_code == 200:
      joke = response.json()['value']['joke']
    else:
      joke = "No jokes!"
  return joke

In order to test the application code, I have this test code:

import unittest
from unittest.mock import MagicMock, patch
from urllib.error import HTTPError

import requests
from app import joke
from requests.exceptions import Timeout

class TestJoke(unittest.TestCase):
  '''each time we make the get_joke() , we get a different result
   so in order to test the len_joke(), we will mock the get_joke()
   the mock will help isolate the len_joke() that is under test,
   from its dependency. Our testing methodology is completely independent 
   of an external network connection or an external API'''



  @patch('app.joke.requests')
  def test_get_joke_raise_timeout_exception(self, mock_requests): 
    mock_requests.exceptions = requests.exceptions
    mock_requests.get.side_effect = Timeout('seems like the server is down')
    self.assertEqual(joke.get_joke(), 'No jokes!')
  
  # we will again need a "mock response" variable
  @patch('app.joke.requests')
  def test_get_joke_raise_for_status(self, mock_requests): 
    mock_requests.exceptions = requests.exceptions
    mock_response = MagicMock(status_code=403)
    mock_response.raise_for_status.side_effect = HTTPError('Something went wrong')
    mock_requests.get.return_value = mock_response
    self.assertEqual(joke.get_joke(), 'HTTP error was raised')

The application code is working and I get my joke back from the API. The 'test_get_joke_raise_timeout_exception' test runs fine. However the 'test_get_joke_raise_for_status' is throwing the following error:

mock_response.raise_for_status.side_effect = HTTPError('Something went wrong')
TypeError: __init__() missing 4 required positional arguments: 'code', 'msg', 'hdrs', and 'fp'

Can anyone help me to interpret his traceback and figure out what's wrong with this test?

CodePudding user response:

HTTPError('Something went wrong') isn't a valid way to instantiate an HTTPError. The constructor of that class takes mandatory arguments code, msg, hdrs and fp, so your test will need to supply them.

See the source code and (although it isn't complete, presumably because it expects the class to be used primarily by code in the library, rather than application code) the documentation.

  • Related