Skip to content

Commit de0b795

Browse files
committed
Added methods from QTest and improved documentation
1 parent 6e2337e commit de0b795

File tree

3 files changed

+211
-18
lines changed

3 files changed

+211
-18
lines changed

src/pytestqt/__init__.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
'''
2-
Introduction
3-
============
4-
5-
pytest-qt is a `pytest`_ that provides fixtures to help programmers write
6-
tests for `PyQt`_ and `PySide`_.
7-
8-
.. _pytest: http://www.pytest.org
9-
.. _PyQt: http://www.riverbankcomputing.com/software/pyqt
10-
.. _PySide: https://pypi.python.org/pypi/PySide
2+
`pytest-qt` is a pytest_ plugin that provides fixtures to help programmers write tests for
3+
PySide_ and PyQt_.
114
125
The main usage is to use the ``qtbot`` fixture, which provides methods to simulate user
136
interaction, like key presses and mouse clicks::
@@ -18,10 +11,13 @@ def test_hello(qtbot):
1811
# test away
1912
2013
21-
QtBot Instances
22-
---------------
14+
.. .. literalinclude:: ../src/pytestqt/_tests/test_basics.py
15+
.. :language: python
16+
.. :start-after: # create test widget
2317
24-
.. autoclass:: pytestqt.conftest.QtBot
25-
:members:
18+
19+
.. _pytest: http://www.pytest.org
20+
.. _PySide: https://pypi.python.org/pypi/PySide
21+
.. _PyQt: http://www.riverbankcomputing.com/software/pyqt
2622
2723
'''

src/pytestqt/_tests/test_basics.py

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
from pytestqt.qt_compat import QtGui
1+
from pytestqt.qt_compat import QtGui, Qt, QEvent
22
import pytest
33

44

55
#===================================================================================================
6-
# test_basics
6+
# testBasics
77
#===================================================================================================
8-
def test_basics(qtbot):
8+
def testBasics(qtbot):
99
'''
1010
Basic test that works more like a sanity check to ensure we are setting up a QApplication
1111
properly and are able to display a simple widget.
@@ -20,6 +20,61 @@ def test_basics(qtbot):
2020
assert widget.windowTitle() == 'W1'
2121

2222

23+
#===================================================================================================
24+
# testKeyEvents
25+
#===================================================================================================
26+
def testKeyEvents(qtbot):
27+
'''
28+
Basic key events test.
29+
'''
30+
31+
class MyWidget(QtGui.QWidget):
32+
33+
def __init__(self):
34+
QtGui.QWidget.__init__(self)
35+
self._reset()
36+
37+
def event(self, ev):
38+
if type(ev) is QtGui.QKeyEvent:
39+
self._record(ev)
40+
return True
41+
42+
return False
43+
44+
45+
def _record(self, key_event):
46+
self.type = key_event.type()
47+
self.key = key_event.key()
48+
self.text = key_event.text()
49+
self.modifiers = key_event.modifiers()
50+
51+
52+
def _reset(self):
53+
self.type = None
54+
self.key = None
55+
self.text = None
56+
self.modifiers = None
57+
58+
59+
def assertEvent(self, event_type, key, text, modifiers=Qt.NoModifier):
60+
assert self.type == event_type
61+
assert self.key == key
62+
assert self.text == text
63+
assert self.modifiers == modifiers
64+
self._reset()
65+
66+
67+
# create test widget
68+
widget = MyWidget()
69+
qtbot.addWidget(widget)
70+
71+
qtbot.keyPress(widget, 'a')
72+
widget.assertEvent(QEvent.KeyPress, int(Qt.Key_A), 'a')
73+
74+
qtbot.keyRelease(widget, 'a')
75+
widget.assertEvent(QEvent.KeyRelease, int(Qt.Key_A), 'a')
76+
77+
2378
#===================================================================================================
2479
# main
2580
#===================================================================================================

src/pytestqt/conftest.py

Lines changed: 144 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,106 @@
11
import pytest
22
from pytestqt.qt_compat import QtGui
3+
from pytestqt.qt_compat import QtTest
34

45
#===================================================================================================
56
# QtBot
67
#===================================================================================================
78
class QtBot(object):
89
'''
9-
Responsible for sending events to Qt objects, simulating user input.
10+
Instances of this class are responsible for sending events to `Qt` objects (usually widgets),
11+
simulating user input.
12+
13+
.. important:: Instances of this class should be accessed only by using a ``qtbot`` fixture,
14+
never instantiated directly.
15+
16+
**Widgets**
17+
18+
.. automethod:: addWidget
19+
.. automethod:: waitForWindowShown
20+
21+
**QTest API**
22+
23+
Methods below are forwarded directly to the `QTest API`_. Consult documentation for more
24+
information.
25+
26+
---
27+
28+
Below are methods used to simulate sending key events to widgets:
29+
30+
.. staticmethod:: keyPress(widget, key[, modifier=Qt.NoModifier[, delay=-1]])
31+
.. staticmethod:: keyClick (widget, key[, modifier=Qt.NoModifier[, delay=-1]])
32+
.. staticmethod:: keyClicks (widget, key sequence[, modifier=Qt.NoModifier[, delay=-1]])
33+
.. staticmethod:: keyEvent (action, widget, key[, modifier=Qt.NoModifier[, delay=-1]])
34+
.. staticmethod:: keyPress (widget, key[, modifier=Qt.NoModifier[, delay=-1]])
35+
.. staticmethod:: keyRelease (widget, key[, modifier=Qt.NoModifier[, delay=-1]])
36+
37+
Sends one or more keyword events to a widget.
38+
39+
:param QWidget widget: the widget that will receive the event
40+
41+
:param str|int key: key to send, it can be either a Qt.Key_* constant or a single character string.
42+
43+
.. _keyboard modifiers:
44+
45+
:param Qt.KeyboardModifier modifier: flags OR'ed together representing other modifier keys
46+
also pressed. Possible flags are:
47+
48+
* ``Qt.NoModifier``: No modifier key is pressed.
49+
* ``Qt.ShiftModifier``: A Shift key on the keyboard is pressed.
50+
* ``Qt.ControlModifier``: A Ctrl key on the keyboard is pressed.
51+
* ``Qt.AltModifier``: An Alt key on the keyboard is pressed.
52+
* ``Qt.MetaModifier``: A Meta key on the keyboard is pressed.
53+
* ``Qt.KeypadModifier``: A keypad button is pressed.
54+
* ``Qt.GroupSwitchModifier``: X11 only. A Mode_switch key on the keyboard is pressed.
55+
56+
:param int delay: after the event, delay the test for this miliseconds (if > 0).
57+
58+
59+
.. staticmethod:: keyToAscii (key)
60+
61+
Auxilliary method that converts the given constant ot its equivalent ascii.
62+
63+
:param Qt.Key_* key: one of the constants for keys in the Qt namespace.
64+
65+
:return type: str
66+
:returns: the equivalent character string.
67+
68+
---
69+
70+
Below are methods used to simulate sending mouse events to widgets.
71+
72+
.. staticmethod:: mouseClick (widget, button[, stateKey=0[, pos=QPoint()[, delay=-1]]])
73+
.. staticmethod:: mouseDClick (widget, button[, stateKey=0[, pos=QPoint()[, delay=-1]]])
74+
.. staticmethod:: mouseEvent (action, widget, button, stateKey, pos[, delay=-1])
75+
.. staticmethod:: mouseMove (widget[, pos=QPoint()[, delay=-1]])
76+
.. staticmethod:: mousePress (widget, button[, stateKey=0[, pos=QPoint()[, delay=-1]]])
77+
.. staticmethod:: mouseRelease (widget, button[, stateKey=0[, pos=QPoint()[, delay=-1]]])
78+
79+
Sends a mouse moves and clicks to a widget.
80+
81+
:param QWidget widget: the widget that will receive the event
82+
83+
:param Qt.MouseButton button: flags OR'ed together representing the button pressed.
84+
Possible flags are:
85+
86+
* ``Qt.NoButton``: The button state does not refer to any button (see QMouseEvent.button()).
87+
* ``Qt.LeftButton``: The left button is pressed, or an event refers to the left button. (The left button may be the right button on left-handed mice.)
88+
* ``Qt.RightButton``: The right button.
89+
* ``Qt.MidButton``: The middle button.
90+
* ``Qt.MiddleButton``: he middle button.
91+
* ``Qt.XButton1``: The first X button.
92+
* ``Qt.XButton2``: The second X button.
93+
94+
:param Qt.KeyboardModifier modifier: flags OR'ed together representing other modifier keys
95+
also pressed. See `keyboard modifiers`_.
96+
97+
:param QPoint position: position of the mouse pointer.
98+
99+
:param int delay: after the event, delay the test for this miliseconds (if > 0).
100+
101+
102+
.. _QTest API: http://doc.qt.digia.com/4.7/qtest.html
10103
11-
Instances of this class should be accessed by the ``qtbot`` pytest fixture.
12104
'''
13105

14106
def __init__(self, app):
@@ -38,6 +130,18 @@ def addWidget(self, widget):
38130
Widget to keep track of.
39131
'''
40132
self._widgets.append(widget)
133+
134+
135+
def waitForWindowShown(self, widget):
136+
'''
137+
Waits until the window is shown in the screen. This is mainly useful for asynchronous
138+
systems like X11, where a window will be mapped to screen some time after being asked to
139+
show itself on the screen.
140+
141+
:param QWidget widget:
142+
Widget to wait on.
143+
'''
144+
QtTest.QTest.qWaitForWindowShown(widget)
41145

42146

43147
#===================================================================================================
@@ -76,3 +180,41 @@ def qtbot(request):
76180
request.addfinalizer(result._close)
77181
return result
78182

183+
184+
185+
186+
#===================================================================================================
187+
# Inject QtTest Functions
188+
#===================================================================================================
189+
def _createQTestProxyMethod(method_name):
190+
191+
def result(*args, **kwargs):
192+
method = getattr(QtTest.QTest, method_name)
193+
return method(*args, **kwargs)
194+
195+
result.__name__ = method_name
196+
return staticmethod(result)
197+
198+
# inject methods from QTest into QtBot
199+
method_names = set([
200+
'keyPress',
201+
'keyClick',
202+
'keyClicks',
203+
'keyEvent',
204+
'keyPress',
205+
'keyRelease',
206+
'keyToAscii',
207+
208+
'mouseClick',
209+
'mouseDClick',
210+
'mouseEvent',
211+
'mouseMove',
212+
'mousePress',
213+
'mouseRelease',
214+
215+
216+
])
217+
for method_name in method_names:
218+
method = _createQTestProxyMethod(method_name)
219+
setattr(QtBot, method_name, method)
220+

0 commit comments

Comments
 (0)