我们应该如何用鼻子测试异常?

时间:2011-10-17 21:09:19

标签: python testing 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,但如果没有引发异常,则不会执行。

我可以在上面的注释行中添加任何内容,以便如果没有异常,则会报告失败吗?

6 个答案:

答案 0 :(得分:45)

nose 提供了测试异常的工具(比如unittest)。 试试这个例子(并阅读Nose Testing Tools

中的其他工具
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]

我认为这是您正在寻找的正确方式,因为它可以让您具体了解您期望或想要的异常。所以你实际上引发了错误,看到它引发了正确的异常。然后你让鼻子评估结果。 (尽可能少地将逻辑放入单元测试中!)

答案 1 :(得分:9)

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块留在异常上,因此如果引发异常,assert False将不会运行。此外,在try块运行完毕后,执行不会再次重新进入except块,因此您不应该遇到麻烦。

     ↓
(statements)
     ↓    exception
   (try) ↚──────────→ (except)
     ↓                   │
(statements) ←───────────┘
     ↓

答案 2 :(得分:9)

我强烈建议您使用assert_raises中的assert_raises_regexpnose.toolsunittest.TestCaseunittest.TestCase的{​​{3}}和assertRaises的行为相同。这些允许使用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显示了如何使用@raises来编写测试来实际测试我们要测试的内容。第一行的问题会导致Nose报告错误,然后我们可以重写测试,以便我们可以最终测试我们测试的意思。

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) 时,举一个例子,我通常想要提供一条信息性的信息。这是一个例子:

test5
使用@raises

test6会通过,但会因错误原因而通过。 ValueError执行更精细的测试,结果显示val max: Option[Int] = Seq(l1, l2, l3, l4).flatten.reduceOption(_ max _) 筹集的不是我们想要的。

答案 3 :(得分:7)

我不知道为什么它不在这里,但又存在一种方式:

import unittest

class TestCase(unittest.TestCase):

    def testKeyError(self):
        d = dict()
        with self.assertRaises(KeyError):
            d[1]

答案 4 :(得分:3)

使用assert_raises

from nose.tools import assert_raises

our_method         = self.client.deleteUser
arg1               = '10000001-0000-0000-1000-100000000000'
expected_exception = UserNotFoundException

assert_raises(expected_exception, our_method, arg1)

在测试中使用try和catch似乎是不好的做法(大多数情况下)。

鼻子中没有特定的文档,因为它基本上只是unittest.TestCase.assertRaises的一个包装(参考How to use nose's assert_raises?

答案 5 :(得分:1)

我不知道鼻子是什么,但你是否尝试在except子句后使用'else'。即

else:
    assert False