如何断言发出特定异常

时间:2015-11-05 17:30:30

标签: python unit-testing

我有以下代码:

def foo(input):
    if not input.startswith("prefix"):
        raise Exception("input should start with prefix!")
    process(input)

现在我要对这个功能进行单元测试;当input未以"prefix"开头时,它实际上可以抛出异常。这是我的unittest代码:

def test_foo_invalud_type(self):
    self.assertRaises(Exception, foo, 999)

此测试代码的问题是:它捕获异常,但异常是'int' object has no attribute 'startswith',而不是input should start with prefix!。测试将通过,但它不是一个好的测试。我怎样才能确定这两个例外?

4 个答案:

答案 0 :(得分:6)

raise Exception形式非常糟糕 - 尝试在提出异常时更具体。使用这样的一般例外使得很难区分您尝试测试的两种不同情况。

在这种情况下,例如,我认为ValueError最适合foo,因为它是正确的事物类型(字符串),但没有正确的值(开头没有'prefix')。

def foo(input):
    if not input.startswith("prefix"):
        raise ValueError("input should start with prefix!")
    process(input)

这使您可以区分输入错误的类型(由于缺少AttributeError *而引发.startswith):

def test_foo_invalid_type(self):  # note fixed typo in 'invalud'
    self.assertRaises(AttributeError, foo, 999)  # and more specific error
输入错误的

(为ValueError前缀明确提出的'prefix'):

def test_foo_invalid_value(self):
    with self.assertRaises(ValueError) as cm:
       foo('no prefix')
       self.assertEqual(
           cm.exception.args, 
           ('input should start with prefix!',),
       )

请注意如何使用assertRaiseswith上下文管理器表单来访问错误本身。这样您还可以检查是否为错误提供了正确的消息。

*您甚至可以考虑处理 AttributeError中的foo ,并提出TypeError。这似乎更适合"该参数类型错误"

答案 1 :(得分:1)

您正在向函数foo传递一个int,但看起来您想要一个str(因为您在startswith参数上使用input)。您的单元测试应该是:

def test_foo_invalud_type(self):
    self.assertRaises(Exception, foo, '999')

答案 2 :(得分:0)

引发错误的行是:

if not input.startswith("prefix"):

而不是:

    raise Exception("input should start with prefix!")

因为您传递的是int而不是字符串:999而不是'999'

请记住,int,没有属性startswith。

答案 3 :(得分:0)

只需实施并提出自己的例外情况。

class BadStartException(Exception):
    pass

def foo(input):
    if not input.startswith("prefix"):
        raise BadStartException("input should start with prefix!")
    process(input)

def test_foo_invalud_type(self):
    self.assertRaises(BadStartException, foo, 999)

请注意,您的测试现在会失败。我不确定你是否想要测试它。