关于python:如何将单元测试的assertraises()正确地用于非类型对象?

How to properly use unit-testing's assertRaises() with NoneType objects?

本问题已经有最佳答案,请猛点这里访问。

我做了一个简单的测试案例:

1
2
3
4
5
6
7
def setUp(self):

  self.testListNone = None

def testListSlicing(self):

  self.assertRaises(TypeError, self.testListNone[:1])

我期待测试通过,但我得到了例外:

1
2
3
4
5
Traceback (most recent call last):

    self.assertRaises(TypeError, self.testListNone[:1])

TypeError: 'NoneType' object is unsubscriptable

我认为断言引发将通过,因为类型错误异常将被抚养?


如果您使用的是python2.7或更高版本,则可以使用assertraise作为上下文管理器,并执行以下操作:

1
2
with self.assertRaises(TypeError):
    self.testListNone[:1]

如果您使用python2.6,除了给出的方法之外,还有一种方法就是使用unittest2,这是unittest的一个后端端口,它是python2.6的新特性,您可以使用上面的代码使其工作。

N.B:我非常喜欢UnitTest的新特性(skiptest、test discovery…),所以我打算尽可能多地使用UnitTest2。我建议这样做,因为在python2.6<中有很多比UnitTest更多的东西。


问题是TypeError在调用assertRaises之前被提出,因为在调用方法之前需要评估assertRaises的参数。你需要传递一个lambda表达式,比如:

1
self.assertRaises(TypeError, lambda: self.testListNone[:1])


使用assertRaises的通常方法是调用函数:

1
self.assertRaises(TypeError, test_function, args)

要测试函数调用test_函数(args)是否引发类型错误。

self.testListNone[:1]的问题是,在调用assertRaises方法之前,python会立即对表达式进行计算。test_functionargs作为单独的参数传递给self.assertRaises的全部原因是允许assertRaisestry...except块内调用test_function(args),允许assertRaises捕获异常。

由于您已经定义了self.testListNone = None,并且需要一个函数来调用,因此可以使用如下operator.itemgetter:

1
2
import operator
self.assertRaises(TypeError, operator.itemgetter, (self.testListNone,slice(None,1)))

自从

1
operator.itemgetter(self.testListNone,slice(None,1))

是说self.testListNone[:1]的一种冗长的方式,但它将函数(operator.itemgetter与参数分开。


完整的代码片段如下所示。它扩展了@mouad对断言错误消息的回答(或通常是str表示其args,这可能有用。

1
2
3
4
5
6
7
8
9
10
11
12
from unittest import TestCase


class TestNoneTypeError(TestCase):

  def setUp(self):
    self.testListNone = None

  def testListSlicing(self):
    with self.assertRaises(TypeError) as ctx:
        self.testListNone[:1]
    self.assertEqual("'NoneType' object is not subscriptable", str(ctx.exception))