Python: 如何在单元(鼻子)测试期间忽略装饰器?

Python: How to ignore decorators during unit (nose) tests?

我想忽略代码中的某些装饰器以跳过相关功能,但仅当 运行ning 作为单元测试的一部分时。这能做到吗?

例如,我有一个函数 f,它用 numba 装饰器定义,如下所示:

@numba.jit
def f(a, b):
  return a + b

当我 运行 调用上述函数的单元测试时,我不希望 numba 魔术发生,因为它会减慢速度并在某些平台上导致错误。是否可以在某个地方进行设置,告诉 nose 运行 测试,而无需应用任何 numba 即时(and/or 所有 numba)装饰器?

您也许可以欺骗 nose 使用您自己的装饰器来保持功能不变。 写一个包含这个函数的文件numba.py

def jit(func):
    return func

并放置在您的 PYTHONPATH 中。 运行 您从这个文件所在的目录进行测试,或者在 你的测试文件作为第一行:

import sys

sys.path.insert(0, 'path/to/dir/with/myfile') 

或者,您可以将环境变量 PYTHONPATH 设置为文件所在的目录。

Windows:

set PYTHONPATH=%PYTHONPATH%;path/to/dir/with/myfile

Unix/Mac:

export PYTHONPATH=$PYTHONPATH$:path/to/dir/with/myfile

您可以使用您可以控制的新装饰器修补装饰器:

import functools

def patch(parent, obj_name, switch_reg, switch_name):
    def gen_switcher():
        def wrapper(func):
            ori_wrapped = ori_decorator(func)
            @functools.wraps(func)
            def _(*args, **kwargs):
                if switch_reg.get(switch_name, False):
                    func_to_call = func
                else:
                    func_to_call = ori_wrapped
                print(func_to_call)
                return func_to_call(*args, **kwargs)
            return _
        return wrapper
    ori_decorator = getattr(parent, obj_name)
    setattr(parent, obj_name, gen_switcher())

与:

# have to patch the decorator before applying it
import numba
switchs = {}
patch(numba, 'jit', switchs, 'DISABLE_NUMBA_JIT')

@numba.jit
def f(a, b):
  return a + b

f(1, 2)

产量:

CPUDispatcher(<function f at 0x10a5f90d0>)

然后:

# this part could be rewrited as a context manager    
switchs['DISABLE_NUMBA_JIT'] = True
f(1, 2)

得到:

<function f at 0x10a5f90d0>

仅对于 numba,您可以设置一个环境变量(例如 export NUMBA_DISABLE_JIT=1)以使 jit 装饰器无操作。

http://numba.pydata.org/numba-doc/dev/user/troubleshoot.html#disabling-jit-compilation

我会将函数分离到您单元测试的非装饰部分 -- 然后让您的真实函数具有装饰器并简单地调用辅助函数:

@numba.jit
def f(a, b):
  return f_undecorated(a, b)

def f_undecorated(a, b):
  return a + b

仅为f_undecorated编写单元测试。

如果您正在使用 coverage,您可以通过在 coverage 命令之前添加 NUMBA_DISABLE_JIT=1 来修改 CI .yml 文件:

NUMBA_DISABLE_JIT=1 coverage run -p "test_*.py"