Skip to content

Commit

Permalink
exceptions raised inside QtVirtual methods now make tests fail
Browse files Browse the repository at this point in the history
fixes #11
  • Loading branch information
nicoddemus committed May 31, 2014
1 parent 7b0a65a commit d1fd7c0
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 5 deletions.
30 changes: 30 additions & 0 deletions pytestqt/_tests/test_exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import pytest
from pytestqt.qt_compat import QtGui, Qt, QtCore


class Receiver(QtCore.QObject):

def __init__(self, raise_error, *args, **kwargs):
QtCore.QObject.__init__(self, *args, **kwargs)
self._raise_error = raise_error


def event(self, ev):
if self._raise_error:
raise ValueError('mistakes were made')
return QtCore.QObject.event(self, ev)


@pytest.mark.parametrize('raise_error', [False, pytest.mark.xfail(True)])
def test_catch_exceptions_in_virtual_methods(qtbot, raise_error):
"""
Catch exceptions that happen inside Qt virtual methods and make the
tests fail if any.
"""
v = Receiver(raise_error)
app = QtGui.QApplication.instance()
app.sendEvent(v, QtCore.QEvent(QtCore.QEvent.User))
app.sendEvent(v, QtCore.QEvent(QtCore.QEvent.User))
app.processEvents()


47 changes: 42 additions & 5 deletions pytestqt/plugin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from contextlib import contextmanager
import sys
import traceback

import pytest
from pytestqt.qt_compat import QtGui

from pytestqt.qt_compat import QtGui
from pytestqt.qt_compat import QtTest


Expand Down Expand Up @@ -208,9 +213,30 @@ def stopForInteraction(self):
stop = stopForInteraction


@contextmanager
def _capture_exceptions(self):
"""
Context manager that captures exceptions that happen insides it context,
and returns them as a list of (type, value, traceback) after the
context ends.
"""
result = []

def hook(type_, value, tback):
result.append((type_, value, tback))
sys.__excepthook__(type_, value, tback)

sys.excepthook = hook
try:
yield result
finally:
sys.excepthook = sys.__excepthook__


def pytest_configure(config):
"""
PyTest plugin API. Called before the start of each test session.
PyTest plugin API. Called before the start of each test session, used
to instantiate the qApplication object that will be used for the session.
:param config.Config config:
"""
Expand All @@ -226,7 +252,7 @@ def exit_qapp():
config._cleanup.append(exit_qapp)


@pytest.fixture
@pytest.yield_fixture
def qtbot(request):
"""
Fixture used to create a QtBot instance for using during testing.
Expand All @@ -235,6 +261,17 @@ def qtbot(request):
that they are properly closed after the test ends.
"""
result = QtBot(request.config.qt_app_instance)
request.addfinalizer(result._close)
return result
with result._capture_exceptions() as exceptions:
yield result

if exceptions:
message = 'Qt exceptions in virtual methods:\n'
message += '_' * 80 + '\n'
for (exc_type, value, tback) in exceptions:
message += ''.join(traceback.format_tb(tback)) + '\n'
message += '%s: %s\n' % (exc_type.__name__, value)
message += '_' * 80 + '\n'
pytest.fail(message)

result._close()

0 comments on commit d1fd7c0

Please sign in to comment.