Python 构造函数中异常的单元测试

问题描述 投票:0回答:7

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

我有一堂课,在

__init__
方法中,我正在做一些断言来检查错误的参数。我想创建一个单元测试,在创建新实例时检查此类 AssertionError 。

在unittest模块中,可以在调用可调用对象时测试(使用

assertRaises
)特定异常,但显然这将适用于类的方法。为构造函数运行此类测试的正确方法是什么?

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

python unit-testing constructor
7个回答
19
投票

在unittest模块中,可以在调用可调用对象时测试(使用

assertRaises
)特定异常,但显然这将适用于类的方法。为构造函数运行此类测试的正确方法是什么?

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

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

话虽这么说,我想回应 nosklo 和 S.Lott 对参数进行类型检查的担忧。此外,您不应该使用断言来检查函数参数:断言作为健全性检查最有用,除非代码出现内部错误,否则不会触发断言。此外,当 Python 在“优化”

-O
模式下运行时,断言语句会被编译出来。如果函数需要对其参数进行某种检查,它应该引发适当的异常。


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
投票

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

self.assertRaises(Exception, MyFunction())

问题是我不仅传递了

MyFunction
,还调用了它,导致失败并引发异常。
Myfunction
需要一个参数,如果没有传入任何内容,我希望它失败。让我沮丧了一段时间,直到我弄清楚:

self.assertRaises(Exception, MyFunction)

按预期工作。


1
投票

首先,在 Python 中检查错误的参数并不是一个好主意。 Python 是动态强类型的是有原因的。

你应该假设这些论据都是好的论据。您永远不知道类的用户的意图,因此通过检查良好的参数是限制类在更通用的实例中使用的一种方法。

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

示例:

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

好吧,这个例子很愚蠢,但是如果我检查并断言该值是整数,那么该函数将无法处理浮点数、字符串、列表,除了我的检查之外没有其他原因,那么为什么要首先检查呢?对于无法工作的类型,它会自动失败,因此您不必担心。


1
投票

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

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

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


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

输出是“预期异常但未抛出”,但单元测试并未标记为失败,即使正在测试的代码尚未编写!

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

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

在我的例子中,我正在测试的类称为

NetworkConfig
,如果网络描述符无效,构造函数必须抛出异常。有效的是:

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

这将按预期工作并执行正确的测试。


0
投票

我的做法:

def test_my_func():
    # if you are mocking some library make it throw error
    MagicMock().mock_function.side_effect = Exception("Something went wrong")
    # use unittest.TestCase() instead of self, ValueError is an example
    with unittest.TestCase().assertRaises(ValueError):
        my_func("hello world")
© www.soinside.com 2019 - 2024. All rights reserved.