这个 DeprecationWarning ("callable is None") 是什么意思?

4
我正在编写一个模块,并使用unittest来编写与实际代码一起的单元测试。
有时候(似乎几乎是随机的),像下面这样没有明确返回值的函数,在使用self.assertRaises(mymodule.MyEmptyException, myfunc())(其中self指的是unittest.TestCase的子类)进行断言时会引发神秘的DeprecationWarning警告。
以下是一个此类函数的示例:
def insertn(self, items, lidex):
    """( z y x -- z b y x )
    add a list of items to the stack at the given index"""
    iter(items)
    for idx, obj in enumerate(items):
        self.insert(lidex, obj)
        lidex += 1

对应的单元测试:

def test_insertn_fail(self):
    """expect failure during multiple insertion"""
    self.assertRaises(mouse16.BadInternalCallException,
        stack.insertn([8, 4, 12], 16))
    with self.assertRaises(TypeError):
        stack.insertn(8, 16)

提供(例如):

./mousetesting.py:103: DeprecationWarning: callable is None

我认为使函数具有非None返回值可能会解决问题(例如:return 0),但然后我会得到以下结果:

======================================================================
ERROR: test_insertn_fail (__main__.CoreStack)
expect failure during multiple insertion
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./mousetesting.py", line 103, in test_insertn_fail
    stack.insertn([8, 4, 12], 16))
  File "/usr/lib/python3.5/unittest/case.py", line 727, in assertRaises
    return context.handle('assertRaises', args, kwargs)
  File "/usr/lib/python3.5/unittest/case.py", line 176, in handle
    callable_obj(*args, **kwargs)
TypeError: 'int' object is not callable

----------------------------------------------------------------------

所以unittest模块试图调用函数的返回值......但没有抱怨None 也不是 callable
我对Python内部的工作原理不够了解,无法理解这里发生了什么。我希望避免由于忽略DeprecationWarning而导致测试在未来出现无法修复的故障。
我的函数(但只有一些,而且不是所有时?)必须返回(占用内存的)闭包或毫无意义的lambda表达式以避免这种情况吗?或者我应该创建一个检测测试是否进行并且然后仅返回no-op lambda的东西?这似乎是为了避免DeprecationWarning而做很多工作。

请提供一个展示问题的 [mcve](即使只是偶尔出现问题)。你的问题在一处提到了 assertEqual(),但是你提供的 traceback 使用了 assertRaises() 上下文管理器。 - Martijn Pieters
@MartijnPieters 啊,我没有注意到,抱歉。我会修复它的。 - cat
1个回答

8
您在错误地使用 self.assertRaises()。 它必须为您调用测试函数,以便捕获异常:
self.assertRaises(mouse16.BadInternalCallException,
    stack.insertn, [8, 4, 12], 16)

您传递了stack.insertn()调用的结果(它没有引发异常,但返回值可能是None或整数),而该返回值不可调用。旧版本的方法也接受None作为该参数,但不再支持,因此当传入None而不是整数时会出现弃用警告。
更好的方法是使用self.assertRaises()作为上下文管理器:
with self.assertRaises(mouse16.BadInternalCallException):
    stack.insertn([8, 4, 12], 16)

这太简单了,我从来没有想过参数是分开的。 - cat
我目前仅使用“with”上下文管理器来处理需要测试是否引发了“SystemExit”的情况,但为了清晰起见,我可能会在任何地方都使用它。 - cat
1
@cat:非上下文管理器版本是在语言中添加上下文管理器之前传递函数而不调用它的版本。使用该方法作为上下文管理器要优于旧方法,因此应优先考虑使用。 - Martijn Pieters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接