2016-04-09 20 views
15

Tôi đang cố viết một plugin pytest để tùy chỉnh giao diện ngoại lệ cụ thể - cụ thể hơn, ngoại lệ giả mạo (phương pháp được gọi là không được gọi là v.v.), vì có rất nhiều của tiếng ồn vô dụng trong traceback của những trường hợp ngoại lệ.Tùy chỉnh thông báo lỗi cho các trường hợp ngoại lệ cụ thể trong pytest

Đây là những gì tôi đã có cho đến nay, hoạt động, nhưng là cực kỳ hacky:

import pytest 
import flexmock 

@pytest.hookimpl() 
def pytest_exception_interact(node, call, report): 
    exc_type = call.excinfo.type 

    if exc_type == flexmock.MethodCallError: 
     entry = report.longrepr.reprtraceback.reprentries[-1] 
     entry.style = 'short' 
     entry.lines = [entry.lines[-1]] 
     report.longrepr.reprtraceback.reprentries = [entry] 

Tôi nghĩ rằng tôi đang làm điều đúng đắn với hookimpl và kiểm tra các loại ngoại lệ với một đơn giản nếu tuyên bố.

Tôi đã thử thay thế report.longrepr bằng một chuỗi đơn giản, cũng đã hoạt động, nhưng sau đó tôi bị mất định dạng (màu trong thiết bị đầu cuối).

Như một ví dụ về các loại đầu ra tôi muốn rút ngắn, đây là một thất bại khẳng định giả:

=================================== FAILURES ==================================== 
_______________________ test_session_calls_remote_client ________________________ 

    def test_session_calls_remote_client(): 
     remote_client = mock.Mock() 
     session = _make_session(remote_client) 
     session.connect() 
     remote_client.connect.assert_called_once_with() 
     session.run_action('asdf') 
>  remote_client.run_action.assert_called_once_with('asdff') 

tests/unit/executor/remote_test.py:22: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/opt/python-3.6.3/lib/python3.6/unittest/mock.py:825: in assert_called_once_with 
    return self.assert_called_with(*args, **kwargs) 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

_mock_self = <Mock name='mock.run_action' id='139987553103944'> 
args = ('asdff',), kwargs = {}, expected = (('asdff',), {}) 
_error_message = <function NonCallableMock.assert_called_with.<locals>._error_message at 0x7f51646269d8> 
actual = call('asdf'), cause = None 

    def assert_called_with(_mock_self, *args, **kwargs): 
     """assert that the mock was called with the specified arguments. 

      Raises an AssertionError if the args and keyword args passed in are 
      different to the last call to the mock.""" 
     self = _mock_self 
     if self.call_args is None: 
      expected = self._format_mock_call_signature(args, kwargs) 
      raise AssertionError('Expected call: %s\nNot called' % (expected,)) 

     def _error_message(): 
      msg = self._format_mock_failure_message(args, kwargs) 
      return msg 
     expected = self._call_matcher((args, kwargs)) 
     actual = self._call_matcher(self.call_args) 
     if expected != actual: 
      cause = expected if isinstance(expected, Exception) else None 
>   raise AssertionError(_error_message()) from cause 
E   AssertionError: Expected call: run_action('asdff') 
E   Actual call: run_action('asdf') 

/opt/python-3.6.3/lib/python3.6/unittest/mock.py:814: AssertionError 
====================== 1 failed, 30 passed in 0.28 seconds ====================== 
+4

Tôi không thực sự có được những gì bạn muốn đạt được. Bạn có muốn giảm độ sâu của ngăn xếp hoặc để xóa các cuộc gọi cụ thể không? Bạn có thể đưa ra một ví dụ về những gì bạn nhận được và những gì bạn muốn đạt được? –

+1

Vấn đề chính tôi muốn giải quyết là sử dụng thư viện 'mock' /' unittest.mock'/'flexmock' của python, khi các kỳ vọng giả định thất bại, có một dấu vết ngăn xếp chồng lên màn hình, khi" phương thức X không được gọi với đối số Y "sẽ đủ. – Andreas

+6

Bạn có ví dụ về đầu ra trông như thế nào và bạn muốn nó trông như thế nào? – theY4Kman

Trả lời

0

Nếu mục tiêu của bạn là làm cho stacktrace dễ đọc, sau đó bạn có thể sử dụng khối mã bên dưới để xuất thông báo lỗi tùy chỉnh. Thông báo lỗi tùy chỉnh này xuất hiện ở cuối stacktrace, vì vậy bạn không cần phải cuộn lên: with raises(ZeroDivisionError, message="Expecting ZeroDivisionError"): pass --> Failed: Expecting ZeroDivisionError Nguồn: pytest's documentation. Vì vậy, thay vì tạo một plugin, bạn có thể dẫn đầu ra của pytest thông qua một thứ gì đó như grep và lọc ra các phần vô dụng của stacktrace.
Dựa trên những gì tôi đã đọc trong tài liệu bạn đang sử dụng đúng chức năng trang trí và móc chính xác nhất (pytest_exception_interact). Tuy nhiên, loại kiểm tra lỗi có thể là không cần thiết. This section of the documentation nói rằng "Cái móc này chỉ được gọi nếu một ngoại lệ được nêu ra không phải là ngoại lệ bên trong như skip.Exception."

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