FAQ

What are the best ways to deal with Active-X subobjects?

Detail

ActiveX collection objects are controls that are comprised of sub-objects. Examples of collection objects include treeview which is a collection of nodes, toolbar, a collection of tool icons and statusbar, a collection of statictext fields. These collection objects pose challenges for test engineers because the properties and methods of the contained objects can not be directly accessed from 4Test. For example, exposed methods might be available on the treeview to select an item, but specific information about a selected node may only be available on the contained object itself. That information is often important to thoroughly verify application behavior. To call the properties and methods of the contained object, it is necessary to use special access methods found in the 4Test CompoundControl class.

The CompoundControl class is provided in a file called oleclass.inc in the directory where SilkTest is installed. The class contains two sets of function prototypes. The first set includes _GetCollectionProp, _SetCollectionProp and _CallCollectionMethod. These prototypes allow access to methods and properties of the container object. The prototype for _GetCollectionProp is displayed below:

obj ANYTYPE _GetCollectionProp (STRING sCollProp, STRING sPropName)

_GetCollectionProp takes two arguments. The first, sCollProp, is the name of the Collection. The second, sPropName, is the name of the property to get. You might use this method to get the “Count” property of a collection to determine the number of contained objects, e.g. the number of tool icons on a toolbar or the number of columns in a table. A call to this method might be written as follows:

INTEGER iCount

iCount = this._GetCollectionProp (“Columns”, “Count”)

The second set of prototypes including _GetItemProp, _SetItemProp and _CallItemMethod allow access to the properties and methods of the contained objects. The prototype for _GetItemProp is displayed below:

obj ANYTYPE _GetItemProp (STRING sCollProp, INT nIndex, STRING sKey, STRING sPropName)

_GetItemProp takes four arguments. The first parameter sCollProp is the name of the Collection or Interface. Collections can be found in the property section of the class definition for the container object. Collections are usually of type PINTERFACE, which is a pointer to an interface or collection. If you are not sure how to obtain a class definition, see the SilkTest documentation for “recording classes”. An example of a collection property definition is displayed below:

property PINTERFACE ChildNodes alias "$ChildNodes"

The ChildNodes interface provides access to the contained objects. To get a listing and description of available properties and methods, you will need to either consult the documentation for the object or use an Object Browser such as the one within the Visual Basic development environment.

The next two parameters, nIndex and sKey, provide two options for specifying the item in the collection. The first option, nIndex, is the ordinal value of the item in the collection, e.g. the 4th item. sKey is the name of the item, e.g. the string associated with a node in a treeview.  If the string, sKey, is empty (""), the numeric value, nIndex, is used. The last parameter, sPropName, is the name of the property to get.

Typically calls to _GetItemProp will be wrapped in a higher level method to provide easy access to a specific property. For example, a method that gets the tool tip associated with a tool in a toolbar or a node in a treeview might be written as follows:

[-] STRING  GetToolTipText (LISTITEM iListItem)

        [-] if TypeOf (iListItem) == STRING

                [ ] return (this._GetItemProp ("ChildNodes", 0,iListItem,"ToolTipText"))

                        [-] else

                                    [ ] return (this._GetItemProp ("ChildNodes", iListItem,"","ToolTipText"))

To call GetToolTipText, the user is required to provide only the contained item as either a string or index. The method then returns the value of the property ToolTipText from the ChildNodes interface.

So far our discussion has been limited to properties. It is also possible to call methods on a contained object in a similar manner. To access methods on a contained object, the CompoundClass prototype _CallItemMethod is used:

obj ANYTYPE _CallItemMethod (STRING sCollProp, INT nIndex, STRING sKey, STRING sMethName,

varargs lArgs)

_CallItemMethod is similar to _GetItemProp. The first three parameters are the same. The forth parameter, sMethoName, is the name of the method to call. The last parameter is a list of the arguments to pass to that method. As with properties the user needs to consult documentation to determine the names of the methods and the number and types of parameters to pass. In the following example, _CallItemMethod is used to get the state of a tool button in a toolbar:

  •             [-] BOOLEAN GetToolState (LISTITEM iListItem)

  •                         [-] if TypeOf (iListItem) == STRING

  •                                     [ ] return (this._ CallItemMethod ("ChildNodes", 0,iListItem,"GetState",{}))

  •                         [-] else

  •                                     [ ] return (this._ CallItemMethod ("ChildNodes", iListItem,""," GetState",{}))

To call GetToolState, the user is required to provide only the contained item as either a string or index. The method then returns a Boolean value which indicates whether the tool is enabled.

Before you can start using the access methods in the 4Test class CompoundClass, you must modify your class definition to inherit from it. If the class definition of your object inherits from Control as many ActiveX objects do, you can simply change the inherited class from Control to CompoundControl as follows;

If your class is defined like this:

winclass StatusBar20WndClass : Control

change its definition like this:

            winclass StatusBar20WndClass : CompoundControl

If your ActiveX class already derives from a 4Test class other than Control, it may not be possible to inherit from CompoundControl as previously described. Changing the derived class in this manner would result in loss of inherited class-specific properties and methods. Instead, simply copy the method prototypes from CompoundClass into your class. Usage of the access methods will not be affected in any way.

The ability to access properties and methods from sub-objects will often enable verification of application behavior that would otherwise be possible only with bitmaps. Using the sub-object methods and properties will result in more reliable and maintainable automated tests.