python - 在函数中将闭包传递给 FunctionType

标签 python testing closures

我有这样的代码:

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

最佳答案

为什么要测试 inner_method?在大多数情况下,您应该只测试公共(public) API 的一部分。 outer_methodA 的公共(public) API 的一部分,所以只测试它。 inner_method 是一个可以更改的实现细节:如果您决定重命名它怎么办?如果您在不修改 outer_method 的外部可见行为的情况下稍微重构它会怎样? A 类的用户无法(轻松)调用 inner_method。单元测试通常只用于测试您类(class)的用户可以调用的东西(我假设这些是用于单元测试的,因为这种粒度的集成测试会很奇怪——同样的原则仍然大部分成立)。

实际上,提取在另一个函数范围内定义的函数时会遇到问题,原因有多种,包括变量捕获。您无法知道 inner_method 是否仅捕获 selfouter_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 上的“private-ish”方法:

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() 来模拟它(其中 aA 被测对象)。

此外,使用 A 类。 parens 是不必要的,除非你有父类。

关于python - 在函数中将闭包传递给 FunctionType,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55282608/

相关文章:

android - 如何访问我的 127.0.0.1 :8000 from android tablet

python - 导入 coremltools 时出错 - 无法导入名称 ParametricSoftPlus

python - 如何使用 python 删除推文/字符串中的用户提及和 url

web-services - 调用测试用例不起作用

javascript - 理解闭包和作用域

Python - 使用 PyQt 进行线程处理

ruby-on-rails - 使用 FactoryGirl 进行 Controller 测试

java - 有没有人使用 SIKULI 来测试他们基于 GUI 的应用程序?

ios - 在 Swift 运行时从闭包中获取参数信息

objective-c - 桥接头是否有可能将 (void (^)(NSError *))block (ObjC) 变成 block : () throws -> () (Swift)?