0

I am trying to write a simple test however my views are decorated with nested user_passes_test statements. They check things like a stripe subscription and is_authenticated. I have found various posts such as this which address how to bypass a decorator with patch but I can't quite work out how to integrate everything together.

tests.py

@patch('dashboard.views.authorised_base_user_checks', lambda func: func)
def test_dashboard_root_exists(self):
    response = self.client.get('/dashboard/')
    self.assertEqual(200, response.status_code)

decorator in views

def authorised_base_user_checks(view_func):
    decorated_view_func = login_required(user_active(subscriber_exists(subscriber_valid(view_func))))
    return decorated_view_func

views.py

@authorised_base_user_checks
def IndexView(request):
    ...

The above still fails to pass through the decorator.

Thanks!

Cam Rail
  • 177
  • 1
  • 2
  • 11

1 Answers1

0

This approach with patching of decorator most probably does not work because import of views module happens after the patching. If view has been already imported the decorator had been already applied to IndexView and patching the decorator function would have no effect at all.

You can reload the view module to overcome this:

import imp
import dashboard.views

@patch('dashboard.views.authorised_base_user_checks', lambda func: func)
def test_dashboard_root_exists(self):
   # reload module to make sure view is decorated with patched decorator
   imp.reload(views)

   response = self.client.get('/dashboard/')
   self.assertEqual(200, response.status_code)

   # reload again
   patch.stopall()
   imp.reload(views)

Disclaimer: this code only demonstrates the idea. You need to make sure stopall and final reload always happens, so they should be in finally or in tearDown.

  • The code was there to give the idea, I haven't run it etc. The last `patch` had incorrect name of the function. I fixed it now – Roman-Stop RU aggression in UA Oct 12 '18 at 12:41
  • Thanks I updated mine with those changes ... is that stack trace what you would expect if the decorator was still being called or is it perhaps something different? – Cam Rail Oct 12 '18 at 12:50
  • Just checked and the `def authorised_base_user_checks(view_func):` code isn't actually being called at all as I put a set trace in there and it wasn't activated – Cam Rail Oct 12 '18 at 12:57
  • Sorry, my idea with mocking decorator internals was misleading as it will not work in this case (namely because there's no actual function invocation in decorator, it uses other functions to wrap). – Roman-Stop RU aggression in UA Oct 12 '18 at 13:04
  • no problems thanks for trying... the above still fails unfortunately, I guess the nesting is complicating things, I'll have to have more of a look around. Thanks for your help – Cam Rail Oct 12 '18 at 13:11
  • I use both approaches in my projects without any problem. The approach with reloading should work in your case as well. Mocking internals works if your decorator invokes the wrapped function directly (so unfortunately not in your case). – Roman-Stop RU aggression in UA Oct 12 '18 at 13:14