Bypassing a decorator for unit testing

4.2k views Asked by At

I have a decorator @auth which basically checks a database to ensure a user can access a given REST call. I would like to write some unit tests for these calls. My initial idea was to simply monkeypatch the decorator into a pass through that does nothing. (My initial idea failed, so I may just monkeypatch some function inside of @auth so that it always passes, but I'm still curious if I can bypass a decorator completely)

I threw together a quick sample of what I was hoping to accomplish.

example.py

# example.py
from __future__ import print_function

def sample_decorator(func):
    def decorated(*args, **kwargs):
        print("Start Calculation")
        ans = func(*args, **kwargs) + 3
        print(ans)
        print("Finished")
        return ans
    return decorated

@sample_decorator
def add(a, b):
    return a + b

test_example.py

# test_example.py
from __future__ import print_function
import pytest

import example

def test_add_with_decorator():
    assert example.add(1, 1) == 5

def testadd_with_monkeypatch_out_decorator(monkeypatch):
    monkeypatch.setattr(example, 'sample_decorator', lambda func: func)
    assert example.add(1, 1) == 2  # this fails, but is the behaviour I want

Is there some straight forward way to accomplish this?

2

There are 2 answers

2
user2722968 On BEST ANSWER

The decorator can set an attribute on the wrapping function to give access to the wrapped function.

Something along the line of

def wrap_foo(func):
 def decorated(*args, **kwargs):
  func(*args, **kwargs)
 decorated.__wrapped__ = func
 return decorated

@wrap_foo
def foo():
 pass

# Wrapped
foo()

# Unwrapped
foo.__wrapped__()
1
Alex Hall On

Just keep the definitions separate:

def raw_add...

add = sample_decorator(raw_add)

assert example.raw_add...