我有以下代码:
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!
。测试将通过,但它不是一个好的测试。我怎样才能确定这两个例外?
答案 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!',),
)
请注意如何使用assertRaises
的with
上下文管理器表单来访问错误本身。这样您还可以检查是否为错误提供了正确的消息。
*您甚至可以考虑处理 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)
请注意,您的测试现在会失败。我不确定你是否想要测试它。