|
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Overview
This thread is started for the purpose of sharing information I have picked up over the last 2 months as I have tried to learn how to use the vbScripts language. I feel that learning vbScript fundamentals is an essential part of learning to work effectively with QTP.
While my journey is by no means over, I wanted to get this information out there, so other new folks can get started as efficiently as possible.
I encourage others on this forum to provide other resources and FAQs—or to argue a counterpoint to those I provide in follow-on replies to this thread starter.
But please do not post raves, rants and other forms of content-free replies to this thread. These just clutter up the thread and make it difficult for others to find the real information.
-Hope this helps, Terry Horwath
------------------------------------
The Basics
In no particular order:
1. The Microsoft vbScript Version 5.6 Documentation, provided in a standard online HELP file *.chm format, should be considered your basic gold standard reference. Once you get past your basic learning curve this is often the only reference you will need. QTP bundles a version of this file, but if you need or want to get a copy from the mothership here is the URL to download a copy:
http://www.microsoft.com/downloads/detai...;displaylang=en
Note that the above online documentation unfortunately mixes Microsoft’s support for both vbScript and javaScript, so be aware of this as you prowl through this guide (applicability is noted at the top of each section).
2. While the above document is great for looking up a particular Property, feature, Function, Method, etc., it is not the best way for most of us to learn language basics, and more importantly, to see how the various components and constructs are related. To address this aspect I can personally recommend the O’Reily “vbScript in a Nutshell” manual, but that book costs about $30. An online, free, resource that is almost as good can be found at yet another Microsoft URL; then follow the “vbScript” link on the page:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/Scriptinga.asp
3. vbScript is designed to, and requires, a compliant runtime environment, also referred to as a host. The Microsoft documentation assumes that you are going to write for and run scripts in the Windows Script Host (WSH) environment and to often use the language to control Windows Management Instrumentation (WMI) objects, or to write active server web pages. But what we are interested in is Mercury’s QTP runtime environment support for vbScript. Keep this in mind when using the MS documentation (including that provided by QTP), because you will occasionally find that not all features and functions described in the MS documentation is supported in the QTP runtime. For example QTP does not provide the root wscript object described in the MS documentation. (This issue will, or at least should, be addressed by subsequent additions to this thread).
Beyond the Basics
In no particular order:
1. A forum dedicated to all things vbScript, very similar to sqaforums.com is www.visualbasicscript.com Like this forum you need to set up an account to ask questions. The moderators are very knowledgeable (and appear to answer most of the posts). But be aware—this forum expects that you will search before posting, and will have taken modest steps to find your answer with web searches.
2. A great resource to get scripting ideas, possible solutions to your problem, and to find vbScript syntax dissected with commentary is, once again, a Microsoft site dedicated to promoting vbScript usage. It is called the Hey Scripting Guy! forum and can be found at the following URL:
http://www.microsoft.com/technet/scriptcenter/resources/qanda/default.mspx
While the focus is primarily WMI, they post 5 articles a week, and the archive goes back about 2 years. It contains a wealth of information about using vbScript techniques and objects.
3. If you are going to develop two or more shared libraries for inclusion with your QTP test cases, learn how to encapsulate each library in a vbScript Class. Once vbScript basics are mastered, learning to develop Classes and instantiate objects is a small additional effort. The primary advantages to using classes are the ability to (a) hide Private data variables, (b) control access to Public variables through the use of Properties and (c) maintain logical and separate namespaces in each library--for example object "fileio" and "msglog" can each have a Write() method: fileio.Write() and msgLog.Write().
Other vbScript Basics Related Articles
In no particular order, other articles I have recently posted that address vbScript basics:
1. Use of the special characters for line continuation and multiple statements per line:
http://www.sqaforums.com/showflat.php?Cat=&Board=UBB20&Number=344186
2. The wscript Object and QTP:
http://www.sqaforums.com/showflat.php?Cat=&Board=UBB20&Number=347101
3. wscript.Sleep throws and exception:
http://www.sqaforums.com/showflat.php?Cat=&Board=UBB20&Number=347071
4. I and others have also posted what we feel are useful shared code examples in the following thread:
http://www.sqaforums.com/showflat.php?Cat=0&Number=347046
------------------------------------------
Search words/phrases to find this thread: newby; new user; vbScript basics; vbScript FAQs; vbScript Resources; vbScript Help; getting started
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Article Title: Misleading error message using ExecuteFile()
Sigh, sometimes QTP can be so frustrating...
In the following code example, the file xx.vbs does not exist: Code:
'my test case ' msgBox "what a misleading error message:" ' ExecuteFile "xx.vbs"
The Run Error dialog presented by QTP (I am using version 8.2) when it executes this code is:
Invalid procedure call or Argument
Details>> Line (1) "'my test case".
Totally misleading. But now you know to watch for this.
-Terry
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Article: Subs, Functions, and those pesky parens: ()
You execute the following code:
Code:
function x(s) 'by default, s is passed "byRef" s="altered by x()" end function ' sVar="zero" ' x(sVar) msgBox sVar ' call x(sVar) msgBox sVar
The first time function x() is invoked, using the "x(sVar)" form, sVar is not modified after x() returns.
But the second time function x() is invoked, using the "call x(sVar)" form, sVar is modified, as expected, after x() returns.
So what the heck is going on here?
Well the following post probably describes more than you will ever want to know about this subject:
http://www.visualbasicscript.com/m_41080/tm.htm
But getting a good handle on when to use ()'s, and why is important to using vbScript successfully (and avoiding alot of subtle problems--this is nuanced language).
-Terry
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Article: Assignment and Evaluation nuances
Based on my understand of C and Java, the following code snippet should assign the return value of foo() to iNum, and then compare iNum to False:
Code:
Function foo () foo=7 End Function ' ' If (iNum=foo())=False Then ' If isEmpty(iNum) Then msgBox "Eval1, iNum is not initialized" else msgBox "Eval1, iNum returned FALSE" End If else msgBox "Eval1, iNum: " & iNum End If msgBox "after Eval1, iNum: " & iNum
Based on this [erroneous] assumption we would expect to see two message boxes, each indicating that iNum has a value of 7. Well, in vbScript the results are: the first message box indicates that iNum is ...not initialized and the 2nd displays nothing for the value of iNum--both because iNum is still equal to Empty.
What I believe the above IF statement is saying is (1) "is iNum (which has a value of Empty) equal to 7? (the value returned from foo), the answer of which is False, and then (2) is False equal to False?, the answer of which is True, so the IF THEN statements are executed.
You then review the MS online vbScript doc and see that there is a well written section that describes the Eval and Execute functions that are designed to deal with the overloading of the '=' equals sign. So then you might conclude that the following code would now allow us to assign iNum and evaluate its value, all in a single statement:
Code:
If Execute("iNum=foo()")=False Then ' If isEmpty(iNum) Then msgBox "Eval2, iNum is not initialized" else msgBox "Eval2, iNum returned FALSE" End If End If msgBox "after Eval2, iNum: " & iNum
Well, the results are still not what we want or expect, because the Execute() function is not returning the value assigned to iNum--although now, at least iNum is being initialized with the return value from foo().
The bottom line is, you need to discipline yourself to perform the assignment and then an evaluation of that assignment in two statements, to ensure correct functionality, as in:
Code:
iNum=foo() If iNum=False Then
All code in this article was executed/validated in both the WSH and QTP runtime environments. I encourage replies to this post if you have syntax--that you have validated in both environments--that achieves assignment and evaluation in a single statement.
-fyi, Terry Horwath
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Article: exploiting vbScript's variant return data type
For those of us used to working with strongly typed languages (like C, Java, C++, etc) working with vbScript's single variant data type (where any variable can hold any type of data, and morph over time) can take some getting used to.
But beyond the "a novice can get some code to work really fast without much knowledge" argument (hum...), I have recently realized that vbScript, unlike strongly typed langs, provides multi-state function return possibilities. For example in the following code snippet:
Code:
Option Explicit ' function foo(iRetControl) ' if iRetControl=1 then foo="abc" else foo=False end if end function ' dim s ' s=foo(1) if s=False then msgBox "foo(1) returned boolean False" else msgBox "foo(1) returned string: " & s end if ' s=foo(2) if s=False then msgBox "foo(2) returned boolean False" else msgBox "foo(2) returned string: " & s end if
foo() can return a String or a Boolean False. And the code that evaluates these return values does not have to do any casting.
This, at least for me, has significant advantages when writing functions that return say a string, integer, array, whatever when they execute successfully and a boolean False (or whatever) when they encounter some type of failure.
If you have not spotted this nuance, now you have another tool in your toolbag.
-fyi, Terry Horwath
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
re: exploiting vbScript's variant return data type
This follow-on post provides a more concrete example, and shows how this capability can be turned around, in that it may be more appropriate to return say a True value when a function executes as expected, with a variety of returns based on failure. For example: Code:
function WriteFile (sFilespec, sBuffer) ' if sBuffer is successfully written to sFilespec then WriteFile=True else WriteFile="description of failure" end if end function ' ' retCode=WriteFile("c:\a\b\myfile.txt", "blah, blah") if NOT retCode then use the returned string to process/log the error... ExitTest end if continue on with the test...
With a slightly more complex example and called function your test code's response can be conditioned by a passed return control variable. For example: Code:
function WriteFile (sFilespec, sBuffer, bLogError) ' if sBuffer is successfully written to sFilespec then WriteFile=True else if bLogError then Reporter.ReportEvent ... WriteFile=False else WriteFile="description of failure" end if end if end function ' ' retCode=WriteFile("c:\a\b\myfile.txt", "blah, blah", True) if retCode=False then 'error was logged by WriteFile(), exit test now ExitTest end if continue on with the test...
In the 2nd code example you can choose to process the error yourself (last parm set to False), or to let WriteFile() log the error (last parm set to True) and simply return the calling code a False when a failure is encountered.
-fyi, Terry
|
seminole
Junior Member
Reged: 05/18/06
Posts: 66
|
|
Post deleted by Terry Horwath
|
RKY
stranger
Reged: 08/22/06
Posts: 586
Loc: Bangalore, India
|
|
For more info on VB script along with example by section by section Look into this below ulr
http://www.html.dk/dokumentation/vbscript/ html-vss/vbstoc.htm
I hope this make sense
Regards, Ram.
--------------------
Hope this helps you,
- RKY
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Subject: include() method
Below is a simple chunk of code I have seen on a few sites (and in a few books) that provides a generic method for "including" any number of vbScript files in a program running in a non-QTP environment (such as WSH). Code:
'************************************************************************* ' ' Implements a simulated "include" capability in a vbScript, ' using ExecuteGlobal to ensure the "included" file's contents are ' available to all. ' ' from the public domain Old Dominion University website, at ' http://www.cs.odu.edu/~wild/cs477/Spring01/Examples/Script/wrox/Chapter05 ' ' ************************************************************************* ' Option Explicit ' ' ' Include() vbScript sub implements a generic "include" capability ' to your scripting library environment. ' Sub include(file) ' Dim fso, f, str ' Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.OpenTextFile(file, 1) str = f.ReadAll f.Close
ExecuteGlobal str End Sub ' ' ' Once the above sub is part of your main global library, you ' can then include any number of additional libs using the ' following statement. ' include "anotherVbScriptLib.vbs"
Keep in mind that this function is not recommended for use in QTP--in that runtime environment either use QTP's ExecuteFile() function or add the files to include on the Resource tab in the Test Options workflow.
-Terry Horwath
P.S. Here is an unbroken link to the interesting site recommended in the above posting:
http://www.html.dk/dokumentation/vbscript/html-vss/vbstoc.htm
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Subject: Working with a custom vbScript Class
This post is intended for those who have wanted to investigate writing and using custom vbScript classes to supplement their QTP scripting, or perhaps more realistically, their vbScript library development.
I am not claiming to be a vbScript expert when it comes to custom classes. Rather I wish to share the information I have learned over the last several months, information I wish I could have read about in one concise thread like this when I was getting started.
-Terry Horwath
Executing the Example
Attached to this posting is a file, classExample.txt. Save this file to your disk as classExample.vbs. While this example will run, all of the good bullet proofing for error checking have been stripped—out, so that the basic elements of a custom vbScript class can more easily explored.
As currently commented, this class code only executes under the Windows Scripting Host (WSH) runtime environment on your PC. Should you care to run it under QTP--which offers no real advantage for learning purposes--you will need to make some comment changes within the sleep() method in the class definition.
After saving the attachment as described above, double-click on the file. The code at the bottom of the file is intended to allow you to interact with the custom class, myClass, and its instantiated object, myObj. When executed you should see:
1. A small IE window is displayed. 2. A msgBox with some info about the window is displayed. 3. Thereafter following the msgBox instructions to conclusion.
Now, before diving into the full source code for this class, take the time to read the following sections which attempt to grow the example from the ground up.
vbScript Class Overview
When you see a programming language that supports “class” and “object” you tend to (or at least I tend to) think of a traditional object oriented programming (OOP) environment that supports the following general characteristics:
http://en.wikipedia.org/wiki/Object-oriented_programming
But vbScript’s support for “class” and “object” is more modest in scope:
http://www.microsoft.com/mind/1199/classes/classes.asp
To summarize, the vbScript class concept:
1. Does NOT support inheritance. So it is not possible to create a Collie class which inherits characteristics from a Dog class which inherits characteristics from a Mammal class, etc.
2. Does NOT support polymorphism. Kind of a related to inheritance, where for example a Dog class will “bark” and a Pig class will “oink” when they are asked to “speak” (in a class hierarchy where they inherited the base Speak() method from the Mammal class, then override that method to implement animal unique behavior).
3. DOES support encapsulation, an OO technique which conceals how a particular class is implemented, independent from objects that use the class’s Public Properties and Methods. Another way to think about encapsulation is to say it is the ability to hide implementation details while sharing higher level behavior.
It is this author’s opinion that the lack of inheritance and polymorphism are not major shortcomings in scripting environments such as WSH and especially QTP, where you are not trying to build large complex OO programs.
Encapsulation is then the primary reason to consider using vbScript classes. And, with encapsulation comes namespace control--which permits any number of class elements to be named foo as long as each of those elements resides in a different class (i.e. a different namespace).
vbScript Class Basics
Here is the basic syntax and keywords for the vbScript Class statement:
http://www.html.dk/dokumentation/vbscript/HTML/vsstmClass.htm
Using this syntax, lets start building a new custom class: Code:
class myClass
end class
The above class is of course useless, but none-the-less fully formed. You instantiate (fancy word for create) an object from this class using the following syntax: Code:
dim myObj set myObj = new myClass
Now we have a useless but fully formed object.
A Bit Less Useless Class
Now lets start adding some meat to the class. The first capabilities we explore are the built-in, but optional, methods:
Class_Initialize() http://www.html.dk/dokumentation/vbscript/HTML/vsevtinitialize.htm
Class_Terminate() http://www.html.dk/dokumentation/vbscript/HTML/vsevtterminate.htm
Code:
class myClass Private sub Class_Initialize() MsgBox("myObj has been created") End sub ‘ Private sub Class_Terminate() MsgBox("myObj has been terminated/destroyed") End Sub end class ‘ dim myObj set myObj= new myClass ‘implicitly execute Class_Initialize() myObj = Nothing ‘implicitly execute Class_Terminate()
Still pretty useless, but the above class and its instantiated object can be executed interactively in the WSH environment should you care to experiment.
The idea here is to place all your object initialization code statements in Class_Initialize() and all your tear-down code, such as closing windows, sessions, etc. in Class_Terminate().
Note: my evaluation of QTP’s (version 8.2) support for custom classes shows me its runtime fails to call the Class_Terminate() method when an object is implicitly destroyed when a test terminates prior to explicitly destroying the object. I consider this a bug.
Working with Class Properties
A Property is a named data variable of a class. Properties define object characteristics such as size, color, and screen location, or the state of an object, such as enabled or disabled.
At this point we add one Public and one Private Property, and the Private Property’s associated Get() and Let() methods to our class: Code:
class myClass Public iVar , Private iWidth ' Public Property Let Width(iPixels) iWidth=iPixels End Property ' Public Property Get Width() Width=iWidth End Property end class dim myObj set myObj= new myClass
In the above example we are using the Private and Public keywords, which while not unique to the Class statement, offer enforcement of “visibility” external to the Class. Public Class properties are visible within the Class block, as well as by code outside the Class block, but Private Class properties are visible only within the Class block.
Class Properties provide more complex support for control and access over data variables, but their syntax is similar to working with global variables: Code:
myObj.Width= 1234 ‘write (Private) iWidth indirectly through its Let method myWidth = myObj.Width ‘read (Private) iWidth indirectly through its Get method ‘ myObj.iVar = 1234 ‘write (Public) iVar directly myVar = myObj.iVar ‘read (Public) iVar directly ‘ myObj.iWidth=1234 ‘ERROR, (Private) iWidth is hidden from the caller myWidth =myObj.iWidth ‘ERROR, ditto…
First lets discuss the Public iVar class Property. It is nothing more than a glorified global variable, and its only advantage over a global variable is namespace control (i.e. in other words we could have an iVar in multiple classes without a naming collision).
Now for the much more interesting Private iWidth Property. Why have we gone to all this trouble to read and write the iWidth variable, indirectly through its associated Get and Set methods? The short answer is data encapsulation—-the iWidth variable can’t be accessed external to the class without using its Get and Let methods, but it still looks like a typical data variable to the outside world. The longer answer is hopefully explained with the extended example below, which shows error handling and bullet proofing code added to the Width Let Property: Code:
Public Property Let Width(iPixels)
if NOT isNumeric(iPixels) Then Exit Property End If if iPixels<250 Then '250 min pixel width enforced by the IE Object iWidth=250 elseif iPixels > gLib.getScreenWidth/2 Then iWidth=gLib.getScreenWidth/2 else iWidth=iPixels end if End Property
You could of course write a class method, or a global non-class function, to achieve the equivalent bullet proofing, but this use of class Get/Let Properties adds extensible error checking and data range enforcement to a seemingly simple data assignment statement.
There is another advantage to using class Get/Let Properties as well: unlike a global variable that can be altered from anywhere in your global code, the only way to write the iWidth variable in our custom object is through its Let Width() method. This provides a centralized means to determine (and when debugging, trap) when the value is modified and by who.
Note that within the class itself the Private iWidth variable can be accessed directly. This is because class code is always considered trusted. Note also that you can have a Let method without an associated Get method and visa-versa, depending on your needs.
Working with Class Methods
A class Method is nothing more than a vbScript Function or Subroutine encapsulated within a Class code block. Here again we can use the Private and Public keywords to control visibility outside of the class: Code:
class myClass Public function foo (parm1, parm2) do some work… bar() foo=someReturnValue end function ' Private sub bar () do some work internal to this class… end sub end class
In the above example the foo() method can be called from outside the class, but not the bar() subroutine. The bar() subroutine is meant to do class internal implementation work and therefore it is intentionally hidden from the world outside of the class. Here again we have another example of encapsulation in action.
Putting It All Together – Exploring the Attached Example in Detail
All of the keywords and concepts associated with a custom vbScript class have now been introduced and explained. Returning to the attached example, we will step through each line of code at the bottom of the file; which is the code intended to execute and use the custom class:
line #178 set myObj = new myClass A new object is created from the custom class. Anywhere from a little to a lot of work gets performed in this single statement, because the Class_Initialize() method is implicitly called.
line #188 myObj.Height = 400 line #189 myObj.Width = 200 These two lines of code explicitly set the height and width of the IE window we are about to spawn. Both of these statements are optional, and override the default window size established by the Class_Initialize() method.
line #191 myObj.Open(True) This line of code calls the required Open() class method, which does the heavy lifting to create and then invoke an IE window. This line of code demonstrates the power of encapsulation because not only is a lot of functionality implemented in this method, but the method also initializes the hidden IE object, ieObj, on line #25 used to maintain and interact with the spawned IE window (in this manner the foreground code works with the myObj object, while the class itself works with the much more complicated “Internet.Explorer” object). The Boolean value passed to this method determines if new lines of text written to window will be pre- or post-appending in the window. (It is counter-intuitive that you most often want to pre-append new lines to this type of “watch” window, so that the newest lines are always visible).
line #195 myObj.write("one" & vbCR) line #199 myObj.write("two" & vbCR) Well, these lines simply demonstrate writing to the just created IE Window. In real usage this would occur for the life of a test case, from any number of Actions (that have access to the myObj object), again and again, as the test progresses through its paces, occasionally writing status/progress messages to the window.
line #203 myObj.Close The myObj object is destroyed, which internally destroys the “Internet.Explorer” object and the IE window is deleted from the PC desktop.
Digging Deeper – The Full ieWindow Class
If you haven’t had enough yet…
The attached example is a stripped-down version of my full ieWindow class, which is available on this forum—-with a terse document—-in the following post:
http://www.sqaforums.com/showthreaded.php?Cat=0&Number=348572&page=0&vc=1
Substantially more functionality and bullet-proofing is contained in this real class--in particular--code to gracefully deal with a user interactively closing the IE window.
Note that unlike the attached example, the above full ieWindow class only executes in the QTP runtime environment.
|
EAS
Advanced Member
Reged: 01/22/02
Posts: 684
|
|
Terry, That's good stuff.
You could also add the use of the "Default" key word to the procedure name to enable a default method that can be used without specifying the name. By using something like:
Code:
Public Default Function Bar(strName)
You can call it from your Foo object like:
Code:
strXXX = Foo.Bar("Terry")
or Code:
strXXX = Foo("Terry")
Also, instead of creating your object in your library file you can do it in your script if you add a small helper function to your library.
Code:
Function GetClass() Set GetClass = New myClass End Function
Now in your actions you can do this:
Code:
Dim objFoo Set objFoo = GetClass
This allows you to create objects with a scope other than global. It also allows you to create as many objects as you want.
I generally use classes to wrap some object or to create libraries of utility methods. I frequently wrap dictionary objects in classes to store data and access it in ways that are filtered and manipulated through methods and properties.
Using classes can help build easy to use "frameworks" by organizing things into objects.
-------------------- TDForums.com
Edited by Tarun Lalwani (02/28/07 11:39 AM)
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
EAS,
Thanks for these comments and pointers.
The use of vbScript classes and their instantiated objects are very flexible. It was not my intention to indicate that they could only be used in the same manner as I presented them in my "introduction to vbScript classes" posting.
In particular, I did instantiate the object right after the class def in my example, thus making it a global object. I used this technique (which I really should not have done in an "introduction to..." type of post) because I am currently using classes to encapsulate my shared libs, each in their own class--using this technique it made sense to create one global object per library, to allow all QTP actions to reference each lib (and, more importantly for one lib to call another lib's "well known" object).
Thanks again for making these observations.
-Terry
P.S. Hey EAS, any chance you could edit your above post? I believe the last Code block is not terminated correctly, and is now forcing the entire thread to display about 15" wide.
Edited by Terry Horwath (02/28/07 06:36 AM)
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Subject: Calling a test case function from a Library Function
The following thread points out some rather unexpected behavior if you try to call a test case function from a function that is part of a vbScript library included by the test case. While this is a bit of a brain twister, and why you would want to do this is not readily apparent, you want to remember that this scenario is not supported by at least version 8.2 of QTP:
http://www.sqaforums.com/showflat.php?Cat=0&Number=362982&an=0&page=0#Post362982
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Subject: Working with the Dictionary Object
Code:
Option Explicit ' Dim strKey, myObj, myObj2 ' Set myObj = CreateObject("Scripting.Dictionary") Set myObj2 = myObj ' Environment("MyDictionary") = myObj2 Environment("MyDictionary").Add "x","value X" Environment("MyDictionary").Add "y","value Y" ' For Each strKey In myObj.Keys MsgBox strKey & ": " & myObj.Item(strKey) Next MsgBox "myObj Items Count: " & myObj.Count ' strKey="z" MsgBox strKey & ": " & myObj.Item(strKey) ' MsgBox "myObj Items Count: " & myObj.Count
In the above code (that can be executed in a QTP test case) there is only one Dictionary object, but three references to it: myObj, myObj2, and Environment("MyDictionary").
More importantly, this example points out why you should probably wrap a Dictionary object inside of a custom object that does some error checking: if you "read" a non-existant Dictionary element (as we do above using the non-existant 'z' key) the key and an Empty value is added to the Dictionary. (Seems to me that vbScript should throw an exception in that scenario, but it does not).
|
Jared_Quinert
Junior Member
Reged: 10/02/01
Posts: 12
Loc: Melbourne, Australia
|
|
A quick question regarding classes -
When I create a QTP script and define a class in the script, all is good. If I then move the class definition out to a function library and associate the function library with the script, it doesn't seem to be able to find it. Is there something simple I'm missing? Have built frameworks before but am a QTP/VBScript newbie.
Thanks in advance,
Jared
-------------------- ---------------------------
Software testing thoughts - http://www.quinert.com/blog/
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Jarad wrote:
Quote:
snip... When I create a QTP script and define a class in the script, all is good. If I then move the class definition out to a function library and associate the function library with the script, it doesn't seem to be able to find it. snip...
Hum... I do this all the time, as each of my included function libs are wrapped in a custom class. So I am not sure what the problem is here.
Reply with the following info and I will give it a look:
1. What is the exact error message from the failing line of QTP script code that fails in its attempt to instantiate an object from the class defined in the included lib?
2. Slim down the script to just the bare number of lines of code need to demonstate the problem. Do the same for the included lib. Then ZIP just those two files (the QTP "script" can be added as just script.txt, I will then create a real test case using my QTP 8.2).
3. Also be precise in how you are including the lib. For example are you using ExecuteFile() or including the lib in the Test Resource tab?
Hopefully I will spot something. Oh, also include your version of QTP (I am using 8.2 at this time).
-Terry Horwath
|
nimmala_rk
Newbie
Reged: 03/16/07
Posts: 12
|
|
Post deleted by Terry Horwath
-------------------- Rama Krishna
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Rama, while everyone likes to hear their effort is useful to others I ask that you and others please do not post raves, rants and other forms of content-free replies to this thread. These just clutter up the thread and make it difficult for others to find the real information.
Subject: Using Encoded vbScript Scripts in QTP
QTP currently (in all version up through this posting, which includes version 9.2) only supports including vbScripts in clear text. *.vbe scripts created using Microsoft's encoder/obfuscator from *.vbs scripts won't run under QTP. For more information refer to the following thread:
http://www.sqaforums.com/showflat.php?Cat=0&Number=366563
-Terry
|
thorwath
Veteran
Reged: 07/22/99
Posts: 3769
Loc: Grand Rapids, MI
|
|
Subject: Using Function Pointers in vbScript
Function pointers in vbScript? Who would have thought!
Well, the getRef() function is designed to return a reference to a procedure that can be bound to an event. And while there are some restrictions to using this function, especially in QTP (noted below), this capability may prove useful when you want to construct dynamic references to library functions.
The syntax for getRef() is (see online help for more details):
set funcPtr = getRef("functionName")
The first restriction is that "functionName" must be a text string that is the name of a function or sub that is currently in scope (i.e. in the current namespace where the getRef() statement is located). This feature would be much more useful if this restriction (which I found to be true in WSH as well as QTP) was not imposed.
A further QTP restriction occurs when trying to use the getRef() statement in a QTP script where the function being referenced is located in a library that is included by the script. The remainder of this article discusses that restriction, and a workaround for it.
This works: Code:
'Script code, no included vbScript lib ' Dim funcptr ' Sub foo () msgBox "in foo()" End Sub ' Set funcptr = getRef("foo") funcptr
While the following code fails (where lib1.vbs is included by the QTP test script): Code:
'Script code START *************************** ' Dim funcptr ' Set funcptr = getRef("foo") funcptr ' 'Script code END ***************************** ' 'lib1.vbs code START ************************* ' Sub foo () msgBox "in foo()" End Sub ' 'lib1.vbs code END ***************************
In the above code the failure occurs at the Set funcptr = getRef("foo") line, with an error message of "invalid procedure call or argument: 'getRef'". I can only guess why this fails, because clearly the foo() function is in scope (you can prove that yourself by calling it before the failing line of code). I am guessing is has something to do with the fact that QTP implements file inclusion in a manner that is not compatible with the interpreter's parm checking for the call to getRef(). But no matter, you are always in a grey area when the implementation is left up to each runtime environment (which is the case for file inclusion).
Now, here is one workaround to this failure (where lib1.vbs and lib2.vbs are included by the QTP test script): Code:
'Script code START *************************** ' Dim funcptr ' Set funcptr = setFuncPtr("foo") funcptr ' Set funcptr = setFuncPtr("bar") funcptr ' 'Script code END ***************************** ' 'lib1.vbs code START ************************* ' Sub foo () msgBox "in foo()" End Sub ' function setFuncPtr(sFuncName) set setFuncPtr = getRef(sFuncName) end function ' 'lib1.vbs code END *************************** ' ' 'lib2.vbs code START ************************* ' Sub bar () msgBox "in bar()" End Sub ' 'lib2.vbs code END ***************************
In the above code, the getRef() function is wrapped in a function, setFuncPtr(), arbitrarily contained in any included *.vbs file. I believe this wrapper function forces resolution later in runtime (I know that is a strange statement in an interpreted lang), OR that QTP bunches all code include in external libs into their own namespace. Whatever.
I include the 2nd lib, with the bar() sub, so that I could confirm that this workaround works when the function names, as text strings, specified by the test case reside in libs other than the one that contains the setFuncPtr() wrapper function.
This workaround was validated by me in QTP 8.2 and another forum member in version 9.2.
-Terry Horwath
|
Jared_Quinert
Junior Member
Reged: 10/02/01
Posts: 12
Loc: Melbourne, Australia
|
|
My other response appears to have not turned up. I have managed to find out that the solution is to put a factory function in the script which defines the class.
So the function library which defines your class has to look like this:
Code:
Function getMyClassInstance Set getMyClassInstance = New myClass End Function
Class myClass Dim fred
sub class_initialize fred="Fred" end sub End Class
Then, instead of
Set a=New myClass
use
Set a=getMyClassInstance
Bizarre...
Jared
Edited by XFlibble (03/20/07 05:56 PM)
|
|
Powered by UBB.threads™ 6.5.5
|