Hi,
I've been searching in depth, but have not come across anything useful
in the archives or in general on the web. I would like to perform
end-to-end acceptance testing of relax, an open source python program
(http://nmr-relax.com) which uses wxPython for the GUI. The sequence
of operations would be along the lines of:
1). Click on the menu entry File->New.
2). Work through a wizard (here is one problem, as this is a modal
dialog. The other problem is when it is modeless).
3). Fill out a number of text and other controls.
4). Click on an 'execute' button.
5). Wait for number crunching code running in a thread to terminate.
6). Check that the calculated values are what is expected.
One major problem is step 2), as the modal dialog takes over. I've
tried running the app in a thread, or the test of the app in a thread
(http://groups.google.com/group/wxpython-users/browse_thread/thread/d6dbfc7ecff6d49b/2b980fed8fa24770?lnk=gst&q=acceptance+testing#2b980fed8fa24770),
but that doesn't seem to solve the problem. I have also tried to make
this non-modal by calling Show() rather than ShowModal(), but this
also seems to not work. I have pasted some code below which
demonstrates the problem, both with modal and modeless modes.
Using the Python unit testing framework, implementing most of this
sequence is easy using wx.CallAfter() calls to queue up a series of
methods to execute events. But one important part of this testing
would be that events are forced to wait for GUI element to be created.
Is there a way of making queued events wait? Is there a completely
different and better way of doing this testing than in the code below?
Any help would be appreciated.
Cheers,
Edward
from unittest import TestCase, TestLoader, TestSuite, TextTestRunner
import wx
modal_flag = True
class Menu:
"""The menu bar GUI class."""
def __init__(self, gui):
"""Build the menu bar."""
# Store the args.
self.gui = gui
# Create the menu bar GUI item and add it to the main frame.
self.menubar = wx.MenuBar()
self.gui.SetMenuBar(self.menubar)
# The 'File' menu entries.
menu = wx.Menu()
menu.AppendItem(wx.MenuItem(menu, id=1, text="&New\tCtrl+N"))
self.menubar.Append(menu, "&File")
# The 'File' menu actions.
self.gui.Bind(wx.EVT_MENU, self.new, id=1)
def handler_ok(self, event):
# The bug.
self.gui.my_bug = True
print("Triggering bug now")
if not modal_flag:
self.gui.new_wizard.Destroy()
def new(self, event):
# The wizard.
self.gui.new_wizard = wx.Dialog(self.gui, -1, title='New')
# The sizer for the dialog.
sizer = wx.BoxSizer(wx.VERTICAL)
self.gui.new_wizard.SetSizer(sizer)
# Add a button.
ok = wx.Button(self.gui.new_wizard, id=2, label="Ok")
sizer.Add(ok, 1, wx.ALL|wx.EXPAND, 20)
self.gui.Bind(wx.EVT_BUTTON, self.handler_ok, ok)
# Display.
if modal_flag:
self.gui.new_wizard.ShowModal()
self.gui.new_wizard.Destroy()
else:
self.gui.new_wizard.Show()
class Test(TestCase):
def setUp(self):
"""Set up for all the tests."""
# Start the GUI.
self.app = wx.App()
# Build the GUI.
self.gui = wx.Frame(parent=None, id=-1, title="")
# The bug.
self.gui.my_bug = False
# Add a menu.
self.menu = Menu(self.gui)
# Make it the main application component.
self.app.SetTopWindow(self.gui)
def tearDown(self):
"""Cleanup actions."""
# Kill the app.
wx.CallAfter(self.app.Exit)
self.app.MainLoop()
def click_new_analysis(self):
"""Simulate a menu click for a new analysis."""
# The event.
click_event = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, 1)
self.gui.ProcessEvent(click_event)
def click_noe_analysis(self):
"""Simulate the clicking of the NOE button in the new analysis
wizard."""
# The event.
click_event = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, 2)
self.gui.ProcessEvent(click_event)
def test_noe_analysis(self):
"""Test the NOE analysis."""
# Open the new analysis wizard.
wx.CallAfter(self.click_new_analysis)
# Select the NOE analysis.
wx.CallAfter(self.click_noe_analysis)
# Show the GUI.
self.gui.Show()
# Catch the bug.
print("My bug: %s" % self.gui.my_bug)
self.assert_(not self.gui.my_bug)
# Execute the testing test.
if __name__ == "__main__":
suite = TestSuite([TestLoader().loadTestsFromTestCase(Test)])
# Run the test suite.
results = TextTestRunner().run(suite)
print results