【问题标题】:How do I unit test an __init__() method of a python class with assertRaises()?如何使用 assertRaises() 对 python 类的 __init__() 方法进行单元测试?
【发布时间】:2008-09-17 22:26:37
【问题描述】:

我有一堂课:

class MyClass:
def __init__(self, foo):
    if foo != 1:
        raise Error("foo is not equal to 1!")

并且应该确保传递给构造函数的不正确参数正确引发错误的单元测试:

def testInsufficientArgs(self):
    foo = 0
    self.assertRaises((Error), myClass = MyClass(Error, foo))

但是我明白了……

NameError: global name 'Error' is not defined

为什么?我应该在哪里定义这个错误对象?我以为它是作为默认异常类型内置的,不是吗?

【问题讨论】:

    标签: python unit-testing exception


    【解决方案1】:

    此示例中的“错误”可以是任何异常对象。我想你可能已经阅读了一个代码示例,它使用它作为元语法占位符来表示“适当的异常类”。

    所有异常的基类称为“Exception”,它的大多数子类都是所涉及的错误类型的描述性名称,例如“OSError”、“ValueError”、“NameError”、“TypeError”。

    在这种情况下,适当的错误是“ValueError”(foo 的值是错误的,因此是 ValueError)。我建议在您的脚本中将 'Error' 替换为 'ValueError'。

    这是您尝试编写的代码的完整版本,我正在复制所有内容,因为您的原始示例中有一个奇怪的关键字参数,您似乎将其与作业混为一谈,而我正在使用 ' failUnless' 函数名,因为那是函数的非别名:

    class MyClass:
        def __init__(self, foo):
            if foo != 1:
                raise ValueError("foo is not equal to 1!")
    
    import unittest
    class TestFoo(unittest.TestCase):
        def testInsufficientArgs(self):
            foo = 0
            self.failUnlessRaises(ValueError, MyClass, foo)
    
    if __name__ == '__main__':
        unittest.main()
    

    输出是:

    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.007s
    
    OK
    

    单元测试库“unittest”中存在其他单元测试框架修复的缺陷。您会注意到,不可能从调用上下文中访问异常对象。如果要解决此问题,则必须在 UnitTest 的子类中重新定义该方法:

    这是它的一个使用示例:

    class TestFoo(unittest.TestCase):
        def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
            try:
                callableObj(*args, **kwargs)
            except excClass, excObj:
                return excObj # Actually return the exception object
            else:
                if hasattr(excClass,'__name__'): excName = excClass.__name__
                else: excName = str(excClass)
                raise self.failureException, "%s not raised" % excName
    
        def testInsufficientArgs(self):
            foo = 0
            excObj = self.failUnlessRaises(ValueError, MyClass, foo)
            self.failUnlessEqual(excObj[0], 'foo is not equal to 1!')
    

    我从python2.5的unittest.py中复制了failUnlessRaises函数并稍作修改。

    【讨论】:

    • 这是你出错的地方,这是你想要的,这是你打算编写的代码。这可能是我见过的最好的答案。
    • self.failUnlessRaises 现在已弃用。改用 self.assertRaises。 docs.python.org/2/library/unittest.html#deprecated-aliases
    • @LoveMeSomeCode __init__ 函数通常不返回任何值。我看到的典型的unittests函数,通过函数测试返回值。通常建议您也测试您的__init__ 函数吗?如果是这样,您是否通过直接访问 __init__ 所属的类的实例属性来检查 __init__ 函数内部更改的值?
    • @alpha_989 我想说的是,一般来说,如果 init 函数有任何破坏性行为或与外部源的连接,我会测试它们,例如连接到数据库,打开文件等。我的大多数类只会在那里初始化一些变量,所以我不打扰。不过我很懒惰,通常只是对过去出现问题的东西进行测试。
    【解决方案2】:

    这个怎么样:

    class MyClass:
        def __init__(self, foo):
            if foo != 1:
                raise Exception("foo is not equal to 1!")
    
    import unittest
    
    class Tests(unittest.TestCase):
        def testSufficientArgs(self):
            foo = 1
            MyClass(foo)
    
        def testInsufficientArgs(self):
            foo = 2
            self.assertRaises(Exception, MyClass, foo)
    
    if __name__ == '__main__':
        unittest.main()
    

    【讨论】:

    • 如果您愿意,您可以在顶部将 'class Error' 定义为 Exception 的子类,并在此示例中使用它来代替 Exception。
    【解决方案3】:

    我想你在想Exceptions。将描述中的错误一词替换为异常,你应该很高兴:-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      相关资源
      最近更新 更多