2008-11-28 236 views
8

我来自Java世界,您可以隐藏变量和函数,然后使用反射对它们运行单元测试。我已经使用嵌套函数来隐藏我的类的实现细节,以便只有公共API可见。我正在尝试针对这些嵌套函数编写单元测试,以确保在开发时不会破坏它们。我已经打过电话像嵌套功能之一:嵌套函数运行单元测试

def outer(): 
    def inner(): 
     pass 

outer.inner() 

导致的错误信息:

AttributeError: 'function' object has no attribute 'inner'

有我的方式来编写针对这些嵌套函数单元测试?如果没有,有没有办法通过在__前面加上类似变量来为类变量触发名称调用的函数名称?

回答

5

Python约定是命名带有下划线的“私有”函数和方法。当你看到一个前导下划线时,你不会尝试和使用它。

请记住,Python is not Java

+11

这个问题如何回答?是否有很好的解决方案来隔离单元测试的这些内部函数?即使没有从外部函数对象访问内部函数,也可能通过使用python模块解析器,ast或tokenizer来实现代码本身。显然这比编码更容易。 :-) – 2011-07-09 16:02:06

+1

它回答了这个问题,因为没有*测试私人的实现细节。你可以依靠测试覆盖工具来告诉你,如果你测试的公共接口充分行使私有实现。 – SingleNegationElimination 2011-07-09 16:24:50

11

内部不存在,直到外部使它。你应该将内层移动到顶层函数以进行可测试性,或者让外层测试测试自身和内层的所有可能的执行路径。

请注意,内部函数不是一个简单的函数,它是一个闭包。考虑这种情况:

def outer(a): 
    b = compute_something_from(a) 
    def inner(): 
     do_something_with(a, b) 

这是标准的可测试性权衡。如果你的cyclomatic complexity太高,你的测试将会太多。

1

我不认为有任何机会从extern命名空间访问inner()。

但是,在我看来,保持inner()嵌套的事实意味着真正重要的唯一“契约”是outer()的一个。 inner()是实现的一部分,你不应该想测试实现。 如果您真的想测试inner(),请使用包含inner()的所有功能的数据对outer()进行大量测试。

2

无法从外部函数对象获取内部函数(请参阅其他答复!)。然而,单元测试和闭包(至少对我而言)都是令人惊叹的开发人员性能改进。我们可以兼得吗?我们可以单独测试嵌套函数吗?

不容易。

但是,使用python模块解析器,ast或tokenizer来实现代码本身,提取内部函数(通过嵌套的某些路径),并允许测试从状态运行它们为函数(在测试目标中定义的)嵌套函数(封闭的名称的值)和存根/模拟。

任何人都知道这样的事情吗?谷歌搜索未能找到任何东西。

1

我有同样的疑问,并找到一种方法来获取内部函数的测试。

def outer(): 
    def inner(): 
     pass 

    if __debug__: 
     test_inner(inner) 
     # return 

def test_inner(f): 
    f() # this calls the inner function 

outer() 

基本上,您可以将内部函数作为参数发送到外部并根据需要进行测试。当调用outer()时,您的测试将运行,并且由于它是一个闭包,它将保留外部函数的任何额外属性(如变量)。使用列表,您可以发送尽可能多的功能。要忽略如果,一个选项是运行这样的代码:

python -O code.py 
1

我已经写了一个小的辅助模块,它允许正是这一点:嵌套函数

例子:

def f(v1): 
    v2 = 1 
    def g(v3=2): 
    return v1 + v2 + v3 + 4 
    def h(): 
    return 16 
    return g() + h() + 32 

class C(object): 
    def foo(self): 
    def k(x): 
     return [ self, x ] 
    return k(3) 

def m(): 
    vm = 1 
    def n(an=2): 
    vn = 4 
    def o(ao=8): 
     vo = 16 
     return vm + an + vn + ao + vo 
    return o() 
    return n() 

这些可以使用这种类型的代码进行单元测试:

import unittest 
from nested import nested 

class TestNested(unittest.TestCase): 
    def runTest(self): 
    nestedG = nested(f, 'g', v1=8, v2=1) 
    self.assertEqual(nestedG(2), 15) 
    nestedH = nested(f, 'h') 
    self.assertEqual(nestedH(), 16) 
    nestedK = nested(C.foo, 'k', self='mock') 
    self.assertEqual(nestedK(5), [ 'mock', 5 ]) 
    nestedN = nested(m, 'n', vm=1) 
    nestedO = nested(nestedN, 'o', vm=1, an=2, vn=4) 
    self.assertEqual(nestedO(8), 31) 

def main(argv): 
    unittest.main() 

if __name__ == '__main__': 
    import sys 
    sys.exit(main(sys.argv)) 

小助手模块nested看起来像这样:

import types 

def freeVar(val): 
    def nested(): 
    return val 
    return nested.__closure__[0] 

def nested(outer, innerName, **freeVars): 
    if isinstance(outer, (types.FunctionType, types.MethodType)): 
    outer = outer.func_code 
    for const in outer.co_consts: 
    if isinstance(const, types.CodeType) and const.co_name == innerName: 
     return types.FunctionType(const, globals(), None, None, tuple(
      freeVar(freeVars[name]) for name in const.co_freevars))