I come from the Java world, where you can hide variables and functions and then run unit tests against them using reflection. I have used nested functions to hide implementation details of my classes so that only the public API is visible. I am trying to write unit tests against these nested functions to make sure that I don't break them as I develop. I have tried calling one of the nested functions like:
我来自Java世界,您可以在其中隐藏变量和函数,然后使用反射对它们运行单元测试。我使用嵌套函数来隐藏类的实现细节,以便只显示公共API。我正在尝试针对这些嵌套函数编写单元测试,以确保在开发时不会破坏它们。我试过调用一个嵌套函数,如:
def outer():
def inner():
pass
outer.inner()
which results in the error message:
这会导致错误消息:
AttributeError: 'function' object has no attribute 'inner'
AttributeError:'function'对象没有属性'inner'
Is there a way for me to write unit tests against these nested functions? If not, is there a way to trigger the name munging for function names like you can for class variables by prefixing them with __?
有没有办法让我对这些嵌套函数编写单元测试?如果没有,有没有办法通过为__添加前缀来触发名称,为类变量触发函数名称?
6 个解决方案
#1
5
The Python convention is to name "private" functions and methods with a leading underscore. When you see a leading underscore, you know not to try and use it.
Python惯例是使用前导下划线命名“私有”函数和方法。当您看到前导下划线时,您知道不要尝试使用它。
Remember, Python is not Java.
请记住,Python不是Java。
#2
11
inner doesn't exist until outer makes it. You should either move inner up to a toplevel function for testability, or have the outer test test all the possible execution paths of itself and inner.
内在不存在,直到外在它。您应该将内部向上移动到顶层函数以实现可测试性,或者让外部测试测试其自身和内部的所有可能的执行路径。
Do note that the inner function isn't a simple function, it's a closure. Consider this case:
请注意,内部函数不是一个简单的函数,它是一个闭包。考虑这种情况:
def outer(a):
b = compute_something_from(a)
def inner():
do_something_with(a, b)
That's the standard testability trade-off. If your cyclomatic complexity is too high, your tests will be too numerous.
这是标准的可测试性权衡。如果您的圈复杂度太高,那么您的测试将会太多。
#3
2
No way to get inner function from outer function object (see the other replies!). Yet both unit tests and closures have made (for me at least) amazing developer performance improvements. Can we have both? Can we test nested functions in isolation?
无法从外部函数对象获取内部函数(请参阅其他回复!)。然而,单元测试和闭包都使(至少对我来说)开发人员的性能有了惊人的提升。我们可以同时拥有吗?我们可以单独测试嵌套函数吗?
Not easily.
However, such could seemingly be achieved with use of python modules parser, ast, or tokenizer to dice up the code itself, extracting inner functions (by some path through the nesting), and allowing tests to run them with state from enclosing functions (values for closed-over names) and stubs/mocks for more-nested functions (defined within the test target).
然而,这似乎可以通过使用python模块解析器,ast或tokenizer来实现代码本身,提取内部函数(通过嵌套的某些路径),并允许测试使用封闭函数的状态运行它们(值对于更多嵌套函数(在测试目标中定义),用于封闭式名称和存根/模拟。
Anybody know of anything like this? Googling failed to find anything.
有人知道这样的事吗?谷歌搜索没有找到任何东西。
#4
1
I don't think that there is any chance to access inner() from the extern namespace.
我认为没有机会从extern命名空间访问inner()。
However, in my opinion the fact that you keep inner() nested implies that the only "contract" that really matters is outer()'s one. inner() is part of the implementation, and you shouldn't want to test the implementation. If you really want to test inner(), do extensive tests on outer() with data that will involve all the functionalities of inner().
但是,在我看来,你保持inner()嵌套这一事实意味着真正重要的唯一“契约”是outer()的一个。 inner()是实现的一部分,您不应该测试实现。如果你真的想测试inner(),那么对outer()进行大量测试,其中包含涉及inner()所有功能的数据。
#5
1
I had the same doubt and found a way to get tests going for inner functions.
我有同样的疑问,并找到了一种方法来测试内部函数。
def outer():
def inner():
pass
if __debug__:
test_inner(inner)
# return
def test_inner(f):
f() # this calls the inner function
outer()
Basically you can send the inner function as a parameter to the outside and test it as you wish. When calling outer(), your test will run, and since it's a closure, it will preserve any extra property from the outer function (like variables). Using a list, you can send as many functions as you wish. To ignore the if, an option is to run the code like that:
基本上你可以将内部函数作为参数发送到外部并根据需要进行测试。当调用outer()时,你的测试会运行,因为它是一个闭包,它将保留外部函数的任何额外属性(如变量)。使用列表,您可以发送任意数量的功能。要忽略if,一个选项是运行如下代码:
python -O code.py
#6
1
I have written a small helper module which allows exactly this:
我写了一个小助手模块,它允许这样:
Examples of nested functions:
嵌套函数的示例:
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()
These can be unit tested using this kind of code:
这些可以使用这种代码进行单元测试:
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))
The small helper module nested
looks like this:
嵌套的小帮助器模块如下所示:
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))
#1
5
The Python convention is to name "private" functions and methods with a leading underscore. When you see a leading underscore, you know not to try and use it.
Python惯例是使用前导下划线命名“私有”函数和方法。当您看到前导下划线时,您知道不要尝试使用它。
Remember, Python is not Java.
请记住,Python不是Java。
#2
11
inner doesn't exist until outer makes it. You should either move inner up to a toplevel function for testability, or have the outer test test all the possible execution paths of itself and inner.
内在不存在,直到外在它。您应该将内部向上移动到顶层函数以实现可测试性,或者让外部测试测试其自身和内部的所有可能的执行路径。
Do note that the inner function isn't a simple function, it's a closure. Consider this case:
请注意,内部函数不是一个简单的函数,它是一个闭包。考虑这种情况:
def outer(a):
b = compute_something_from(a)
def inner():
do_something_with(a, b)
That's the standard testability trade-off. If your cyclomatic complexity is too high, your tests will be too numerous.
这是标准的可测试性权衡。如果您的圈复杂度太高,那么您的测试将会太多。
#3
2
No way to get inner function from outer function object (see the other replies!). Yet both unit tests and closures have made (for me at least) amazing developer performance improvements. Can we have both? Can we test nested functions in isolation?
无法从外部函数对象获取内部函数(请参阅其他回复!)。然而,单元测试和闭包都使(至少对我来说)开发人员的性能有了惊人的提升。我们可以同时拥有吗?我们可以单独测试嵌套函数吗?
Not easily.
However, such could seemingly be achieved with use of python modules parser, ast, or tokenizer to dice up the code itself, extracting inner functions (by some path through the nesting), and allowing tests to run them with state from enclosing functions (values for closed-over names) and stubs/mocks for more-nested functions (defined within the test target).
然而,这似乎可以通过使用python模块解析器,ast或tokenizer来实现代码本身,提取内部函数(通过嵌套的某些路径),并允许测试使用封闭函数的状态运行它们(值对于更多嵌套函数(在测试目标中定义),用于封闭式名称和存根/模拟。
Anybody know of anything like this? Googling failed to find anything.
有人知道这样的事吗?谷歌搜索没有找到任何东西。
#4
1
I don't think that there is any chance to access inner() from the extern namespace.
我认为没有机会从extern命名空间访问inner()。
However, in my opinion the fact that you keep inner() nested implies that the only "contract" that really matters is outer()'s one. inner() is part of the implementation, and you shouldn't want to test the implementation. If you really want to test inner(), do extensive tests on outer() with data that will involve all the functionalities of inner().
但是,在我看来,你保持inner()嵌套这一事实意味着真正重要的唯一“契约”是outer()的一个。 inner()是实现的一部分,您不应该测试实现。如果你真的想测试inner(),那么对outer()进行大量测试,其中包含涉及inner()所有功能的数据。
#5
1
I had the same doubt and found a way to get tests going for inner functions.
我有同样的疑问,并找到了一种方法来测试内部函数。
def outer():
def inner():
pass
if __debug__:
test_inner(inner)
# return
def test_inner(f):
f() # this calls the inner function
outer()
Basically you can send the inner function as a parameter to the outside and test it as you wish. When calling outer(), your test will run, and since it's a closure, it will preserve any extra property from the outer function (like variables). Using a list, you can send as many functions as you wish. To ignore the if, an option is to run the code like that:
基本上你可以将内部函数作为参数发送到外部并根据需要进行测试。当调用outer()时,你的测试会运行,因为它是一个闭包,它将保留外部函数的任何额外属性(如变量)。使用列表,您可以发送任意数量的功能。要忽略if,一个选项是运行如下代码:
python -O code.py
#6
1
I have written a small helper module which allows exactly this:
我写了一个小助手模块,它允许这样:
Examples of nested functions:
嵌套函数的示例:
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()
These can be unit tested using this kind of code:
这些可以使用这种代码进行单元测试:
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))
The small helper module nested
looks like this:
嵌套的小帮助器模块如下所示:
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))