在Python构造函数中对异常进行单元测试

时间:2009-06-15 17:10:21

标签: python unit-testing constructor

我只是Python和编程的初学者,对unittest模块有一些疑问。

我有一个类,在__init__方法中我正在做一些断言来检查错误的参数。我想创建一个unittest,在创建新实例时检查这样的AssertionError。

在unittest模块中,可以在调用callable时测试(使用assertRaises)特定异常,但显然这将适用于类的方法。为构造函数运行此类测试的正确方法是什么?

我知道我可以尝试使用错误的参数创建类的实例,并且unittest将报告测试失败,但是在第一次此类异常之后立即停止,即使我可以在多个测试中包装多个测试功能,它看起来并不优雅。

6 个答案:

答案 0 :(得分:17)

  

在unittest模块中,可以在调用callable时测试(使用assertRaises)特定异常,但显然这将适用于类的方法。为构造函数运行此类测试的正确方法是什么?

构造函数本身是可调用的:

self.assertRaises(AssertionError, MyClass, arg1, arg2)

话虽如此,我想回应nosklo和S.Lott关于对参数进行类型检查的担忧。此外,您不应该使用断言来检查函数参数:断言最有用,因为除非您的代码出现内部错误,否则将无法触发健全性检查。此外,当Python以“优化”-O模式运行时,会编译断言语句。如果函数需要对其参数进行某种检查,则应该引发一个正确的异常。

答案 1 :(得分:7)

不要乱用assertRaises。这太复杂了。

这样做

class Test_Init( unittest.TestCase ):
    def test_something( self ):
        try:
            x= Something( "This Should Fail" )
            self.fail( "Didn't raise AssertionError" )
        except AssertionError, e:
            self.assertEquals( "Expected Message", e.message )
            self.assertEquals( args, e.args )

任何其他异常都是普通的测试错误。

另外,不要在__init__方法中混淆太多的前期错误检查。如果有人提供了错误类型的对象,则代码将在正常事件过程中失败并通过正常方式引发正常异常。您不需要“预先筛选”对象。

答案 2 :(得分:2)

不知道这有什么帮助,但我遇到的问题如下:

self.assertRaises(Exception, MyFunction())

问题是我不只是传递MyFunction,而是调用它,导致失败并引发异常。 Myfunction期待一个论点,如果没有任何内容传递,我希望它失败。沮丧我一段时间,直到我弄明白:

self.assertRaises(Exception, MyFunction)

按预期工作。

答案 3 :(得分:1)

嗯,首先,检查错误的参数在python中不是一个好主意。由于某种原因,Python是动态强类型的。

你应该假设参数是好的参数。你永远不会知道你的类'用户'的意图,所以通过检查好的参数是一种限制你的类在更通用实例中的使用的方法。

相反,使用文档字符串和文本定义一个好的API并记录它,并将错误参数的错误自动流向用户。

示例:

def sum_two_values(value_a, value_b):
    return value_a + value_b

好吧,这个例子很愚蠢,但是如果我检查并将值断言为整数,该函数将无法使用浮点数,字符串,列表,除了我的检查之外没有任何理由,所以为什么要先检查?它将自动失败,因为它不起作用的类型,所以你不必担心。

答案 4 :(得分:0)

S.Lott的答案不正确:self.fail()本身会引发异常,然后由以下行中的异常引起:

class NetworkConfigTest1(unittest.TestCase):
    def runTest(self):
        try:
            NetworkConfig("192.168.256.0/24")
            self.fail("Exception expected but not thrown")
        except Exception, error:
            printf("Exception caught: %s" % str(error)
            pass

输出是“Exception expected but not thrown”,但是单元测试没有被标记为失败,即使正在测试的代码还没有被写入!

检查方法是否引发异常的更有效方法是使用:

self.failUnlessRaises([error], [callable], [arguments to callable])

就我而言,我正在测试的类名为NetworkConfig,如果网络描述符无效,构造函数必须抛出异常。有效的是:

class NetworkConfigTest1(unittest.TestCase):
    def runTest(self):
        self.failUnlessRaises(Exception, NetworkConfig, "192.168.256.0/24")

这可以根据需要运行并执行正确的测试。

答案 5 :(得分:0)

如果只想检查构造函数是否引发异常,那么使用lambda会更好:

    def testInsufficientArgs(self):
        self.assertRaises(ValueError, lambda: MyClass(0))

像这样,构造器参数不是“神奇地”设置的(就像@Miles的答案一样),IDE总是可以告诉您构造器的使用位置。