I have a method that looks like this:
def doImportDatabase(self, xmlFPath):
#
# This clicks on the Import Database menu, which opens up
# a modal dialog
#
self.widgetManip.chooseMenuItem(MenuSetup.MENU_TOOLS_IMPORT_DATABASE)
#
# This types a file name in the modal dialog, and clicks the OK button
#
importWndManip = self.xmlImportWndManip()
importWndManip.doTypeXMLFileName(xmlFPath)
importWndManip.doOK()
The problem I'm having is that as soon as the menu item is clicked, the modal dialog takes over, and the last three lines (entering the file name and clicking OK) do not happen
until I have manually clicked on the OK button to close the dialog box.
I tried running the application in a separate thread, than doImportDatabase, like this:
class TransanaInSeparateThread(threading.Thread):
def __init__(self, app):
threading.Thread.__init__(self)
self.app = app
def run(self):
self.app.MainLoop()
TransanaInSeparateThread(app).start()
... Then go about building the test harness and invoking doImportDatabase().
But to no avail. Does anyone have ideas for how I could get around this problem?
Thx
----
Alain Désilets, MASc
Agent de recherches/Research Officer
Institut de technologie de l'information du CNRC /
NRC Institute for Information Technology
alain.d...@nrc-cnrc.gc.ca
Tél/Tel (613) 990-2813
Facsimile/télécopieur: (613) 952-7151
Conseil national de recherches Canada, M50, 1200 chemin Montréal,
Ottawa (Ontario) K1A 0R6
National Research Council Canada, M50, 1200 Montreal Rd., Ottawa, ON
K1A 0R6
Gouvernement du Canada | Government of Canada
> # This types a file name in the modal dialog, and clicks the OK button
^^^^^^^^^^^^
> The problem I'm having is that as soon as the menu item is clicked, the
> modal dialog takes over, and the last three lines (entering the file name
> and clicking OK) do not happen until I have manually clicked on the OK
> button to close the dialog box.
Alain,
By definition, a modal dialog grabs the application until it is dismissed.
For testing purposes, you want the dialog to be in non-modal mode. Robin
posted the syntax a week or so ago; the archives will have that message.
HTH,
Rich
--
Richard B. Shepard, Ph.D. | The Environmental Permitting
Applied Ecosystem Services, Inc. | Accelerator(TM)
<http://www.appl-ecosys.com> Voice: 503-667-4517 Fax: 503-667-8863
I couldn't find that message in the archive, but in any case, I don't think making the dialog non modal would work. Basically, the code that is invoked when the menu item is clicked has this:
val = self.ShowModal()
if val == wx.ID_OK:
... Process the inputs entered into the dialog
If I replace this by something like:
val = self. Show()
... Process the inputs entered into the dialog
Then when I programmatically click on the menu item, the above code will be invoked, and control will return to my test script only once the processing of the dialog data has finished. Since my test code clicks on the menu item, AND THEN enters data into the dialog, it means that the data entered into the dialog will be NULL at the time when the dialog returns.
It seems to me that the application and the code that drives it for testing need to run in separate threads. But I tried that and it didn't work.
Actually, this brings me to the more generall question of:
"Has anybody else figured out exactly how to do automated acceptance testing of a wxPython application using PyUnit?"
I have been able to do *Unit* testing of individual dialogs. For example, I could test JUST the above dialog by starting it non modally, manipulating some of its components, and then seeing what happens as a response to it.
But now, I am trying to do global acceptance testing, where my test program does not control how the dialog is started.
Thx.
Alain Désilets
>
> HTH,
>
> Rich
>
> --
> Richard B. Shepard, Ph.D. | The
> Environmental Permitting
> Applied Ecosystem Services, Inc. | Accelerator(TM)
> <http://www.appl-ecosys.com> Voice: 503-667-4517
> Fax: 503-667-8863
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: wxPython-user...@lists.wxwidgets.org
> For additional commands, e-mail:
> wxPython-...@lists.wxwidgets.org
>
>
> If I replace this by something like:
>
> val = self. Show()
> ... Process the inputs entered into the dialog
>
> Then when I programmatically click on the menu item, the above code will
> be invoked, and control will return to my test script only once the
> processing of the dialog data has finished. Since my test code clicks on
> the menu item, AND THEN enters data into the dialog, it means that the
> data entered into the dialog will be NULL at the time when the dialog
> returns.
Could be. I've not used modeless dialogs. There should be no space in
self.Show(), but I assume that's a message typo and not in the code.
> It seems to me that the application and the code that drives it for
> testing need to run in separate threads. But I tried that and it didn't
> work.
Guess that a wxPython version of 'expect' is what's needed.
Sorry that didn't help.
No sweat. Thx for trying and have a good weekend.
Alain Désilets
> The problem I'm having is that as soon as the menu item is clicked,
> the modal dialog takes over, and the last three lines (entering the
> file name and clicking OK) do not happen until I have manually
> clicked on the OK button to close the dialog box.
Break the test into multiple chunks. One that builds the dialog and
another to test drive the dialog, and then another for things that need
to be done when the dialog is completed. You then need to do something
that will cause the middle chunk to be run after the dialog has been
shown. Since I don't know how the rest of your testing framework works
I can't really advise how to do that, but I would probably do something
like use wx.CallAfter to cause the middle chunk to be invoked in the
first idle time after ShowModal is called.
--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!
> Actually, this brings me to the more generall question of:
>
> "Has anybody else figured out exactly how to do automated acceptance
> testing of a wxPython application using PyUnit?"
OSAF has a framework for running functional tests of Chandler. It
essentially does an automated test drive of the app, similar to what it
sounds like you are attempting. It is quite complex however, and is
tied very tightly to the structure and architecture of Chandler. There
is some work going on right now to make it possible replace the current
framework and to create tests by recording events and being able to play
them back. It's taken some (minor) hacking of wxWidgets to make it
possible, so I'm not sure yet if we'll be able to move that code into
the official wxWidgets...
There are no easy answers here, but you can read up on some
(admittedly less-than-ideal) options at:
http://wiki.wxpython.org/index.cgi/Unit_Testing_with_wxPython?
highlight=%28testing%29
BTW, much of wxWidgets is not thread safe, so you shouldn't run the
wxPython mainloop in any thread other than the main thread.
Regards,
Kevin
> Thx
>
> ----
> Alain Désilets, MASc
> Agent de recherches/Research Officer
> Institut de technologie de l'information du CNRC /
> NRC Institute for Information Technology
>
> alain.d...@nrc-cnrc.gc.ca
> Tél/Tel (613) 990-2813
> Facsimile/télécopieur: (613) 952-7151
>
> Conseil national de recherches Canada, M50, 1200 chemin Montréal,
> Ottawa (Ontario) K1A 0R6
> National Research Council Canada, M50, 1200 Montreal Rd., Ottawa, ON
> K1A 0R6
>
> Gouvernement du Canada | Government of Canada
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: wxPython-user...@lists.wxwidgets.org
> For additional commands, e-mail: wxPython-users-
> he...@lists.wxwidgets.org
>
Well, there's unit testing and there's acceptance testing. From the
rest of the thread, it sounds like you want to do acceptance testing
here, and I have no specific knowledge, but...
You already have a mechanism to click on a menu, it seems. In that
case, it seems like breaking the test code out into another thread
and having it send events to the main window may be just what the
doctor ordered. It'll require a bit more harness around the
unittest module, but I can imagine that you could probably put
together a fixture relatively easily that all of your tests could
then use.
If you want to do unit testing, however, test that you can open the
dialog, interact with its controls, and get the right values back.
Then test separately the database opening, parsing, etc. It's a bit
hard to see how to do this at first, but you'll get the hang of it
if you beat your head against your monitor for long enough. :)
***
On the "fixture" bit, I do this a lot for testing wx stuff since
with frames opening and closing, and only sometimes being shown, wx
gets a bit hinky so the fixture makes sure that everything is
cleaned up appropriately.
Something along these lines:
class WindowFixture(unittest.TestCase):
def setUp(self):
self.app = wx.PySimpleApp()
self.win = MyFrame.MyFrame()
def tearDown(self):
if self.win:
self.win.Close()
del self.app
def Reveal(self):
self.win.Show()
self.app.MainLoop()
self.win = None
...then all of my tests for "MyFrame" derive from this thing. I'd
actually toyed with making a ctor that took the class to be
instantiated, but it added a lot of noise for something I didn't
actually end up needing after carefully considering my problem.
(There's some documentation on the wxPyWiki about why you need to do
the above stuff, which I could expand on more if anyone cares.)
...and the Reveal method was stolen from an idea by Phlip that he
talks about in Test-First User Interfaces, where it's nice sometimes
just to inject a self.Reveal() into a test to show the current state
of the window.
-tom!
> Well, there's unit testing and there's acceptance testing.
> From the rest of the thread, it sounds like you want to do
> acceptance testing here, and I have no specific knowledge, but...
Yes, integrated Acceptance Testing is what I am trying to do.
> You already have a mechanism to click on a menu, it seems.
> In that case, it seems like breaking the test code out into
> another thread and having it send events to the main window
> may be just what the doctor ordered. It'll require a bit
> more harness around the unittest module, but I can imagine
> that you could probably put together a fixture relatively
> easily that all of your tests could then use.
Good idea. This is sort of the inverse of what I tried when I ran the
wxPython app inside an other thread. You propose that it should instead
be the GUI driving code that is run in a separate thread. I'll try that.
> If you want to do unit testing, however, test that you can
> open the dialog, interact with its controls, and get the
> right values back.
> Then test separately the database opening, parsing, etc.
> It's a bit hard to see how to do this at first, but you'll
> get the hang of it if you beat your head against your monitor
> for long enough. :)
Yes, that's how I have done GUI testing in the past. But in the current
case, the application I am testing was not developed with that in mind.
The logic and presentation layers are very tightly coupled. I could of
course refactor it, but I would prefer not to, since the app does not
have automated testing in place (and I'm not reckless enough to do major
refactorings without a safety net).
But even with applications which I built to make this sort of piecemeal
testing possible, I have often been burned with bugs that only came up
when you considered a particular sequence of dialogs. So I think you
need to do this sort of Integrated Acceptance testing also, in addition
to the Piecewise Unit Testing.
In my case, I'm dealing with an existing app where creation of the
dialog, displaying, and processing of the data entered into it are
bundled into one method. I could of course refactor to split them apart,
but I'm reluctant to do this without the safety net of a unit test suite
(the system has none at the moment).
But if all else fail, I will try that.
I have done so using nose. It's a Windows-only solution, but what I do is
use the AutoIt ActiveX control via win32com, which I use to drive the GUI
and make various assertions about its state.
http://www.autoitscript.com/autoit3/
Here's a simple one:
def testHelpDlg():
"""Tests that the help dialog appears when the
menu shortcut keys are pressed. Assumes
that the app has already been started."""
oAutoIt = client.Dispatch("AutoItX3.Control")
oAutoIt.Send("!hh") # Send Alt-h, h key combination
# Test that Help dialog appears within 5 seconds
assert 1 == oAutoIt.WinWaitActive("AnalyzeAssist Help",
"",
5)
# dismiss the dialog
oAutoIt.Send( "{ENTER}" )
# allow 200 msec for dialog to disappear
oAutoIt.Sleep( 200 )
AutoIt can also be used to click buttons, check the text in text boxes and
status bars, etc. You can also use it to record sequences of mouse and
keyboard work, although you will then need to translate the script it
produces into the COM version for use from Python.
Regards,
Ryan Ginstrom