我有这样的代码:
class A():
def __init__(self, a):
self.a = a
def outer_method(self):
def inner_method():
return self.a +1
return inner_method()
我想为inner_method
编写测试。为此,我正在使用这样的代码:
def find_nested_func(parent, child_name):
"""
Return the function named <child_name> that is defined inside
a <parent> function
Returns None if nonexistent
"""
consts = parent.__code__.co_consts
item = list(filter(lambda x:isinstance(x, CodeType) and x.co_name==child_name, consts ))[0]
return FunctionType(item, globals())
使用find_nested_func(A().outer_method, 'inner_method')
调用它,但是在调用“ FunctionType”时失败,因为无法创建函数,因为在函数停止为内部函数的那一刻,“ self.a”停止存在。我知道构造FunctionType可以将可以解决此问题的闭包作为参数来接受,但是我不知道如何使用它。我该如何通过?
它给出的错误是下一个错误:
return FunctionType(item, globals())
TypeError: arg 5 (closure) must be tuple
答案 0 :(得分:1)
您为什么要测试inner_method
?在大多数情况下,您应该只测试公共API的一部分。 outer_method
是A
的公共API的一部分,因此请对其进行测试。 inner_method
是可以更改的实现细节:如果您决定重命名该怎么办?如果在不修改outer_method
的外部可见行为的情况下稍微对其进行重构,该怎么办?类A
的用户没有(简单)的方法来调用inner_method
。单元测试通常仅用于测试您的类用户可以调用的东西(我假设这些是用于单元测试的,因为集成测试这种细粒度的方法很奇怪,并且大多数情况下仍然适用相同的原理)。
实际上,提取另一个函数范围内定义的函数会遇到问题,原因包括变量捕获。您无法知道inner_method
仅捕获self
还是outer_method
执行某些逻辑并计算inner_method
使用的某些变量。例如:
class A:
def outer_method():
b = 1
def inner_method():
return self.a + b
return inner_method()
此外,您可能在函数定义周围有控制语句,因此如果不运行outer_method
,就无法确定使用哪个定义。例如:
import random
class A:
def outer_method():
if random.random() < 0.5:
def inner_method():
return self.a + 1
else:
def inner_method():
return self.a + 2
return inner_method()
您无法在此处提取inner_method
,因为其中有两个,并且在运行outer_method
之前您不知道实际使用了哪个。
因此,请勿测试inner_method
。
如果inner_method
确实非常复杂,以至于您想单独进行测试(如果这样做,则有原则的测试表明您应该模拟出它的用法,例如,在outer_method
中的用法),然后只需在A
上将其设为“私密的”方法即可:
class A:
def _inner_method(self):
return self.a + 1
def outer_method(self):
return self._inner_method()
有原则的测试表明,您实际上不应该测试下划线方法,但有时有必要这样做。通过这种方式,您可以像测试其他任何方法一样测试_inner_method
。然后,在测试outer_method
时,可以通过执行a._inner_method = Mock()
(其中a
是受测试的A
对象)来模拟它。
此外,使用class A
。除非您有父类,否则不需要括号。