Monday, August 18, 2008

Building the framework (2)

Last time we have started building the GUI Automated Testing framework. Today we are going to enhance it. Download the source to be able to follow the text.

The first version implemented the BaseComponent class to represent windows components. We could not do anything but find out location of the component. It would be nice to be able write text into a text box or click a button by simple method, wouldn't it?

To do that, we need to know the type of each component. The type name of .NET components is stored in component.GetType().Name. Knowing the type, we create subclass of BaseComponent for each type. In the subclass, we provide nice methods and properties.

First, we enhance BaseComponent class. We add _CheckVisibility(self) method that checks whether the component is visible. If not, it raises an exception. We need it for checking if button is visible so we can click it or text box is visible to write it. And we add guiat property to be able to activate the tested application from a component by calling self.guiat.Activate().

Let's look on a button. The Button class is very simple:
from time import sleep
from Win32API import Win32API
from BaseComponent import BaseComponent

class Button(BaseComponent):
"""interface to the Button component"""

def Click(self):
""" perform left mouse click on the center of the button, no parameters"""
self.guiat.Activate()
self._CheckVisibility()
pos = self.location
Win32API.MouseClick(pos[0] + (pos[2]/2), pos[1] + (pos[3]/2))
sleep(0.1)
The Click(self) method activates the tested application, checks whether the component is visible, finds out the position of the button, clicks into the middle of the button position, and finally waits a little bit. I do not like the waiting but it is here for safety. Windows may repainting some areas or do some other cool thinks, so it is better to give them some time for it.

The TextBox class provides three methods and one property:
  • FocusEditor(self)
    The method essentially does the same as Button's Click method. It activates the tested application, checks whether the component is visible, and clicks into the middle of the TextBox position to focus the editor.
  • Clear(self)
    The method focuses the text box, moves cursor to the start position simulating pressing Home key, and simulates pressing Delete key until the text in text box is empty. If the text is not empty then, it raises exception.
  • Write(self, aString)
    The method clears the text box and uses Win32API method SendString to simulate typing aString. Then checks whether the text box contains the aString value and raises exception if not.
  • value
    The property contains the actual value of the text box. When user assigns a string to it, the string is written to the text box.
Now look on the creating instances of GUIAT components in the Form class. We have simply added dictionary with known component types (RecognizableComponents). When we go through all components on the form in the _AnalyzeStructure method, we first check whether we know the component type or not. If so, we create instance of the appropriate component type class (e.g. Button or TextBox). If not, we create instance of the BaseComponent class.

Let's try a small example:
>>> import GUIAT
>>> g = GUIAT.GUIAT()
>>> g.Run()
Starting GUIAT...
"frmGUIAT" (frmGUIAT)
"btnAddItem" (Button)
"lblNewItem" (Label)
"txtNewItem" (TextBox)
"lbxItems" (ListBox) - UNKNOWN
"btnQuit" (Button)
Starting GUIAT done.
>>> txt = g.mainForm._GetComponentByName('txtNewItem')
>>> btn = g.mainForm._GetComponentByName('btnAddItem')
>>> txt.value = 'Hello world!'
>>> btn.Click()
The result of the above small script is a new line in the list box. You see that the button, label, and text box are know component types. The label is treated as BaseComponent (see RecognizableComponents in Form.py). The list box is unknown component.

Today, we have shown how to create button and text box GUIAT classes that control respective .NET components. We can already script our small tested application!

Next time, we add list box class and logging.