Maintaining scripts is an important task in UI automation. Some times, it may be difficult to do. However, if we separate script flow and actual actions, we may able to maintain the scripts without any issues even the UI changes.
The formal approach.
Here is the steps to create for a test script w.r.t to QEngine
1. Create New Suite named as Test
2. Create New module in that suite if needed
3. Create New Script named as TestScript
4. Record the steps in TestScript.
5. Playback when needed.
Looks cool. Say, we have 100 scripts in that Test Suite. Playback is not an issue. Assume that one element changed in the UI. Now, we need to check and edit all the 100 scripts. This will neutralize any gains made using test automation.
Here is the new model
1. Create New Suite named as Test
2. Create python file for UI functions named UIFunctions.py
3. Create python file for script flow named ScriptActions.py
4. Create New Script named as TestScript
5. Record or use export mode for recording the scripts. Create functions using recorded actions. Store the functions in UIFunctions.py
6. Call the functions needed in ScriptActions.py.
7. Call and import the script flow in TestScript.
8. Playback.
In this approach, if anything changes we need to modify in two files. Let see this with examples.
Content of UIFunctions.py
| Code: |
|
from Framework import * def clickthisbutton(): setLastWindow() def clickthislink(): setLastWindow() def function1(): .......... ......... ..... |
| Code: |
|
from UIFunctions import * def Script01(): clickthisbuttion() clickthislink() def Script02(): clickthislink() clickthisbutton() def Script03(): def Script04(): .......... ....... ....... |
| Code: |
|
from ScriptActions import Script01 Script01() Content of TestScript02 from ScriptActions import Script02 Script02() ....... ..... |
Once, we embrace the idea of removing the object repositories from the automation, we can solve few issues to.
Say, we need to click on the "Add This", what are the options we have?
| Code: |
| clickElement("Add This",1) |
| Code: |
| fireEventOnElement("ID","addthis","Add This",1,"Click","NONE","false") |
| Code: |
| fireEventOnElement(".*","innertext","Add This",1,"Click","NONE","true") |
| Code: |
| getElementProperty(tagName,propertyName,propertyValue,index,propertyNeeded,regExpRequired='false') |
| Code: |
|
i=1 while i: value=getElementProperty(".*","innertext",".*",i,"innertext","true") if value=="Add This": maxvalindex=i i=i 1 else: break |
Every UI automation software uses some form of object repositories. Before diving into the need of those, first let us know what is an object repositories and how it affects UI automation.
When you record a action in the UI, the information about the object such as type,action performed,index in the page,input made if any and window name will be stored in a file. That file may be xml, excel,database,custom extension or binary format. At playback the object info is read and software will try to find the same object in the page to perform the same operation. The file in which the object stored is called Object Repository.
This object repositories work best when the UI doesn't change or web page has only static content. When the UI changes or the properties of object changed w.r.t page or entirely, then playback wont perform the action on that object.
Even if we assume that object properties is not changed, the reading and executing the test will take more time and will grow exponentially with number of objects stored. Whatever the file format, automation software need to read the file, search for the object and execute the desired action.
As most of pages has dynamic content and number of pages for any web hosted software increasing how do we tackle this issue?
My solution is simple. Get rid of Object repository or reduce the number of objects stored in that to minimum(subjective). Is that possible? May be.
QEngine has few functions to do this.
| Code: |
| fireEventOnChildElement(tagName,propertyName,propertyValue,
index,identifier,actionName,actionValue='',childpropname='', childpropval='',childindex=1,childRegExp='false',parentRegExp='false') fireEventOnElement(tagName,propertyName,propertyValue,index,actionName,actionValue='',regExpRequired='false') fireEventAtPosition(title,classID,xCoord,yCoord,actionName,actionValue='',waittime=1) fireEventOnObject(classID,type,xCoord,yCoord,actionName,actionValue='') |