Testing Python Decorators?

Related searches

I'm writing some unit tests for a Django project, and I was wondering if its possible (or necessary?) to test some of the decorators that I wrote for it.

Here is an example of a decorator that I wrote:

class login_required(object):

    def __init__(self, f):
        self.f = f

    def __call__(self, *args):
        request = args[0]
        if request.user and request.user.is_authenticated():
            return self.f(*args)
        return redirect('/login')

Simply:

from nose.tools import assert_equal
from mock import Mock

class TestLoginRequired(object):
    def test_no_user(self):
        func = Mock()
        decorated_func = login_required(func)
        request = prepare_request_without_user()
        response = decorated_func(request)
        assert not func.called
        # assert response is redirect

    def test_bad_user(self):
        func = Mock()
        decorated_func = login_required(func)
        request = prepare_request_with_non_authenticated_user()
        response = decorated_func(request)
        assert not func.called
        # assert response is redirect

    def test_ok(self):
        func = Mock(return_value='my response')
        decorated_func = login_required(func)
        request = prepare_request_with_ok_user()
        response = decorated_func(request)
        func.assert_called_with(request)
        assert_equal(response, 'my response')

The mock library helps here.

Testing Python Decorators?, Simply: from nose.tools import assert_equal from mock import Mock class TestLoginRequired(object): def test_no_user(self): func = Mock()� Testing decorators is tiny bit different. You need to leave decorated function out of the equation and instead verify whether decorator does what it supposed to. Coincidentally I have just the

A decorator like this might be tested simply thanks to duck-typing. Just supply a mock object to the call function, that seems to hold and act as a request, and see if you get the expected behaviour.

When it is necessary to use unit tests is quite individual i'd say. The example you give contain such basic code that one might say that it isn't necessary. But then again, the cost of testing a class like this is equally low.

Leveraging the power of decorators in Python's unit-test framework , Python provides this functionality with its in-built unit-testing framework. One only needs to add the following line to start creating test cases for� Browse other questions tagged python unit-testing decorator or ask your own question. The Overflow Blog Podcast 259: from web comics to React core with Rachel Nabors

Example for Django's UnitTest
class TestCaseExample(TestCase):
    def test_decorator(self):
        request = HttpRequest()
        # Set the required properties of your request
        function = lambda x: x
        decorator = login_required(function)
        response = decorator(request)
        self.assertRedirects(response)

In general, the approach I've utilized is the following:

  1. Set up your request.
  2. Create a dummy function to allow the decorator magic to happen (lambda). This is where you can control the number of arguments that will eventually be passed into the decorator.
  3. Conduct an assertion based on your decorator's response.

Things to remember about decorators // James Cooke // Brighton , Notes to myself about Python decorators with a focus on making them Failing to do so will prevent doctest from testing the decorated function. Here we assign the function to a variable. We will notice that after the variable is assigned, it became a function. Below is the output of the test_decorator: test_decorators.py::test_decorator PASSED [100%]8 3. Functions in Python can also take other function as input, then return other function.

For those looking for a django type decorator test, this is how I ran tests on my custom django decorator:

common/decorators.py

from functools import wraps
from django.http import Http404


def condition_passes_test(test_func, fail_msg=''):
    """
    Decorator for views that checks that a condition passes the given test,
    raising a 404 if condition fails
    """

    def decorator(view_func):
        @wraps(view_func)
        def _wrapped_view(request, *args, **kwargs):
            if test_func():
                return view_func(request, *args, **kwargs)
            else:
                raise Http404(fail_msg)
        return _wrapped_view
    return decorator

The test:

import django
from django.test import TestCase
from django.http import Http404
from django.http import HttpResponse
from django.test import RequestFactory

from common import decorators


class TestCommonDecorators(TestCase):

    def shortDescription(self):
        return None

    def test_condition_passes_test1(self):
        """
        Test case where we raise a 404 b/c test function returns False
        """
        def func():
            return False

        @decorators.condition_passes_test(func)
        def a_view(request):
            return HttpResponse('a response for request {}'.format(request))
        request = RequestFactory().get('/a/url')

        with self.assertRaises(django.http.response.Http404):
            a_view(request)

    def test_condition_passes_test2(self):
        """
        Test case where we get 200 b/c test function returns True
        """
        def func():
            return True

        @decorators.condition_passes_test(func)
        def a_view(request):
            return HttpResponse('a response for request {}'.format(request))

        request = RequestFactory().get('/app_health/z')
        request = a_view(request)
        self.assertEquals(request.status_code, 200)

NOTE: I Am using it as such on my view where my_test_function returns True or False:

@method_decorator(condition_passes_test(my_test_function, fail_msg="Container view disabled"), name='dispatch')

Module: testing.decorators — IPython 7.16.1 documentation, If you are looking for an IPython version compatible with Python 2.7, please use the IPython Decorator to make a simple function into a normal test via unittest. A keen observer will notice that parameters of the nested inner () function inside the decorator is the same as the parameters of functions it decorates. Taking this into account, now we can make general decorators that work with any number of parameters. In Python, this magic is done as function (*args, **kwargs).

Testing Decorated Python Functions – David Andersson, Decorators are a great way of adding functionality to a function with minimal impact on the function itself. On top of that, decorator logic can be� A decorator is a function that takes another function as an argument, does some actions, and then returns the argument based on the actions performed. Since functions are first-class object in Python, they can be passed as arguments to another functions. Hence we can say that a decorator is a callable that accepts and returns a callable.

If you're writing a test, you may mark it as a known failing test with the pytest.mark.xfail() decorator. This allows the test to be added to the test suite and run on the buildbots without causing undue alarm.

Put simply: decorators wrap a function, modifying its behavior. Before moving on, let’s have a look at a second example. Because wrapper() is a regular Python function, the way a decorator modifies a function can change dynamically. So as not to disturb your neighbors, the following example will only run the decorated code during the day:

Comments
  • I think this is a great question but why would you rewrite this decorator? docs.djangoproject.com/en/1.1/topics/auth/…
  • Any particular reason you're not using django.contrib.auth.decorators.login_required ?
  • While decorators are just pieces of code, they should be tested as any other piece of code.
  • the short answer to @Mark Lavin is that we're rolling our own auth system and we're mimicking the decorators from django.conrtib.auth to make our lives easier
  • You have 1 error, TypeError: assertRedirects() missing 1 required positional argument: 'expected_url'