Python 在嵌套函数上运行单元测试
我来自Java世界,在那里可以隐藏变量和函数,然后使用反射对它们运行单元测试。我使用嵌套函数来隐藏类的实现细节,以便只有公共API可见。我试图针对这些嵌套函数编写单元测试,以确保在开发过程中不会破坏它们。我尝试调用其中一个嵌套函数,如:Python 在嵌套函数上运行单元测试,python,testing,closures,Python,Testing,Closures,我来自Java世界,在那里可以隐藏变量和函数,然后使用反射对它们运行单元测试。我使用嵌套函数来隐藏类的实现细节,以便只有公共API可见。我试图针对这些嵌套函数编写单元测试,以确保在开发过程中不会破坏它们。我尝试调用其中一个嵌套函数,如: def outer(): def inner(): pass outer.inner() 这将导致错误消息: AttributeError:“函数”对象没有属性“内部” 我有没有办法针对这些嵌套函数编写单元测试?如果没有,是否有一种方
def outer():
def inner():
pass
outer.inner()
这将导致错误消息:
AttributeError:“函数”对象没有属性“内部”
我有没有办法针对这些嵌套函数编写单元测试?如果没有,是否有一种方法可以触发函数名的名称蒙格,就像类变量的名称蒙格一样,方法是在函数名前面加上_?直到外部变量出现,内部变量才存在。为了可测试性,您应该将内部函数向上移动到顶级函数,或者让外部函数测试其自身和内部函数的所有可能执行路径 请注意,内部函数不是一个简单的函数,它是一个闭包。考虑这种情况:
def outer(a):
b = compute_something_from(a)
def inner():
do_something_with(a, b)
这是标准的可测试性权衡。如果值太高,测试将太多。Python的惯例是使用前导下划线命名“private”函数和方法。当您看到前导下划线时,您知道不要尝试使用它
记住,.我认为没有任何机会从外部名称空间访问inner() 然而,在我看来,将inner()嵌套意味着真正重要的唯一“契约”是outer()的契约。inner()是实现的一部分,您不应该想测试实现。
如果确实要测试inner(),请使用包含inner()所有功能的数据对outer()进行大量测试。无法从outer function对象获取内部函数(请参阅其他回复!)。然而,单元测试和闭包都(至少对我来说)提高了开发人员的性能。我们两个都可以吗?我们可以单独测试嵌套函数吗 不容易 然而,这似乎可以通过使用python模块解析器、ast或标记器来实现,将代码本身分割开来,提取内部函数(通过嵌套的某个路径),并允许测试使用封闭函数的状态(封闭名称的值)和更多嵌套函数的存根/模拟来运行它们(在测试目标中定义)
有人知道这样的事情吗?谷歌没有找到任何东西。我也有同样的疑问,找到了一种方法让内部函数的测试得以进行
def outer():
def inner():
pass
if __debug__:
test_inner(inner)
# return
def test_inner(f):
f() # this calls the inner function
outer()
基本上,您可以将内部函数作为参数发送到外部,并根据需要对其进行测试。当调用outer()时,您的测试将运行,并且由于它是一个闭包,因此它将保留外部函数的任何额外属性(如变量)。使用列表,您可以发送任意数量的函数。若要忽略if,可选择如下方式运行代码:
python -O code.py
我已经编写了一个小的帮助器模块,它完全支持以下内容: 嵌套函数的示例:
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))
嵌套的小辅助模块如下所示:
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))
我遇到了一个有趣的案例,在这个案例中,我能够使用MagicMock对嵌套函数运行单元测试。关键是嵌套函数作为参数发送给我有权访问的另一个函数。为了与OP的示例保持一致:
# my_app.py
def util(func):
# run some logic using func
def outer():
def inner():
pass
util(inner)
能够模拟util
函数允许访问调用参数,在本例中,调用参数恰好是内部
函数:
def test_inner
# Arrange
mock_util = MagicMock()
with patch.object(my_app, 'util', mock_util):
outer() # run the outer function to capture the util call with MagicMock
inner_function = mock_util.call_args[0][0]
# Act
inner_function() # run the inner function for testing
# Assert
# make whatever assertions you would like
这一次我很幸运,因为我不需要修改要求我测试的代码。为那些正在寻找选项的人提供了一种有意的方式来做类似的事情。尽管如此,如果你要修改代码,你也可以按照这个问题的其他好答案来做。这是如何回答这个问题的是否有很好的解决方案来隔离这些内部函数进行单元测试?即使没有从外部函数对象访问内部函数,似乎也可以通过使用python模块解析器、ast或标记器来分割代码本身来实现。显然,声明比编写代码更容易。:-)它回答了这个问题,因为它不测试私有的实现细节。您可以依靠测试覆盖率工具来告诉您,您对公共接口的测试是否充分地执行了私有实现。@Tim:根据问题的最后一句话,如果可以将非内部函数标记为私有,则作者可以使用该函数。因此,了解这个约定是很有用的。我相信可以访问cpython中的内部函数。下面有一个答案确切地说明了如何做到这一点。