如何正确使用单元测试的assertRaises()与NoneType对象
我做了一个简单的测试案例:
def setUp(self):
self.testListNone = None
def testListSlicing(self):
self.assertRaises(TypeError, self.testListNone[:1])
我本来希望这个测试能通过,但却出现了一个异常:
Traceback (most recent call last):
self.assertRaises(TypeError, self.testListNone[:1])
TypeError: 'NoneType' object is unsubscriptable
我以为使用assertRaises会通过,因为会抛出TypeError这个异常。那这是什么原因呢?
4 个回答
通常使用 assertRaises
的方法是调用一个函数:
self.assertRaises(TypeError, test_function, args)
来测试函数调用 test_function(args)
是否会引发一个 TypeError 错误。
但是,self.testListNone[:1]
的问题在于,Python 会立即计算这个表达式,也就是说在调用 assertRaises
方法之前就已经执行了。这么做的原因是希望 test_function
和 args
作为不同的参数传给 self.assertRaises
,这样 assertRaises
就可以在 try...except
代码块中调用 test_function(args)
,从而捕获到异常。
因为你已经定义了 self.testListNone = None
,而且你需要一个可以调用的函数,你可以像这样使用 operator.itemgetter:
import operator
self.assertRaises(TypeError, operator.itemgetter, (self.testListNone,slice(None,1)))
因为
operator.itemgetter(self.testListNone,slice(None,1))
这其实是说 self.testListNone[:1]
的一种冗长方式,但它把函数(operator.itemgetter
)和参数分开了。
这个问题是因为 TypeError
错误在 assertRaises
被调用之前就出现了,因为 assertRaises
的参数需要在调用方法之前先被计算出来。你需要传递一个 lambda
表达式,像这样:
self.assertRaises(TypeError, lambda: self.testListNone[:1])
如果你正在使用Python 2.7或更高版本,你可以利用assertRaises这个功能,它可以作为上下文管理器来使用,你可以这样做:
with self.assertRaises(TypeError):
self.testListNone[:1]
如果你使用的是Python 2.6,除了之前提到的方法,还有另一种方式,就是使用unittest2。这个库是将unittest的新功能移植到Python 2.6上,你可以用上面的代码让它工作。
注意:我非常喜欢unittest的新功能(比如SkipTest、测试发现等),所以我打算尽可能多地使用unittest2。我建议你也这样做,因为在Python 2.6或更低版本中,unittest提供的功能远不如unittest2丰富。