Showing posts with label General. Show all posts
Showing posts with label General. Show all posts

Monday, May 21, 2007

Site updates and upgrades

Hey all,
The site will undergo a major upgrade in the coming week (or two): immigrating to my own server, better platform (Wordpress 2.2), a structued Knowladge Base, better loading time, and much more. For me the most importent upgrade will be an automatic code highlighter, which will allow me to publish articles in 20 sec., instead of an hour.

I hope this will all happen by this Sunday, but there're many factors involved - my work, the students strike, the coming holiday etc.

Anyways, heads up.

Monday, May 7, 2007

Basic Principle – Descriptive Programming

To the hebrew version of this post

Before we can move on to some of the more advanced subjects, it's probably better if we ensure we're all speaking the same language. So now we'll create a proper base-line for some basic QTP techniques (though even they are sometimes referred to as "advanced"). One of the most profound techniques necessary for advanced QTP usage is "Descriptive Programming" (DP).

General Background




When using DP, we're bypassing the native object repository (OR) mechanism, which may have many advantages (easy to generate and read code, good data organization, etc.), but is extremely not flexible. We'll examine situations in which the OR's advantages are outweighed by the DP's flexibility.

In order to fully grasp how DP actually works, it's best to first understand how QTP's native OR works. The native OR is not some complex and deep mechanism, but rather a simple way of keeping groups of properties and values. To clarify: Whenever we add a certain window to the OR, QTP gathers the window's properties (e.g. – Height="400", Title="New Entity", vbName="NewEntityID"), and stores them as a group of property-value pairs. When QTP runs the script, it compares these properties and values to the "physical" objects, and finds (or fails to find) the object which they describe. Nothing mystical about it.

Usage

In DP, we're "manually" specifying the properties and values by which the relevant object will be identified. This way QTP won't search for the properties data in the OR, but will take it from the DP statement. This can be done in a fast, ad-hoc way, in the very line of the command we want to execute:

The syntax is: Class(PROPERTIESSTRINGS).Command, where PROPERTIESSTRINGS specifies the properties and values for the object's identification. For example:


VBWindow("property1:=value1", "property2:=value2").Click


We can even create an object hierarchy (though once we use DP, we must continue to use DP down the hierarchy):


VBWindow("property1:=value1").VBCheckBox("property2:=value2").Click


Of course "VBWindow" class is just an example for DP with VB objects. DP can be done with SWFWindow, Browser, WinComboBox etc.

The only difference between using DP to using the native QTP OR, is in the content within the class's brackets (in this example: VBWindow()). When using the native OR, we'll put the logical name of the object as defined in the OR. When using DP, we'll put strings describing the properties and values the object will be identified by (structured as "property:=value").

This syntax has the benefit of being shot and quick, but may cause problems if we'll use the object again somewhere else. In this case we'll have to rewrite the all the description strings, making the code less readable, and harder to maintain (i.e., if one of the properties were to change, we'll be forced to make several repairs in different places throughout the code). Luckily, DP allows us to define a static descriptive object, and set its properties once. This way, the script simply refers to the descriptive object:


'----Create Object----'
Dim oDesc
Set oDesc = Description.Create

'----Set ID properties & values---'
oDesc("property1").Value = "value1"
oDesc("property2").Value = "value2"

'----Use and reuse the description object---'
VBWindow(oDesc).Type "Something"
'…
'…

VBWindow(oDesc).Close

'----Release description object---'
Set oDesc = Nothing


We can even combine the two methods:


VBWindows(oDesc).VBCheckBox("vbname:=DPIsCool").Set "ON"


Common uses

(Detailed examples can be found in the attached file)

Well, you might ask yourself why we even bother. QTP's native OR does all these things, is tidier, and up to QTP 9, was the only way to enjoy the benefits of code auto-complete. Well, in some sense, you're right – sometimes, the best way to go is to use the OR, straight up. However, in some cases, DP is preferable by far, and sometimes even the only way to go:

Easy-breezy coding: if we're only going to use an object once or twice, there's no need to use the slow, complex OR, when you can just immediately write the ID string as part of the command. Moreover, with DP you can copy code-snippets between scripts, without having to worry about references to undefined object in the new script.

Inherent dealing with double objects: in case the identification properties and values match more than one object, QTP will through an "object's description matches more than one of the objects currently displayed in your application" error. If we're using the native OR, there no easy way to deal with the situation (we could use a complex Recovery Scenario, but it gets very ugly, very soon). However, DP easily deals with double objects by using the index property. We can add "index:=X" to the description strings (when X is a zero-based counter), and QTP will point to object #X.

Object reference in external functions: when using external functions, you can never count on the relevant object being defined in the calling action's OR. And even if the object is defined there, its logical name might be different, so really, DP remains the only option.

Objects that change hierarchies: sometime an object will appear under a different parent each time (e.g. – a pop-up which appears under the initiating sub-window). In some applications, the only way to work with such objects is with DP.

A common usage which deserves a separate section

Working with a collection of objects: other reasons aside, this is the "Killer Feature" of DP. It makes DP a must for every QTP programmer, and it's hard to overstate its importance and inherent possibilities. According to this concept, instead of working with a single object at a time, we can gather all the objects which answer to our identification properties, and work with them as a collection, serially.

This will be clarified via an example: we're dealing with an unknown number of checkboxes. We don’t know (and don’t care) how they're called, or where they are on the screen – we just need to mark all of them as checked. If we were to do this "the old way", we would have to keep track of each checkbox's properties, and write separate commands that identify each of them, and marks them. With the new objects-collection method, we can ask for all the checkboxes in the screen, loop through them, and mark all of them with a single, easily maintainable command.

This method represents a major improvement, since we've severely reduced our dependence in the application. If the number of checkboxes, their locations, or their names were to change, our code will need zero-maintenance to keep on working. Moreover, in some situations, this method is really the only possible way to go.

This method is implemented with the .ChildObjects command. It receives a DP descriptive object, and returns a collection of the objects that answer to the description. The description can have 0 properties, in which case all the objects will be returned. The following example demonstrates the .ChildObjects command syntax, as well as a pretty standard way to utilize the returned collection:


Dim oDesc
Dim oChildren
Dim i

oDesc = Description.Create
oDesc("micclass").Value = "VbCheckBox"
'----We could've left the oDesc object blank, To get all objects----'

Set oChildren = VBWindow("Main").ChildObjects(oDesc)
'----Now oChildren holds the checkboxs' collection----'

'----Run through the collection----'
For I = 0 to oChildren.Count-1
'----Set the specific checkbox to "ON"----'
oChildren(i).Set "ON"
Next


As you may have noticed, the .ChildObjects command must be executed on a top-level window. This means that you can't get a collection of the top-level windows of an app, only a collection of child-objects In a certain top-level window. This was true until QTP 9, which introduced the Desktop utility object. This allows us to execute Desktop.ChildObjects(oDesc), which returns a collection of top-level windows, so all is well.

More examples and uses are available in the attached file.

Further reading

1. QTP help : Using Programmatic Descriptions


Thursday, May 3, 2007

Advanced QTP

Go to the Hebrew version of this post

So, what is this all about?

This blog is meant to be a resource hub for advanced programming in QTP. It's meant for all of you who are tired of meaningless courses and empty books, that teach how to open the OR window (hint - it's a click), but say nothing of design patterns, writing maintainable scripts, encapsulating logically related functions, and other must-know coding standards.
It seems that no one knows we're programmers, not just users.

There are forums and sites who deal with the same problem, some of them are truly excellent (SQAForums immediately comes to mind). However, since their main business is problem solving, none of them is structured enough for straight, old-fashioned learning. This blog will try to fill that gap.

The blog will serve both Hebrew and English readers, so each post will have a link to its Hebrew counterpart. Feel free to go straight to the Hebrew Site.

Hope you'll find all of this helpful. I'm opened to suggestions, questions and improvements, so don't hesitate. After all, this is all done for you :)

Excellent day,
Combustible Moo.

A little about me, and the motivation behind this

I've been working with Mercury's Quicktest Professional for a few years now, and it never ceased to amaze me: Mercury (and the rest of the world) treats me as a user.

All the courses out there, all the book, the hi-tech night studies, help files and whatnot, they all teach me the basics (even the so called "advanced" courses). So, I know what each button does, and I know where to look for the correct sub-menu, and that's all swell, but I have never learnt how to write code. Not really.

Sure, the "advanced" courses deal with some code elements, but as far as they're concerned, I'm like an Excel user, who could use some macro-writing skills. It seems no one understands that in order to be a good in QTP, you need to be good in programming. Yes, you can work with QTP in "user mode", even write your own code, but usually you'll end up with a hard-to-maintain, poor ROI and unreadable test. There are exceptions, but that's what they are, exceptions.

First I thought it's just the books and course, but then I understood: my project managers also think QTP is a point-and-click, record-and-play program. And they've come to expect record-and-play auto-magic results, not willing to acknowledge that sometimes even a QTP script has bugs. But maybe the worst thing is watching my colleagues think of themselves as mere users, afraid to take that extra step towards becoming truly excellent at what they do.

So, the project managers wont push us there, the books aren't any good, and the courses are usually worse. Is there no hope? Well, not all is lost.
There are others out there who see things as I do (or to be more precise, I see things as they do), and are trying to set things straight. But for all of their effort, there's no place that teaches real, hard-core programming for QTP.

So, I've taught my self to listen to the programmers talks in the hallways, steal their books and read their code, and inch my way into good programming. I think I'm half-way there, but I still want to share what I've learnt, hear some new ideas, and hopefully make it easier for others to take the same path.

Hope you'll join me.