Testing UI with UI scripting: getting hooq to work
We do need to test User Interfaces (UI) developed with Nokia Qt using UI scripting. There is squish of course and other commercial products but we also like to give a try to open source alternatives if available. One is described in this 2-years old blog post by the author (from which this post heavily borrows), source code is available here.
We tested that in Debian wheezy; install some additional packages:
sudo apt-get install libqt4-dbg libqtscript4-qtbindings
Then clone the git repo:
git clone git://gitorious.org/hooq/hooq.git
enter it, apply the patch which includes the fix mentioned here and here, then qmake and make:
cd hooq wget /posts_img/2012/03/0001-patch-GdbInjector-add-a-couple-of-asserts.patch git apply 0001-patch-GdbInjector-add-a-couple-of-asserts.patch qmake hooq.pro make
We have tried it out with UIPF, the User Interface for Process Flowsheeting.
To run, it start hooq/hooq. The user interface appears:
For organizing your tests, Hooq uses the concept of a ‘test set’ – this can be one per application, tests for different areas of the same application, or whatever you choose. Select File -> New test set to create one, fill in the stuff including full path to your debug-mode application:
Now you can type the description for the first test case in the textbox at the bottom and click the “Record” button to open up your application and perform the required actions:
We end recording by closing the application. At the end of the recording session, the test set contains our first test entry, with run and edit buttons:
Running the test now is of little use because it will execute till the end at max speed, possibly missing any asynchronous event and closing the application before we can actually test anything. The idea is that the script obtained by recording should be edited, adding verifications, diagnostic etc. – for the test scripts Hooq uses QtScript, a scripting language based on ECMAScript i.e. JavaScript + a few Qt-specific extensions. By clicking on the edit button you’ll get a script editor with nice synthax highlighting:
If you then click in the margin on the line 17, there’ll then be a breakpoint marker on that line:
If you then click the run button in the toolbar, the script will stop running at that line; at this point, if you click ‘pick property’ in the toolbar, a pop-up “Click on a widget to retrieve its porperties” appears, the cursor becomes a cross and you can then click on any widget in the application being tested, to get a list of its Q_PROPERTYs; for example for the message box in the lower part of UIPF we get:
For example, scroll down to “plainText”, and click fectch. This this will insert the JavaScript code required to fetch the variable from the live application during tests:
objectFromPath("WindowMain-0::QSplitter-1::QTextEdit-1").property("plainText")
This requires you to do something with this value. If on the other hand you click “compare”, it will automagically insert a check into the JavaScript code in the editor:
compare(objectFromPath("WindowMain-0::QSplitter-1::QTextEdit-1").property("plainText"), "* ****************** LIBPF 01.00.0868 [2012/02/26 16:09:12] ******************\n* All rights reserved; do not distribute without permission.\n* Paolo Greppi (C) Copyright 2004-2012 Paolo Greppi libpf.com\n* ****************** Jasper 00.01.0192 [2012/03/08 10:03:37] *****************\n* (C) Copyright 2010-2012 Paolo Greppi, Daniele Bernocco Universita' di Genova\nmain * Define components\nmain * Clean up persistent storage database\nmain * Program exits correctly");
To make sure the variable actually has that value at that point, I also insert a wait statement before:
msleep(1000) compare(objectFromPath("WindowMain-0::QSplitter-1::QTextEdit-1").property("plainText"), "* ****************** LIBPF 01.00.0868 [2012/02/26 16:09:12] ******************\n* All rights reserved; do not distribute without permission.\n* Paolo Greppi (C) Copyright 2004-2012 Paolo Greppi libpf.com\n* ****************** Jasper 00.01.0192 [2012/03/08 10:03:37] *****************\n* (C) Copyright 2010-2012 Paolo Greppi, Daniele Bernocco Universita' di Genova\nmain * Define components\nmain * Clean up persistent storage database\nmain * Program exits correctly");
Now remove the breakpoint, and run it a few times; it should repeat your input and quit each time, without an error; however, if you change the reference string in the compare statement to something else, then click run, the test will produce an error:
This is more useful when the test hasn’t changed, but when the application itself has (i.e. a regression). Hooq also has a “Run All” feature, to run all the tests in a set unattended, and show a summary at the end.
To turn this tool in an effective automated UI test tool, the following is required:
- fix a few rough spots
- add a CLI command to run selected tests without any access to a display (hidden UI) for running in daemon mode
- add XML output similar to boost::test
- get some help from a JavaScript guru and prepare a few example scripts with wait-on-event conditions (i.e. wait for table to be populated from remote database, wait for disk operation to complete…), identifying controls etc.