2013-02-04 22 views
12

Tôi muốn đảm bảo rằng một điều kiện nhất định trong mã của tôi gây ra một thông điệp tường trình được ghi vào nhật ký django. Làm thế nào tôi sẽ làm điều này với khung kiểm thử đơn vị Django?Làm cách nào để kiểm tra xem một thông báo nhật ký nhất định có được ghi lại trong trường hợp kiểm tra Django không?

Có nơi nào tôi có thể kiểm tra thư đã đăng nhập hay không, tương tự như cách tôi có thể kiểm tra email đã gửi? Thử nghiệm đơn vị của tôi mở rộng django.test.TestCase.

Trả lời

27

Sử dụng mô-đun mock để mô phỏng mô-đun ghi nhật ký hoặc đối tượng trình ghi nhật ký. Khi bạn đã thực hiện điều đó, hãy kiểm tra các đối số có chức năng ghi nhật ký được gọi.

Ví dụ, nếu bạn mã trông như thế này:

import logging 

logger = logging.getLogger('my_logger') 

logger.error("Your log message here") 

nó sẽ trông giống như:

from unittest.mock import patch # For python 2.x use from mock import patch 

@patch('this.is.my.module.logger') 
def test_check_logging_message(self, mock_logger): 
    mock_logger.error.assert_called_with("Your log message here") 
+3

Điều nhỏ ... từ Python 3.3 trở đi, việc nhập cho thử nghiệm phải là 'từ bản vá nhập unittest.mock'. Nếu không, vẫn còn tốt! –

+0

@Simeon Visser làm thế nào để làm điều đó với giả lập, nếu bên trong cuộc gọi đăng nhập, chúng tôi đang đi qua một ngoại lệ? Một cái gì đó như "logger.exception (KeyError ('test'))" Bằng cách này, "assert_called_with" sẽ không bắt được nó vì tôi đoán các tham chiếu cho đối tượng KeyError là khác nhau. (nghĩa là chúng không còn là chuỗi đơn giản nữa). – SpiXel

+3

@SpiXel: bạn có thể xem nội dung của mock_logger.error.call_args_list và đưa ra các xác nhận về các đối số. Ví dụ, nó sẽ là một cái gì đó như: 'assert" Test "trong str (my_logging_argument)' hoặc 'self.assertEqual (str (my_logging_argument)," KeyError ('test') "'. Xem: https: //docs.python .org/3/library/unittest.mock.html # unittest.mock.Mock.call_args_list –

3

Cách phổ biến của mocking ra đối tượng logger (xem câu trả lời của chap lộng lẫy Simeon Visser của) là hơi khó khăn ở chỗ nó đòi hỏi các thử nghiệm để thử ra đăng nhập trong tất cả những nơi nó được thực hiện. Điều này là khó xử nếu việc ghi nhật ký đến từ nhiều hơn một mô-đun, hoặc trong mã bạn không sở hữu. Nếu module đăng nhập đến từ tên thay đổi, nó sẽ phá vỡ các bài kiểm tra của bạn.

Gói 'testfixtures' lộng lẫy bao gồm các công cụ để thêm trình xử lý ghi nhật ký nắm bắt tất cả thông điệp nhật ký được tạo, bất kể chúng đến từ đâu. Các tin nhắn được chụp sau đó có thể được thẩm vấn bằng thử nghiệm. Trong hình thức của nó đơn giản nhất:

Giả sử mã dưới kiểm tra, trong đó ghi:

import logging 
logger = logging.getLogger() 
logger.info('a message') 
logger.error('an error') 

Xét nghiệm này sẽ là:

from testfixtures import LogCapture 
with LogCapture() as l: 
    call_code_under_test() 
l.check(
    ('root', 'INFO', 'a message'), 
    ('root', 'ERROR', 'an error'), 
) 

Từ 'root' cho thấy khai thác gỗ đã được gửi thông qua một logger tạo ra bằng cách sử dụng logging.getLogger() (tức là không có args.) Nếu bạn vượt qua một arg để getLogger (__name__ là thông thường), arg đó sẽ được sử dụng thay cho 'root'.

Kiểm tra không quan tâm mô-đun nào đã tạo nhật ký. Nó có thể là một mô-đun phụ được gọi là mã của chúng tôi dưới sự kiểm tra, bao gồm cả mã bên thứ 3.

Bài kiểm tra xác nhận về thông điệp nhật ký thực tế được tạo, trái ngược với kỹ thuật chế nhạo, xác nhận về các số thập phân đã được chuyển. Chúng sẽ khác nếu cuộc gọi logging.info sử dụng các chuỗi định dạng '% s' với các đối số bổ sung mà bạn không tự mở rộng (ví dụ: sử dụng logging.info('total=%s', len(items)) thay vì logging.info('total=%s' % len(items)), mà bạn nên làm. chẳng hạn như 'Sentry' để hoạt động đúng - họ có thể thấy rằng "total = 12" và "total = 43" là hai trường hợp của cùng một thông điệp tường trình. Đó là lý do tại sao pylint cảnh báo về dạng sau của cuộc gọi logging.info.)

LogCapture bao gồm các cơ sở để lọc nhật ký và tương tự. Gói phụ huynh 'testfixtures' của nó, được viết bởi Chris Withers, một chap lộng lẫy khác, bao gồm nhiều công cụ kiểm tra hữu ích khác.Tài liệu là ở đây: http://pythonhosted.org/testfixtures/logging.html

+0

Làm việc tốt Jonathan! :) –

0

Nếu bạn đang sử dụng các lớp kiểm tra, bạn có thể sử dụng giải pháp sau đây:

import logger 

from django.test import TestCase 


class MyTest(TestCase): 
    @classmethod 
    def setUpClass(cls): 
     super(MyTest, cls).setUpClass() 
     cls.logging_error = logging.error 
     logging.error = cls._error_log 

    @classmethod 
    def tearDownClass(cls): 
     super(MyTest, cls).tearDownClass() 
     logging.error = cls.logging_error 

    @classmethod 
    def _error_log(cls, msg): 
     cls.logger = msg 

    def test_logger(self): 
     self.assertIn('Message', self.logger) 

phương pháp này thay thế error chức năng của logging mô-đun với phương pháp tùy chỉnh của bạn chỉ dành cho mục đích thử nghiệm và đưa vào stdout cls.logger biến có sẵn trong mọi trường hợp kiểm tra bằng cách gọi self.logger. Cuối cùng, nó hoàn nguyên các thay đổi bằng cách đặt hàm error từ logging mô-đun trở lại.

+0

Tôi nghĩ bạn nên sử dụng hàm 'mock.patch' thay vì' setUpClass' và 'tearDownClass'. –

1

Bạn cũng có thể sử dụng assertLogs từ django.test.TestCase

Khi bạn đang

import logging 

logger = logging.getLogger('my_logger') 

def code_that_throws_error_log(): 
    logger.error("Your log message here") 

Đây là mã kiểm tra.

Điều này cho phép bạn tránh vá chỉ dành cho nhật ký.

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