Bypass decorator with mock in django test

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!

1 answer

  • answered 2018-10-12 08:37 Roman Konoval

    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.