2

I am new to python and flask. I wanted to create unit tests for an api written. We have used jwt for authentication.

To unit test, I don't want the flow to enter @jwt_required decorator. In addition to that I have chained a few other decorators for that method.

class A():

   @jwt_required()
   @mandatory_fields_check
   @unlock_and_lock()
   def get(self, address, name): 
      ..
      ..
      ..
       return jsonify(
            {"payload": data,
             "message": "data received successfully"}), 200

Unit test I am trying to write

def test_get():
   a_obj = A()
   a_obj.get("address123", 'xyz')

When I run above test using py.test, I am getting Runtime error

    def _find_app():
            top = _app_ctx_stack.top
            if top is None:
               raise RuntimeError(_app_ctx_err_msg)
     RuntimeError: Working outside of application context.
E
E           This typically means that you attempted to use functionality that needed
E           to interface with the current application object in some way. To solve
E           this, set up an application context with app.app_context().  See the
E           documentation for more information.

Below are my objectives:

  1. I don't want flow to enter decorators logic

  2. Jwt decorator is asking for context. However my intention is to unit test this method as a normal class method without any flask features.

  3. How can I mock objects created inside the method under test?

bhaskar
  • 21
  • 2
  • 4

3 Answers3

2

Instead of trying to mock the decorator, mock out the function the decorator is calling.

I ran into a similar obstacle using flask_jwt_extended where I wanted to mock out the jwt_required decorator.

@jwt_required
def post(payload)
    ....

Instead of

mock.patch('flask_jwt_extended.jwt_required')

I looked at the function the jwt_required decorator was calling (which in this case was verify_jwt_in_request from flask_jwt_extended.view_decorators). So,

mock.patch('flask_jwt_extended.view_decorators.verify_jwt_in_request')

did the trick!

Mathieu Dhondt
  • 8,405
  • 5
  • 37
  • 58
  • Hi, I tried your way but it is still not working for me. I am sure I am missing something but not sure what. – Prakash Jun 10 '23 at 18:03
0

based on the description here

It should be like this, but not tested.

import mock
def mock_jwt_required(realm):
    return

@mock.patch('flask_jwt.jwt_required', side_effect=mock_jwt_required)
def test_get(jwt_required_fn):
    a_obj = A()
    a_obj.get("address123", 'xyz')
Gang
  • 2,658
  • 3
  • 17
  • 38
0

I used this library called undecorated and its working fine for me. https://stackoverflow.com/a/35418639

https://pypi.org/project/undecorated/

This is clean, however if there is a any easier way without importing libraries please suggest.

bhaskar
  • 21
  • 2
  • 4