Search code examples
pythonjsonnosetestsflask-restful

Python nose test failing on JSON response


This is the method in ReportRunner class in report_runner.py in my Flask-Restful app:

class ReportRunner(object):

  def __init__(self):
        pass

  def setup_routes(self, app):
      app.add_url_rule("/run_report", view_func=self.run_report)

  def request_report(self, key):
    # code #

  def key_exists(self, key):
    # code #

  def run_report(self):
    key = request.args.get("key", "")
    if self.key_exists(key):
      self.request_report(report_type, key)
      return jsonify(message = "Success! Your report has been created.")
    else:
      response = jsonify({"message": "Error => report key not found on server."})
      response.status_code = 404
      return response

and the nose test calls the URL associated with that route

def setUp(self):
    self.setup_flask()
    self.controller = Controller()
    self.report_runner = ReportRunner()
    self.setup_route(self.report_runner)

def test_run_report(self):
    rr = Report(key = "daily_report")
    rr.save()
    self.controller.override(self.report_runner, "request_report")
    self.controller.expectAndReturn(self.report_runner.request_report("daily_report"), True )
    self.controller.replay()
    response = self.client.get("/run_report?key=daily_report")
    assert_equals({"message": "Success! Your report has been created."}, response.json)
    assert_equals(200, response.status_code)

and the test was failing with the following message:

AttributeError: 'Response' object has no attribute 'json'

but according to the docs it seems that this is how you do it. Do I change the return value from the method, or do I need to structure the test differently?

The test is now passing written like this:

json_response = json.loads(response.data)
assert_equals("Success! Your report has been created.", json_response["message"])

but I'm not clear on the difference between the two approaches.


Solution

  • According to Flask API Response object doesn't have attribute json (it's Request object that has it). So, that's why you get exception. Instead, it has generic method get_data() that returns the string representation of response body.

    json_response = json.loads(response.get_data())
    assert_equals("Success! Your report has been created.", json_response.get("message", "<no message>"))
    

    So, it's close to what you have except:

    • get_data() is suggested instead of data as API says: This should not be used and will eventually get deprecated.

    • reading value from dictionary with get() to not generate exception if key is missing but get correct assert about missing message.

    Check this Q&A also.