TextCtrl: Emulating key events in wxPython 4

1,310 views
Skip to first unread message

Pyfips

unread,
Jul 11, 2019, 10:32:08 AM7/11/19
to wxPython-users
Hello again,

I am trying to test my dialogs in wxPython programmatically. For this, I am emitting the events of wxPython like this:

wx.PostEvent(element, wx.CommandEvent(wx.EVT_BUTTON._getEvtType(), element.GetId()))
wx.Yield()

Currently, I am stuck with emitting events for TextCtrls.

I have tried to...
* Post a key event.
charHookEvent = wx.KeyEvent(wx.EVT_CHAR_HOOK._getEvtType())
charHookEvent.SetEventObject(element)
event = DummyKeyEvent(wx.EVT_KEY_DOWN._getEvtType())

The corresponding function in my dialog is called, however, the keycode is 0 and I have no chance to set it (I tried to override the KeyEvent and override the methods GetKeyCode() etc.)

* I tried to hand the KeyEvent over to <TextCtrl>.EmulateKeyPress, but this somehow does nothing.
* I took a look at wx.UIActionSimulator. This works for me if the dialog is shown. But if the dialog is not shown, the function outputs text to my IDE (or whatever other application currently has the focus).

A third way would be to directly call SetValue, but than I may have a different behaviour of the dialog in my test. The disadvantage is, that I cannot test keyboard shortcuts like Ctrl+S etc. like this.

Is there anything I am missing?

Thank you for your help and best regards

Robin Dunn

unread,
Jul 12, 2019, 11:26:35 AM7/12/19
to wxPython-users
On Thursday, July 11, 2019 at 7:32:08 AM UTC-7, Pyfips wrote:
Hello again,

I am trying to test my dialogs in wxPython programmatically. For this, I am emitting the events of wxPython like this:

wx.PostEvent(element, wx.CommandEvent(wx.EVT_BUTTON._getEvtType(), element.GetId()))
wx.Yield()

Currently, I am stuck with emitting events for TextCtrls.

I have tried to...
* Post a key event.
charHookEvent = wx.KeyEvent(wx.EVT_CHAR_HOOK._getEvtType())
charHookEvent.SetEventObject(element)
event = DummyKeyEvent(wx.EVT_KEY_DOWN._getEvtType())

The corresponding function in my dialog is called, however, the keycode is 0 and I have no chance to set it (I tried to override the KeyEvent and override the methods GetKeyCode() etc.)

I keep forgetting to do it, so I've added an issue to help me remember to graft the setter methods for the (c++) public attributes back into the wx.KeyEvent class. https://github.com/wxWidgets/Phoenix/issues/1306
 

* I tried to hand the KeyEvent over to <TextCtrl>.EmulateKeyPress, but this somehow does nothing.
* I took a look at wx.UIActionSimulator. This works for me if the dialog is shown. But if the dialog is not shown, the function outputs text to my IDE (or whatever other application currently has the focus).

A third way would be to directly call SetValue, but than I may have a different behaviour of the dialog in my test. The disadvantage is, that I cannot test keyboard shortcuts like Ctrl+S etc. like this.

Is there anything I am missing?


Testing GUIs is hard. Most people (including me) would say that the best bet is to fully decouple the UI from the rest of the application. IOW, make it so your event handlers do nothing but invoke other parts of your application that are designed to be testable, using something like the mock package when needed to make the rest of the application think that the GUI is there. Then, if needed, you can do the opposite and mock the parts of the application API needed for testing the UI.

Of course that is not always easy to do, especially if there is already a lot of highly coupled UI code. If you're on Windows then there are tools like AutoHotKey that can be used to inject key and mouse events into an application at a low enough level that wxWidgets, and the native controls themselves,  can't tell them apart from events coming from a real user. There are similar tools for the other platforms but I'm not recalling their names at the moment.

--
Robin


Dietmar Schwertberger

unread,
Jul 12, 2019, 3:19:44 PM7/12/19
to wxpytho...@googlegroups.com
On 11.07.2019 16:32, 'Pyfips' via wxPython-users wrote:
> I am trying to test my dialogs in wxPython programmatically. For this, I
> am emitting the events of wxPython like this:

I don't think that it's worth testing this way, except if you have
software where every GUI misbehaviour costs you a lot of money.

For my purposes it has always been fine to instantiate the dialogs
and call the event handlers.

With some helpers, my test code then looks like this:

self.frame.filemanager.open(self._get_test_file_name('test.xxx'))

self.frame.presenter.set_file_index(4, notify=True)
frame.filemanager.grid.SelectRow(4, False)
frame.filemanager.grid.SelectRow(5, True)

import MY_GUI
MY_GUI.Dialog._add_test( ('callback', ('reference', None, 1), {}) )
MY_GUI.Dialog._add_test( ('callback', ('parameter_filter',
'with_limits', False), {}) )
MY_GUI.Dialog._add_test( ('callback', ('parameter_filter',
'real_parametric', False), {}) )
MY_GUI.Dialog._add_test( ('callback', ('parameter_matching', 'name',
True), {}) )

MY_GUI.Dialog._add_test( "OK" )
self.frame.menu.reports.create_report()

(Sometimes a wx.Yield() may be required in addition.)


The good thing is that this will not just help you testing after
the implementation is done, but it will also save you time during
development.
Just set up the test code to load test data and set up the configuration
for your data processing routine(s).
Then set a break point or wait for an exception and do the development
in the IDE's debugger with full introspection into the live data.


Regards,

Dietmar

Pyfips

unread,
Jul 12, 2019, 4:43:42 PM7/12/19
to wxPython-users
Thank you both for your answers! And thanks for creating the ticket.

I have seen in some Javascript frameworks and enzyme, that testing the GUI without real GUI can work quite well. I was surprised that this also works good in wxpython, exspecially for buttons, layouting, resizing etc. So for "dumb" events - at the moment. And of course for a lot of the logic (like "is the data really transferred to my data object if I press the OK button").
I try to manipulate the GUI the way the user would do, as far as possible. In the best case I would be able to detect forgotten event.Skip() commands that are not propagated to the parent, among other things of course.
And maybe later write some generic tests that can be applied to any dialog (does F1 open the help, does escape close the dialog from every input element, does pressing return behave the same way as hitting the OK button, is the dialog not too big, is it centered on screen etc.)
These are tasks that can be easily applied if the GUI tests are written programmatically, but hard to implement with "real" UI testing applications like Ranorex or others.

Reply all
Reply to author
Forward
0 new messages