Не переусердствуйте. Как и в течение десятилетий, передайте числовое смещение от стандартной фактической эпохи 1 января 1970 года, полуночи по Гринвичу / UTC / & amp; c в секундах (или миллисекундах) с этой эпохи. JavaScript нравится, Java нравится, C нравится, а Интернету нравится.
В общем случае вы не можете, потому что
@with_connection
def spam(connection):
# Do something
эквивалентно
def spam(connection):
# Do something
spam = with_connection(spam)
, что означает, что «исходный» спам может больше не существовать. Хак (не очень красивый) будет выглядеть так:
def with_connection(f):
def decorated(*args, **kwargs):
f(get_connection(...), *args, **kwargs)
decorated._original = f
return decorated
@with_connection
def spam(connection):
# Do something
spam._original(testcon) # calls the undecorated function
Вместо того, чтобы делать ...
def with_connection(f):
def decorated(*args, **kwargs):
f(get_connection(...), *args, **kwargs)
return decorated
@with_connection
def spam(connection):
# Do something
orig_spam = magic_hack_of_a_function(spam)
Вы могли бы просто сделать ...
def with_connection(f):
...
def spam_f(connection):
...
spam = with_connection(spam_f)
... это весь синтаксис @decorator
- тогда вы, очевидно, сможете получить доступ к исходному spam_f
обычным образом.
Решение balpha можно сделать более универсальным с помощью этого мета-декоратора:
def include_original(dec):
def meta_decorator(f):
decorated = dec(f)
decorated._original = f
return decorated
return meta_decorator
Затем вы можете украсить свои декораторы @include_original, и у каждого будет тестируемая (недекорированная) версия, спрятанная внутри это.
@include_original
def shout(f):
def _():
string = f()
return string.upper()
return _
@shout
def function():
return "hello world"
>>> print function()
HELLO_WORLD
>>> print function._original()
hello world
Обычный подход к тестированию таких функций - сделать любые зависимости, такие как get_connection, настраиваемыми. Затем вы можете переопределить его с помощью макета во время тестирования. В основном то же самое, что и внедрение зависимостей в мире Java, но намного проще благодаря динамической природе Pythons.
Код для этого может выглядеть примерно так:
# decorator definition
def with_connection(f):
def decorated(*args, **kwargs):
f(with_connection.connection_getter(), *args, **kwargs)
return decorated
# normal configuration
with_connection.connection_getter = lambda: get_connection(...)
# inside testsuite setup override it
with_connection.connection_getter = lambda: "a mock connection"
В зависимости от вашего кода вы можете найти лучший объект, чем декоратор, который можно вставить заводская функция включена. Проблема с его использованием в декораторе заключается в том, что вам придется не забывать восстановить его до старого значения в методе teardown.
Вот, FuglyHackThatWillWorkForYourExampleButICantPromiseAnythingElse:
orig_spam = spam.func_closure[0].cell_contents
Изменить : для функций / методов, оформленных более одного раза и с более сложными декораторами, вы можете попробовать использовать следующий код. Он основан на том факте, что декорированные функции имеют __name__d иначе, чем исходная функция.
def search_for_orig(decorated, orig_name):
for obj in (c.cell_contents for c in decorated.__closure__):
if hasattr(obj, "__name__") and obj.__name__ == orig_name:
return obj
if hasattr(obj, "__closure__") and obj.__closure__:
found = search_for_orig(obj, orig_name)
if found:
return found
return None
>>> search_for_orig(spam, "spam")
<function spam at 0x027ACD70>
Однако это не доказательство дурака. Он потерпит неудачу, если имя функции, возвращаемой декоратором, совпадает с именем декорированного. Порядок проверок hasattr () также является эвристическим, существуют цепочки декорирования, которые в любом случае возвращают неверные результаты.
Он потерпит неудачу, если имя функции, возвращаемой декоратором, совпадает с именем декорированного. Порядок проверок hasattr () также является эвристическим, существуют цепочки декорирования, которые в любом случае возвращают неверные результаты. Он потерпит неудачу, если имя функции, возвращаемой декоратором, совпадает с именем декорированного. Порядок проверок hasattr () также является эвристическим, существуют цепочки декорирования, которые в любом случае возвращают неверные результаты.Добавьте декоратор, не выполняющий никаких действий:
def do_nothing(f):
return f
После определения или импорта with_connection, но до Чтобы перейти к методам, которые используют его в качестве декоратора, добавьте:
if TESTING:
with_connection = do_nothing
Затем, если вы установите глобальное ТЕСТИРОВАНИЕ на True, вы замените with_connection на декоратор, не требующий действий.