Building GUI Tests with Aspect Oriented Programming

Aspect-oriented programming (AOP) is a program paradigm taking modularity to the next level. I want to give an insight into this with my own example to show how it can be used beneficially.

Motivation

Posing a special challenge, GUI testing is not so much a standard as testing of solely algorithmic activities. This is true due to the high degree of complexity in human computer interactions. Because of this it is very hard to provide distinct definitions of the user-interface needed for testing.

But still we wish, that at least the most basic functions of data processing within the graphical user interface can be tested adequately to recognise the symptoms of flawed code at an early stage. Nevertheless the already very complex GUI-Code (our opsi-configed is already made up of more than 130 000 lines of code) should be altered as little as possible. And that is where aspect-oriented programming comes into play.

An Approach with Aspect-oriented Programming

But what exactly is aspect-oriented programming? According to Wikipedia,

"Aspect-oriented programming (AOP) is a programming paradigm [for object-oriented programming] that aims to increase modularity by allowing the separation of cross-cutting concerns."

In practice that means that you define a certain point (a so-called Pointcut) of the program flow – for example a specific user input or a constructor call. Apart from that it is also possible to combine different Pointcuts with additional conditions to create a new Pointcut. Pointcuts are the foundation of aspect-oriented programming. They contain the all the information where exactly an Advice applies.

Using an Advice, you can control what to do when a certain Pointcut is reached. That means, you can call a specific method every time a Pointcut is reached. It is possible to call this method just before or right after the Pointcut - depending on your requirements. Using this technique it is possible to manipulate return values or arguments and you can even prevent a method from being called.

Aspects in general combine Pointcuts and Advices and they contain at least one of them. The good thing is: You can simply add new Aspects without touching the already existing code.

In general there are many programming languages that support implementation of aspect-oriented programming - such as C/C++, Perl, Python or Javascript, just to mention a few of them. Some of them already have it included within their language and some of them as an extended in a library.

In Java, this programm paradigm is implemented in the aspect-oriented extension AspectJ. AspectJ is an open-source project, which has been developed by Xerox PARC and is now maintained by the Eclipse Foundation. For using this extension, you need the corresponding AspectJ libraries and the belonging compiler which does not only compile the program, but weaves the Aspects into the individual Java classes. This is the so-called "Compile-time weaving" which makes it possible to create ordinary Java-Bytecode that can be executed by JVMs without any restrictions.

aspectj_illustration

This graphic illustrates roughly the process of "Compile-time weaving". Using the AspectJ-Compiler an aspect-class is weaved into the already-existing configed and the newly written recorder-class. Even though the sourcecode of the configed remains untouched, the aspects will still have an impact on the configed-classes.

Apart from that, there is also the "Post-compile weaving" which – as the name implies – weaves Aspects into already compiled classes or libraries. For example this can be quite useful if you want to extend new functions into old libraries where you don't have access to the sources.

But no doubt, the most flexible method is the "Load-time weaving": No bytecode is modified, but the Aspects will only be weaved into when loading the classes. The benefit is, to be able to add or remove functions from one start of program to the other. Of course, the loss of performance is greatest when using "Load-time weaving".

To the Construction of a Testing Framework

I myself also use AspectJ for the desired testing framework of our configed. More precisely the AspectJ-Compiler and "Compile-time weaving", because I don't need the flexibility of Load-time weaving and I have access to the sources.

To be specific, after each call of a constructor of a Component (or one of it's derived classes), this object is added to a Hashmap. In this list each element is assigned to a distinct ID-String. Now each time when a user input is executed, I can collect all needed data of this event together with the ID-String of the component in a text file. When I want to replay these actions, exactly this text file is read to create all events in sequence. With the ID-String, I can assign this event to the exact component which the event should be dispatched on.

A small example from my testing framework:

// Declaration of Pointcut
private pointcut constructor():
    call(*.new(..));

// Aspect to "handle" the Pointcut  
after() returning(Component component): constructor() {     
    (...)       
    doSomethingWith(component);     
    (...)       
}   

The foremost declared Pointcut "constructor" is – as the name suggests – put on any constructor. Thereby (..) stands for a any parameters and the wildcard * for any classname. By that, absolutely every constructor is observed. But since the Pointcut itself does nothing, I also need an Aspect. In this case, this Aspect will always be called when the beforehand declared Pointcut returns an object of the type Component or in other words - each Component that has just been created an instance of its constructor, will be delivered as an argument to the Aspect.

Conclusion

AspectJ (and aspect-oriented programming) seems to be a quite useful tool for adding new features - such as testing - to your programs. It's most useful when you already have a huge program which is easy to loose track of. It has proven to work effectively under real-world curcumstances and to keep it's promises. In our case it will be useful for testing and since AspectJ is a quite flexible tool, there will be no impact on your daily activities with configed. But watch out! Use Aspects reasonably. If you do not, they can even be more harmful that the goto statement.