2010-10-08 31 views
32

Tôi có một chức năng sau đây trong Python và tôi muốn thử nghiệm với unittest rằng nếu hàm được 0 làm đối số, nó sẽ đưa ra một cảnh báo. Tôi đã cố gắng assertRaises, nhưng kể từ khi tôi không nâng cao cảnh báo, điều đó không hoạt động.Làm thế nào để kiểm tra với Python của unittest rằng một cảnh báo đã được ném?

def isZero(i): 
     if i != 0: 
     print "OK" 
     else: 
     warning = Warning("the input is 0!") 
     print warning 
     return i 

Cảm ơn bạn, Tomas

+0

Về việc làm việc xung quanh * ... nếu cảnh báo đã được đưa ra vì quy tắc một lần/mặc định, thì bất kể bộ lọc nào được đặt cảnh báo sẽ không được nhìn thấy trừ khi cảnh báo đăng ký liên quan đến cảnh báo đã được xóa. * ([tài liệu] (https://docs.python.org/3/library/warnings.html#testing-warnings)) xem [bài viết này] (https://blog.ionelmc.ro/2013/06/26/testing-python-warnings /) về mức mô-đun '__warningregistry__' (các tài liệu đăng ký đề cập). – saaj

Trả lời

30

Bạn có thể sử dụng người quản lý catch_warnings ngữ cảnh. Về cơ bản, điều này cho phép bạn giả lập trình xử lý cảnh báo, để bạn có thể xác minh chi tiết cảnh báo. Xem official docs để có giải thích đầy đủ hơn và mã kiểm tra mẫu.

import warnings 

def fxn(): 
    warnings.warn("deprecated", DeprecationWarning) 

with warnings.catch_warnings(record=True) as w: 
    # Cause all warnings to always be triggered. 
    warnings.simplefilter("always") 
    # Trigger a warning. 
    fxn() 
    # Verify some things 
    assert len(w) == 1 
    assert issubclass(w[-1].category, DeprecationWarning) 
    assert "deprecated" in str(w[-1].message) 
+0

+1. Tiện lợi và hữu ích. –

+0

Lưu ý rằng đây không phải là chủ đề an toàn, bởi vì nó sửa đổi một 'trạng thái toàn cầu' - nếu bạn sử dụng nó trong một bộ kiểm thử và các cảnh báo khác được phát ra, chúng cũng sẽ hiển thị trong' catch_warnings', điều này có thể gây ra âm bản sai. – nlsdfnbch

4

@ire_and_curses 'answer khá hữu ích và, tôi nghĩ, kinh điển. Đây là một cách khác để làm điều tương tự. Điều này đòi hỏi tuyệt vời của Michael Foord Mock library.

import unittest, warnings 
from mock import patch_object 

def isZero(i): 
    if i != 0: 
    print "OK" 
    else: 
    warnings.warn("the input is 0!") 
    return i 

class Foo(unittest.TestCase): 
    @patch_object(warnings, 'warn') 
    def test_is_zero_raises_warning(self, mock_warn): 
     isZero(0) 
     self.assertTrue(mock_warn.called) 

if __name__ == '__main__': 
    unittest.main() 

Tiện lợi patch_object cho phép bạn thử phương pháp warn.

+0

Giải pháp tốt .. – pelson

+0

+1 - Giải pháp này tốt hơn câu trả lời được chấp nhận, vì nó không sử dụng trạng thái toàn cục của thư viện 'cảnh báo' - điều này có thể gây ra âm bản sai. – nlsdfnbch

17

Bạn có thể viết hàm assertWarns của riêng mình để lồng vào bối cảnh catch_warnings. Tôi vừa mới thực hiện nó theo cách sau, với một mixin:

class WarningTestMixin(object): 
    'A test which checks if the specified warning was raised' 

    def assertWarns(self, warning, callable, *args, **kwds): 
     with warnings.catch_warnings(record=True) as warning_list: 
      warnings.simplefilter('always') 

      result = callable(*args, **kwds) 

      self.assertTrue(any(item.category == warning for item in warning_list)) 

Một ví dụ sử dụng:

class SomeTest(WarningTestMixin, TestCase): 
    'Your testcase' 

    def test_something(self): 
     self.assertWarns(
      UserWarning, 
      your_function_which_issues_a_warning, 
      5, 10, 'john', # args 
      foo='bar'  # kwargs 
     ) 

Xét nghiệm này sẽ vượt qua khi có ít nhất một trong những cảnh báo do your_function là loại UserWarning .

+0

Câu trả lời này worksassertRaisesRegexp (UserWarning, # 'Tệp đầu vào không phải là pdf: Chỉ sử dụng tika', # metac.apply, # self.notpdf) – alemol

+0

Câu trả lời này hoạt động. Tuy nhiên [tài liệu] (https://docs.python.org/2/library/unittest.html#unittest.TestCase.assertRaisesRegexp) nói rằng "Cũng có thể kiểm tra các ngoại lệ và cảnh báo được nêu ra bằng cách sử dụng các phương pháp sau: assertRaises (ngoại lệ, có thể gọi, * args, ** kwds), assertRaises (ngoại lệ) " Vì vậy, tôi đã thử ' assertRaisesRegexp (UserWarning, 'message war', function_which_issues_a_warning, args) 'nhưng thử nghiệm của tôi không thành công: AssertionError: UserWarning không được nêu ra . Ai đó có thể đăng một ví dụ? – alemol

+0

có lẽ đó là tài liệu xấu ... có thể nó hoạt động nếu bạn 'nâng cao UserWarning', nhưng bạn không được phép tăng cảnh báo, bạn được cho là' cảnh báo.warn() 'chúng, do đó cần cho một bắt khác nhau – Anentropic

11

Bắt đầu với Python 3.2, bạn có thể chỉ cần sử dụng phương thức assertWarns().

with self.assertWarns(Warning): 
    do_something() 
Các vấn đề liên quan