Differences and Connections between Runtime Objects and Test Objects

There is a lot of confusion about how the concepts of Runtime Objects and Test Objects are used in QTP. The general idea is usually clear enough, but when it comes down to the actual details, sometimes even the experts do not quite know if using the GetROProperty method on a TO will work.

This article will guide you through the general concepts, and explain all the nitpicking involved in all the commands and practices relevant to the matter.

The QTP Test Object Shell

Under their fancy name, Test Objects refer to your everyday QTP entities. VBCheckbox, Window, WebTable, Browser – these are all QTP constructed test objects, which represent real-world application objects "out there" (i.e., in our application under test).

Whenever we record a real-world object (also known as a Runtime object), QTP creates a corresponding Test Object and stores it in the Object Repository. The Test Object contains QTP specific properties and methods which allow us both to identify the relevant runtime object during playback, as well as to perform standard operations on it and with it.

For example, a Window test object contains properties which allow QTP to identify it in the "real world": text, height, nativeclass, etc.; on top of these, it also contains methods to operate it: Close, Click, Maximize. We can easily see these methods and properties via the object spy’s Test Object tab.

It is important to understand that the test object’s properties and methods are not really "out there" in the application’s runtime object, but are only derived from it. So for example, a SwfComboBox Test Object has the property "all items", while the actual .net application combobox runtime object has no such property. QTP builds the "all items" property out of the combobox runtime object’s available items collection, so even though the property does not exist in the runtime object, it is derived from it.

Test Objects roles

Test objects play several roles in QTP, the most immediate one is object identification. By using a window test object with a text property of "Notepad", we tell QTP to look for a runtime window object with text = "Notepad".

Another important role is standardization. While the application runtime objects might be extremely complex, the corresponding QTP test objects are standard and very simple in comparison. The test object’s simple properties and methods act as a bridge, sparing us the need to nitpick our way through the runtime object’s unknown commands, events and properties. QTP will translate the test object’s simple commands to the runtime object’s commands required to perform the task at hand.

For example, selecting a value in a .Net combobox usually involves changing several properties (SelectedIndex, SelectedItem), and raising several events (SelectionChanged, ItemSelected, TextChanged, etc.). However, the corresponding SwfComboBox test object provides a much more simple and standard "Select" method which does the trick for you.

Working with Test Objects

How can we work with test objects in our scripts?

The most straight-forward way is to simply use them. Every time we maximize a window, select a value from a VBComboBox or click a WebElement, we do it through the QTP test objects. QTP will then locate the corresponding "real" runtime object, and perform the relevant action on it. We can either use prerecorded test objects from the object repository, or create instant test objects via Descriptive Programming.

Aside from straightforwardly using our test objects to perform actions, there are 4 special commands which allow us to access the core of QTP’s test object mechanism: GetTOProperty, GetTOProperties, SetTOProperty and GetROProperty.

GetTOProperty allows us to retrieve the value of a test object property. For example, this command will print out "Notepad":

Msgbox Window("text:=Notepad").GetTOProperty("text")

The GetTOProperty command will retrieve the value as it was originally recorded (or created via DP). It does not matter if the corresponding runtime object exists, or if that value was updated in "the real world" since the object was recorded.

GetTOProperties returns a collection with all the test object properties. Like GetTOProperty, the GetTOProperties command has nothing to do with the actual runtime object in our application, only the test object which represents it.

GetROProperty allows us to get the current value of a test object property. This means that unlike the GetTOProperty and GetTOProperties commands, GetROProperty requires the test object’s corresponding runtime object to exist. QTP will touch the runtime object, and retrieve the value of the property from it. For example, if the text of the Notepad window changed from when that object was recorded, this command will retrieve the updated value:

Msgbox Window("Notepad").GetROProperty("text")

Unlike GetTOProperty and GetTOProperties, it does not even matter if the test object originally recorded the relevant property. In the following example, our test object has only one property – nativeclass, but GetROProperty will still be able to retrieve the value of the window’s text property (where GetTOProperty would return an empty result).

Msgbox Window("nativeclass:=Notepad").GetROProperty("text")

It is important not to be confused by the "RO" in the command name. Even though it has RO (Runtime Object) in it, the command still retrieves only test object properties. So even though a .Net combobox runtime object does not have an "all items" property, you could still execute the following command, and it will print out all the available items:

Msgbox SwfWindow("X").SwfCombobox("Y").GetROProperty("all items")

Last but not Least, SetTOProperty allows us to change a test object’s property for the duration of the test-run. Any changes made with SetTOProperty will be reset once the test-run had finished, or even when you go in and out of actions. It is important to note that changing a test object’s properties might cause QTP not to identify its corresponding runtime object. So for example:

Call Window("Notepad").SetTOProperty("nativeclass", "incorrect value") 
 
Window("Notepad").Close 'this command will fail

The second command will fail as QTP will search for an object with nativeclass = "incorrect value", and it will not find any object matching that description.

From Test Objects to Runtime Objects

Test objects are the cornerstone of all QTP object operations, but they are sometimes too limited for the task at hand. There are two situations in which we might prefer working with the actual runtime objects of the application, as opposed to the QTP test objects:

There are some objects (especially .Net custom controls), which QTP fails to recognize correctly. For example, some combo-boxes might appear as SwfObjects, or generic ActiveX controls. As QTP fails to recognize the object for what they are (in this example, combo-boxes), the test objects it creates do not have the properties or methods that are required to operate the objects (like "all items" and Select).

Another case is when we are required to perform some non-standard operation with an object. Here it makes no difference if QTP succeeds to correctly recognize the object, as the corresponding test object will only provide us with a standard set of commands and properties. A good example for this case is trying to find the font style of a WebElement. The WebElement test object simply does not carry the information we need, and so we have to resort to unusual measures such as working with the WebElement’s runtime object.

Working with Runtime Objects

You can see an object’s runtime properties and methods in the RO tab of the object spy. If it is a .net object, you can also use the .Net form spy to get a more detailed look of those properties that contain inner complex objects.

Not all test objects support working with their corresponding runtime objects, but if they do, it can be done via their .Object property. This property exposes all the properties and methods of the runtime object "hiding" behind our test object. For example:

Print Browser("X").Page("Y"). WebList ("z").Object.selectedIndex

This command will find the runtime object corresponding to the WebList’s test object, access its selectedIndex property, and print its value. Of course that in order for this to work the runtime object must exist when we execute the command. It is important to note that WebList test object does not have a selectedIndex property, only a derived property called "selected item index". So in this case, these commands will print the same value:

Print Browser("X").Page("Y"). WebList ("z").Object.selectedIndex
 
Print Browser("X").Page("Y"). WebList ("z").GetROProperty("selected item index")

The true benefit of working with runtime objects lies with properties and methods that are not available through the QTP test object. So for example, we can find out the color of a WebList’s items text:

Print Browser("X").Page("Y"). WebList ("z").Object.CurrentStyle.Color

We can even use the runtime object’s methods, and perform operations that are otherwise unavailable to us:

Print Browser("X").Page("Y"). WebList ("z").Object.focus

By accessing the runtime world, we can perform almost any operation on our objects, regardless of QTP’s ability to recognize them for what they truly are. So even if our .net combobox is identified as a SwfObject, we’ll still be able to select an item from it, by overwriting the runtime property of the selected item’s index.

SwfWindow("X").SwfObject("Y").Object.SelectedIndex = 1

With all their benefits, it is important to remember that working directly with runtime objects can have significant downsides. Unlike the standard and simple test objects, it is unclear how to operate the object, and exactly what properties and methods it has (CurrentStyle.Color was hard to come by). Even when we find the right properties or methods, using them "from behind the scenes" may cause application errors and invoke hidden bugs.

0 comments:

Post a Comment