Skip to content

Commit 70437e3

Browse files
committed
Capture exceptions during test teardown
Fixes #65
1 parent 1a29606 commit 70437e3

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

pytestqt/_tests/test_exceptions.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import pytest
22
import sys
3-
from pytestqt.plugin import format_captured_exceptions
3+
from pytestqt.plugin import format_captured_exceptions, QT_API
44

55

66
pytest_plugins = 'pytester'
@@ -58,6 +58,8 @@ def test_format_captured_exceptions():
5858

5959

6060
@pytest.mark.parametrize('no_capture_by_marker', [True, False])
61+
@pytest.mark.skipif(QT_API == 'pyqt5', reason='non captured exceptions on PyQt'
62+
' 5.5+ crash the interpreter.')
6163
def test_no_capture(testdir, no_capture_by_marker):
6264
"""
6365
Make sure options that disable exception capture are working (either marker
@@ -90,3 +92,34 @@ def test_widget(qtbot):
9092
'''.format(marker_code=marker_code))
9193
res = testdir.inline_run()
9294
res.assertoutcome(passed=1)
95+
96+
97+
def test_exception_capture_on_teardown(testdir):
98+
"""
99+
Exceptions should also be captured during test teardown.
100+
101+
:type testdir: TmpTestdir
102+
"""
103+
testdir.makepyfile('''
104+
import pytest
105+
from pytestqt.qt_compat import QWidget, QtCore, QEvent
106+
107+
class MyWidget(QWidget):
108+
109+
def event(self, ev):
110+
raise RuntimeError('event processed')
111+
112+
def test_widget(qtbot, qapp):
113+
w = MyWidget()
114+
# keep a reference to the widget so it will lives after the test
115+
# ends. This will in turn trigger its event() during test tear down,
116+
# raising the exception during its event processing
117+
test_widget.w = w
118+
qapp.postEvent(w, QEvent(QEvent.User))
119+
''')
120+
res = testdir.runpytest('-s')
121+
res.stdout.fnmatch_lines([
122+
"*RuntimeError('event processed')*",
123+
'*1 error*',
124+
])
125+

pytestqt/plugin.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -544,8 +544,7 @@ def qtbot(qapp, request):
544544
that they are properly closed after the test ends.
545545
"""
546546
result = QtBot()
547-
no_capture = request.node.get_marker('qt_no_exception_capture') or \
548-
request.config.getini('qt_no_exception_capture')
547+
no_capture = _exception_capture_disabled(request.node)
549548
if no_capture:
550549
yield result # pragma: no cover
551550
else:
@@ -557,6 +556,13 @@ def qtbot(qapp, request):
557556
result._close()
558557

559558

559+
def _exception_capture_disabled(item):
560+
"""returns if exception capture is disabled for the given test item.
561+
"""
562+
return item.get_marker('qt_no_exception_capture') or \
563+
item.config.getini('qt_no_exception_capture')
564+
565+
560566
def pytest_addoption(parser):
561567
parser.addini('qt_no_exception_capture',
562568
'disable automatic exception capture')
@@ -581,15 +587,21 @@ def pytest_addoption(parser):
581587

582588

583589
@pytest.mark.hookwrapper
584-
def pytest_runtest_teardown():
590+
def pytest_runtest_teardown(item):
585591
"""
586592
Hook called after each test tear down, to process any pending events and
587593
avoiding leaking events to the next test.
588594
"""
589595
yield
590596
app = QApplication.instance()
591597
if app is not None:
592-
app.processEvents()
598+
if _exception_capture_disabled(item):
599+
app.processEvents()
600+
else:
601+
with capture_exceptions() as exceptions:
602+
app.processEvents()
603+
if exceptions:
604+
pytest.fail('TEARDOWN ERROR: ' + format_captured_exceptions(exceptions))
593605

594606

595607
def pytest_configure(config):

0 commit comments

Comments
 (0)