Home Programmierung Using LISP as a Code Generator for Perl Win32::GuiTest

Main Menu

Texte / Essays
Using LISP as a Code Generator for Perl Win32::GuiTest
Tuesday, 27 April 2010 11:35
There are no translations available.

by Sebastian K. Glas 27.04.2010

  • Update 2010/05/05 -- see below

Being a Business Analyst for quite some time, I found testing an Applications via its frontend can be a tedious task. But without a doubt, extensive and thorough testing is necessary.

There a ways to automate Frontend Testing: utilities which record key strokes or mouse movement and clicks. I´ve never felt drawn to work with any of these as they do not let you use a powerful and more abstract programming language. Besides, there are commercial solutions.

However, some time ago I discovered the Library Win32::GuiTest for Perl (by Ernesto Guisado and others) which I found to be very useful. First, I like Perl as a functional and expressive language, second the Library has a pragmatic and powerful approach for generating KeyStrokes and accessing Front End Resources in Windows in general. Third, it is published under a free license.

The piece that was missing for me was the power of LISP: using an interactive REPL interface, metaprogramming and syntactic abstractions. Using LISP with EMACS / SLIME is so much fun and such a delight that I never want to miss it again.

So I had the idea of generating Perl code from within LISP, using the REPL to start Perl Files and add interaction.

It took me a day to write the following simple prototype in CLISP. Here is a basic description, in reverse order: I use (ext:run-program) to start the perl.exe interpreter to run a generated perl file. Before that, I create a perl file out of a simple LISP list of strings. All the rest is simply convenience to save me from having to type too much code. In this prototype, the resulting output is sent to a logfile (CLISP returns a stream if desired).

I have to add that I am a LISP beginner, so if you find ways to express things more elegantly, blame it on me. This prototype is very simple and does not include too many abstractions:

As a result, I can type:

> (make-sendkeys-commandlist '("{TAB}" "{ENTER}" "%{F4}") )

which returns

("Win32::GuiTest::SendKeys(\"{TAB}\");" "sleep 1;" "Win32::GuiTest::SendKeys(\"{ENTER}\");" "sleep 1;"  "Win32::GuiTest::SendKeys(\"%{F4}\");" "sleep 1;")

If I wanted to run this script directly from within the REPL, I can say:

> (create-and-run-perlfile (make-sendkeys-commandlist '("{TAB}" "{ENTER}" "%{F4}") ))

which writes the generated commands in a file and starts the perl interpreter. It then returns some execution information:

Session: 2010., Date: 2010-4-27 13:11:33
Using Perl: C:\strawberry\perl\bin\perl.exe
*basepath*: C:\tmp\
Executing: C:\tmp\2010.
Logfile:   C:\tmp\2010.


This way, it is possible to create syntactic abstractions for complete code-blocks of perl code. Adding complete "business transactions", callable with parameters, becomes possible. Complete Testing-Sripts and re-tests can be written easily and can be started out of the REPL.

And of course, with little or no "code duplication" (I like this expression).

Warning: Powerful Scripting imposes a security Risk! Programs Executing keystrokes have access to all privileges available in the current security context!


Simple Set-Up Guide:
Install Perl (I use strawberry) and Win32::GuiTest. You should be able to run the Demo Applications, eg. notepad.pl successfully from the cmd.exe command line.

I use EMACS + SLIME + CLISP. Here is the code. You have to customize *basepath* and *perl-binary*.

[ testframework.lisp ]

[ The source as a syntax-colored html-file ]


Update 2010/05/05

Version 0.1.21 of my LISP Abstraction Layer adds some more features. It allows now to return strings to LISP that were caught by Win32::GuiTest with the GetText function. Perl Warnings and Error Messages are put in a separat logfile and displayed in the Repl.


The Main function remains (create-and-run-perlfile '(list-of-perlcommands))

I encapsulated the calc.pl Example Application as a test function to illustrate the features.

I am approaching the desired state, a Domain Specific Language for these frontend GUI testing tasks with a very abstract, short and simple interface.

Being able to Return Values, sets of Testcases can be stacked. Let´s say you have a hypothetical CRM System; first you would like to create a new customer record. You could write a function which does exactly this and which returns new newly system-generated Customer No.

You then could use this returned Customer No. to execute the next test function, let´s say Creating a new Order.

This can be expressed in just a few lines of code.

This is a Screenshot of one of the Demo Functions:


Testframework Example


This is a simple Architecture Overview:

Architecture of Testframework


For the current source code, see above.