我们应该如何使用nose测试异常?
我正在用nose测试异常。这里有个例子:
def testDeleteUserUserNotFound(self):
"Test exception is raised when trying to delete non-existent users"
try:
self.client.deleteUser('10000001-0000-0000-1000-100000000000')
# make nose fail here
except UserNotFoundException:
assert True
如果抛出了异常,assert语句会被执行;但如果没有抛出异常,assert语句就不会被执行。
有没有什么可以放在上面那行注释的地方,这样如果没有抛出异常,nose就会报告失败呢?
6 个回答
def testDeleteUserUserNotFound(self):
"Test exception is raised when trying to delete non-existent users"
try:
self.client.deleteUser('10000001-0000-0000-1000-100000000000')
assert False # <---
except UserNotFoundException:
assert True
在编程中,try
和except
的意思是,当你在try
块里遇到错误时,程序会跳出这个块去执行except
块里的代码。所以,如果你在try
里写了assert False
,而之前发生了错误,assert False
就不会被执行。此外,except
块执行完后,程序不会再回到try
块里,所以你不需要担心会出现问题。
↓
(statements)
↓ exception
(try) ↚──────────→ (except)
↓ │
(statements) ←───────────┘
↓
我强烈推荐使用 assert_raises
和 assert_raises_regexp
,这两个工具来自 nose.tools
,它们的功能和 assertRaises
以及 assertRaisesRegexp
是一样的。这样你就可以在不使用 unittest.TestCase
类的测试中,享受到同样的功能。
我觉得 @raises
这个工具太简单粗暴了。下面的代码展示了这个问题:
from nose.tools import *
something = ["aaa", "bbb"]
def foo(x, source=None):
if source is None:
source = something
return source[x]
# This is fine
@raises(IndexError)
def test1():
foo(3)
# This is fine. The expected error does not happen because we made
# a mistake in the test or in the code. The failure indicates we made
# a mistake.
@raises(IndexError)
def test2():
foo(1)
# This passes for the wrong reasons.
@raises(IndexError)
def test3():
source = something[2] # This is the line that raises the exception.
foo(10, source) # This is not tested.
# When we use assert_raises, we can isolate the line where we expect
# the failure. This causes an error due to the exception raised in
# the first line of the function.
def test4():
source = something[2]
with assert_raises(IndexError):
foo(10, source)
test3
这个测试通过了,但并不是因为 foo
抛出了我们预期的异常,而是因为设置 foo
使用的数据时出错了,抛出了同样的异常。test4
展示了如何使用 assert_raises
来真正测试我们想要测试的内容。第一行的问题会导致 Nose 报错,然后我们可以重写测试,使得这一行可以真正测试我们想要的内容。
@raises
不能测试与异常相关的消息。当我抛出 ValueError
时,通常我希望带上一个有用的提示信息。这里有个例子:
def bar(arg):
if arg: # This is incorrect code.
raise ValueError("arg should be higher than 3")
if arg >= 10:
raise ValueError("arg should be less than 10")
# We don't know which of the possible `raise` statements was reached.
@raises(ValueError)
def test5():
bar(10)
# Yes, we're getting an exception but with the wrong value: bug found!
def test6():
with assert_raises_regexp(ValueError, "arg should be less than 10"):
bar(10)
使用 @raises
的 test5
会通过,但原因是错误的。test6
进行了更细致的测试,揭示出抛出的 ValueError
不是我们想要的那个。
nose 提供了一些工具,用于测试程序中的错误(就像 unittest 一样)。你可以试试这个例子(还可以了解其他工具,访问 Nose 测试工具)
from nose.tools import *
l = []
d = dict()
@raises(Exception)
def test_Exception1():
'''this test should pass'''
l.pop()
@raises(KeyError)
def test_Exception2():
'''this test should pass'''
d[1]
@raises(KeyError)
def test_Exception3():
'''this test should fail (IndexError raised but KeyError was expected)'''
l.pop()
def test_Exception4():
'''this test should fail with KeyError'''
d[1]
我觉得这就是你想要的正确方法,因为它让你可以明确你期望或想要的错误类型。这样你就可以故意制造错误,看看是否能抛出正确的异常。然后你让 nose 来评估结果。(在单元测试中尽量少写逻辑!)