Testing XUL applications
There are various ways to test applications. For GUI applications, you have the following options:
1.) manual testing2.) unit tests
3.) UI-based tests
The latter two can run automated which is important for continous integration to succeed. When run frequently, automated tests can catch bugs before they affect a wider audience. Preferrably developers should be able to run the tests themselves, so that they don't reintroduce bugs you already have tests for.
An additional goal is having product management define the test runs. The advantages are: time and test diversity. First, if a product manager does not have to continously test an application manually, but can instead integrate new features into a test suite, a lot of time will be saved. Second, his or her distinct perspective of a product will enable the PM to produce more diverse tests. This is especially true if not everybody on the programming team knows all details about the program's intended usage.
So how does UI testing work in our case? The application is loaded into Mozilla. It includes a test matrix which defines each step of the test. The matrix is simple P-code. E.g.
| Action | Target | Value |
|---|---|---|
| switch_tab | customer | |
| type | id.realname | Smith |
| command | id.b_save |
In the example, we switch the current view to a tab named "customer", write "Smith" into the field with the id realname and then hit the save button.
With the above steps you lead the application to the state you want to test:
| Action | Target | Value |
|---|---|---|
| assert_value | id.realname | Smith |
| assert_disabled | id.b_advanced |
If the assert fails, the whole test fails. With the checks you can verify that data is correctly loaded and displayed after a save procedure. Calculated results can be validated. Field states (e.g. being disabled or readonly or visible) can be tested for.
Generated data can be stored in variables and later be referenced using ${varname}.
| Action | Target | Value |
|---|---|---|
| store_value | id.debitor | name |
| type | id.kreditor | ${name} |
In the example, we copy the contents of the field debitor to the field kreditor. First the value of the field debitor is stored in the variable name. It is then stored in the field kreditor. All values (the right side of the expression) are expanded, so that variables can be used for all actions.
Check out Selenium for a complete suite of tests for HTML-based web applications. There is also a Session Recorder for Selenium which makes creating tests extremely easy. Just click through your application as usual and the recorder will produce a testcase for you.
