绕过装饰器进行单元测试
Bypassing a decorator for unit testing
我有一个装饰器 @auth
,它主要检查数据库以确保用户可以访问给定的 REST 调用。我想为这些调用编写一些单元测试。我最初的想法是简单地将装饰器修补成一个什么也不做的通道。 (我最初的想法失败了,所以我可能只是在 @auth
内部修改一些函数,以便它总是通过,但我仍然很好奇我是否可以完全绕过装饰器)
我整理了一个我希望完成的快速示例。
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
有什么直接的方法可以做到这一点吗?
只需将定义分开即可:
def raw_add...
add = sample_decorator(raw_add)
assert example.raw_add...
装饰器可以在包装函数上设置一个属性来访问包装函数。
类似于
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__()
我有一个装饰器 @auth
,它主要检查数据库以确保用户可以访问给定的 REST 调用。我想为这些调用编写一些单元测试。我最初的想法是简单地将装饰器修补成一个什么也不做的通道。 (我最初的想法失败了,所以我可能只是在 @auth
内部修改一些函数,以便它总是通过,但我仍然很好奇我是否可以完全绕过装饰器)
我整理了一个我希望完成的快速示例。
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
有什么直接的方法可以做到这一点吗?
只需将定义分开即可:
def raw_add...
add = sample_decorator(raw_add)
assert example.raw_add...
装饰器可以在包装函数上设置一个属性来访问包装函数。
类似于
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__()