2011-10-17 27 views
24

Tôi đang thử nghiệm ngoại lệ bằng mũi. Dưới đây là ví dụ:Chúng ta nên kiểm tra ngoại lệ bằng mũi như thế nào?

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 

Xác nhận được thực thi nếu ngoại lệ được nêu ra, nhưng nếu không có ngoại lệ, nó sẽ không được thực thi.

Có điều gì tôi có thể đặt trên dòng nhận xét ở trên để nếu không có ngoại lệ được nâng lên, mũi sẽ báo cáo lỗi không?

+0

gần như là một sự lừa đảo của http://stackoverflow.com/questions/11767938/how-to-use-noses-assert-raises – Stefano

Trả lời

39

mũi cung cấp công cụ cho test exceptions (như unittest không). Hãy thử ví dụ này (và đọc về các công cụ khác tại 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] 

tôi sẽ nghĩ rằng đây là cách thích hợp mà bạn đang tìm kiếm bởi vì nó cho phép bạn được cụ thể về các trường hợp ngoại lệ mà bạn mong đợi hoặc muốn Vì vậy, bạn thực sự gây ra lỗi để thấy rằng nó làm tăng ngoại lệ đúng và sau đó bạn để cho mũi đánh giá kết quả. (Đặt ít logic vào các bài kiểm tra đơn vị càng tốt!)

+4

Cảm ơn bạn. Có 'assert_raises' cũng như vẻ bề ngoài. – BartD

+2

mũi cũng cho thấy các assert_raises mà chỉ là self.assertRaises từ unittest. Đó là một trong những thuận tiện cho khi bạn cần phải làm nhiều hơn với các ngoại lệ trong các hình thức. với assertRaises (ValueError) là e:

1

Tôi không biết mũi là gì, nhưng bạn đã thử sử dụng 'else' sau mệnh đề ngoại trừ chưa. I E.

else: 
    assert False 
8
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 

Ngữ nghĩa của try/except ngụ ý rằng các luồng thực hiện rời khỏi khối try trên một ngoại lệ, vì vậy assert False sẽ không chạy nếu một ngoại lệ xảy ra. Ngoài ra, việc thực thi sẽ không nhập lại khối try sau khi khối except được thực hiện đang chạy, vì vậy bạn không nên gặp rắc rối.

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

Tôi không biết tại sao nó chưa có ở đây nhưng tồn tại một cách khác:

import unittest 

class TestCase(unittest.TestCase): 

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

Cơ chế này không được đề cập vì bài đăng cụ thể về thử nghiệm với nosetests, không yêu cầu người dùng của lớp hoặc thừa kế từ 'unittests.TestCase' (lớp xác định' assertRaises' phương pháp bạn đề cập đến). – PeterJCLaw

2

Sử dụng 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) 

dùng thử và nắm bắt trong các thử nghiệm của bạn có vẻ như thực tế xấu (hầu hết các trường hợp).

Không có tài liệu hướng dẫn cụ thể trong mũi vì nó thực chất chỉ là một wrapper quanh unittest.TestCase.assertRaises (ref. How to use nose's assert_raises?)

4

tôi khuyên bạn sử dụng assert_raisesassert_raises_regexp từ nose.tools, mà lặp lại trong các hành vi của assertRaisesassertRaisesRegexp từ unittest.TestCase. Chúng cho phép sử dụng cùng chức năng như được cung cấp bởi unittest.TestCase trong các bộ thử nghiệm không thực sự sử dụng lớp unittest.TestCase.

Tôi thấy rằng @raises là quá cùn một công cụ. Dưới đây là mã minh họa vấn đề:

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 đèo, nhưng không phải vì foo đã quyên góp được ngoại trừ chúng tôi mong đợi nhưng vì mã mà thiết lập các dữ liệu được sử dụng bởi foo thất bại với cùng một ngoại lệ.test4 cho biết cách kiểm tra có thể được viết bằng cách sử dụng assert_raises để thực sự kiểm tra những gì chúng tôi muốn thử nghiệm. Vấn đề trên dòng đầu tiên sẽ khiến Mũi báo cáo lỗi và sau đó chúng tôi có thể viết lại bài kiểm tra sao cho dòng đó để chúng tôi cuối cùng có thể kiểm tra những gì chúng tôi đã làm có nghĩa là để kiểm tra.

@raises không cho phép kiểm tra thư được liên kết với ngoại lệ. Khi tôi nâng cao ValueError, chỉ để lấy một ví dụ, tôi thường muốn nâng cao nó bằng một thông báo mang tính thông tin. Dưới đây là một ví dụ:

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 trong đó sử dụng @raises sẽ vượt qua, nhưng nó sẽ vượt qua với lý do sai lầm. test6 thực hiện một bài kiểm tra tốt hơn cho thấy rằng số ValueError được nêu ra không phải là điều chúng tôi muốn.

Các vấn đề liên quan