In this article, we will see a few interesting ways to automate the Windows Calculator with QTP. To ensure the concepts in this article are not too overwhelming, I have divided it into 2 parts. The first one discusses a few basics and creates a routine that can be used to easily set values to, and retrieve from it. The concepts in this article should also serve as an excellent way of understanding the automation process with QTP, how functions can help increase code reuse, and why at times its extremely important to validate user-input.
Let’s launch the calculator through code:
SystemUtil.Run "calc.exe" |
Now, we have the calculator object launched. Let’s see if we can create a few statements in QTP that act as users to perform some calculations. For this example, let’s calculate 10*20:
Window("nativeclass:=SciCalc", "index:=0").WinButton("text:=1").Click '1 -> 1 Window("nativeclass:=SciCalc", "index:=0").WinButton("text:=0").Click '0 -> 10 Window("nativeclass:=SciCalc", "index:=0").WinButton("text:=\*").Click '* -> 10* Window("nativeclass:=SciCalc", "index:=0").WinButton("text:=2").Click '2 -> 10*2 Window("nativeclass:=SciCalc", "index:=0").WinButton("text:=0").Click '0 -> 10*20 Window("nativeclass:=SciCalc", "index:=0").WinButton("text:==").Click '= -> 10*20= MsgBox Window("nativeclass:=SciCalc", "index:=0")_ .WinEdit("nativeclass:=Edit").GetROProperty("text") |
Notice we have substitued a “\” before *. This is because * is a special Regex character and all special regex characters must have “\” before them to identify them correctly. You can also execute the same code without the “\” and test the result.
The above code can be simplified using a With..End With statement:
With Window("nativeclass:=SciCalc", "index:=0") .WinButton("text:=1").Click '1 -> 1 .WinButton("text:=0").Click '0 -> 10 .WinButton("text:=\*").Click '* -> 10* .WinButton("text:=2").Click '2 -> 10*2 .WinButton("text:=0").Click '0 -> 10*20 .WinButton("text:==").Click '= -> 10*20= MsgBox .WinEdit("nativeclass:=Edit").GetROProperty("text") End With |
I covered the above With..End With block because at times when properties change, you only have to update the property of the Window object once, and not 8 times as you would in the previous code snippet.
We can still simplify this process further, by creating a function. With the help of the function, we can avoid writing long and the same lines of code each time we need to perform the same operation. This saves time, and when you need to make changes, it simplifies maintenance and increases code reuse. Let’s create two functions, then. One will type the key, and the other will retrieve the output from the calculator:
'vKey: Key you want to press Function TypeKey(vKey) '* is a special regex character 'We will put a "\" before it to let QTP know that we are using a literal, not a regex Select Case vKey Case "*" vKey = "\" & vKey End Select With Window("nativeclass:=SciCalc", "index:=0") .WinButton("text:=" & vKey).Click End With End Function |
Function CalculatedValue CalculatedValue = Window("nativeclass:=SciCalc", "index:=0")_ .WinEdit("nativeclass:=Edit").GetROProperty("text") End Function |
Create a function library and copy both functions in it. Then, go to “File” menu and click “Associate Library [LibraryName] with ‘Test’”. Right now, your library should look something like this:
Let’s now use the function that we have created above to perform the same calculation. In your test, you will have:
TypeKey "1" TypeKey "0" TypeKey "*" TypeKey "2" TypeKey "0" TypeKey "=" MsgBox CalculatedValue |
Notice how we have compacted our code from the very first code snippet to the one above.
We have already talked about substituting a “\” before a special regex character. The calculator has 5 keys that include such characters. They are:
* + +/- . M+
We need to incorporate all special regex characters above in our Select-Case block. Thus, we’re now ready to manipulate the TypeKey function above, and create one that will input all sorts of keys from the users, make sure the special characters are followed by a “\” sign, and retrieve the output from the calculator.
Function TypeKey(vKey) 'Use a Select block for special regex characters Select Case vKey Case "*", "+", "+/-", "." vKey = "\" & vKey Case "M+" vKey = "M\+" End Select With Window("nativeclass:=SciCalc", "index:=0") .WinButton("text:=" & vKey).Click End With End Function |
Our function is ready! It is now capable of taking any sort of input from the user and retrieve the output. Let’s put the above function in use:
TypeKey "1" TypeKey "*" TypeKey "2" TypeKey "+" TypeKey "3" TypeKey "=" MsgBox CalculatedValue |
Now, we will begin with the tricky part. Well, not really. This is still the first topic, so we’ll keep it quite easy. We still haven’t created any sort of validation, yet. We are going to manipulate this code a few times and compact it further. We will do this to ensure that our script does not stop because of a user error. For example, if you type “10″ instead of “1″, then “0″, QTP will error out. That is because the calculator does not have any key greater than 9. In other words:
'This is Correct TypeKey "1" '1 exists in the calculator TypeKey "0" '0 exists in the calculator 'This is incorrect TypeKey "10" '10 does not exist in the Calculator |
To avoid occurrence of such user errors, we can begin by creating an array of all keys available to the calculator:
Dim arrCalcKeys arrCalcKeys = Array("Backspace", "CE", "C", "MC", "MR", "MS", "M+", "sqt", "%", "1/x", "=", "/",_ "*", "-", "+", ".", "+/-", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0") |
Now, we can run all our validations against this array. If a user enters any key that is outside this array, that means, there is an error which must be handled. This can help us create a function that will be used solely for purposes of validation. Let’s call it, IsKeyLoaded.
Function IsKeyLoaded(vKey) Dim arrCalcKeys, iCalcKey IsKeyLoaded = False 'Array with all Calculator Keys arrCalcKeys = Array("Backspace", "CE", "C", "MC", "MR", "MS", "M+", "sqt", _ "%", "1/x", "=", "/", "*", "-", "+", ".", "+/-", "1", "2", _ "3", "4", "5", "6", "7", "8", "9", "0") 'Loop through all Array items and attempt to find vKey For Each iCalcKey in arrCalcKeys 'If the Array Item matches with "vKey", Exit Loop. Return True. If CStr(iCalcKey) = CStr(vKey) Then IsKeyLoaded = True Exit For End If Next End Function |
IsKeyLoaded contains the array we created above, and a For-Loop that will check the Input Key against the Keys in the Array. If the 2 keys match, we’re good. If the 2 keys don’t match, that means, the user entered an invalid value. But, we’re in the clear because we now have the error handling for that! This also means that because of an invalid input, our script won’t stop.
You won’t believe we have come this far, so quickly. Remember the “TypeKey” function we created earlier? We will incorporate “IsKeyLoaded” in “TypeKey” and create our validation component.
Function TypeKey(vKey) 'If Key is not found then, Exit Function If Not IsKeyLoaded(vKey) Then Exit Function End If 'Rest of the function remains the same: Select Case vKey Case "*", "+", "+/-", "." vKey = "\" & vKey Case "M+" vKey = "M\+" End Select With Window("nativeclass:=SciCalc", "index:=0") .WinButton("text:=" & vKey).Click End With End Function |
Let’s put the code we have created now into practice. We will also use the “CalculatedValue” function we created earlier. For the sake of experiment, let’s provide our function with 2 invalid keys: A and B. Notice how these keys will not be entered to the Calculator, instead, the function will exit if it finds anything that is outside the scope of our array: arrCalcKeys.
TypeKey "A" 'Ignore TypeKey "1" 'Valid TypeKey "B" 'Ignore TypeKey "2" 'Valid TypeKey "3" 'Valid TypeKey "+" 'Valid TypeKey "1" 'Valid TypeKey "=" 'Valid MsgBox CalculatedValue '124 |
Our script didn’t stop regardless of the user error, and was able to retrieve the output nonetheless. In this article we learned how we can begin from scratch and create a highly usable code block.
{ 29 comments… read them below or add one }
When are we getting the second part of this article Anshoo?
Pragya
Pragya: I had just a small portion remaining for this article. I will revise this article and add it here itself. But, it may be a few weeks before I may be able to get to it because of prior obligations :(
Thank you Anshoo.
Lets say i like to click on a number through QTP on calc. In that case how QTP would know the window Id of that during run time?
To identify each button, do i need to get the window_id’s of all buttons?. Later how i can approach.
Could you explain me with some more clarity.
Hi,
For windows 7 calculator , i noticed that when i spy on any object there is no text property value.
I am trying to work out on this..I did not get solution..can please advice me on this..i tried some ways to get output..below is my script.
Dim oDesc ‘Description Object
Dim colObject ‘object collection
Set oDesc = Description.Create
oDesc(“micclass”).value=”WinButton”
Set colObject=Window(“Calculator”).ChildObjects(oDesc)
Obj=colObject.count()
For i = 1to obj
colObject(i).highlight
propval=colobject(i).getroproperty(“text”)
msgbox propval
Next
-Ramesh
Ramesh: You can map each control to its window_id. It seems to be unique..
Hi,
For windows 7 calculator , i noticed that when i spy on any object there is no text property value.
I am trying to work out on this..I did not get solution..can please advice me on this..
-Ramesh
Ramesh, Win7 calculator may be more suitable with OR.. your observation is correct – there are no properties associated with any controls.
Hi Anshu. please let me know when we will be getting advanced topic on this article. Looking forward for your early response.
Happy New Year to All QTP Lovers, and Especially Anshoo Arora.
Hi Anshoo,
Its a very nice learning.
Do you have any article which focus on VC++ applications as an example.
Or any other scripting examples on windows applications other than inbuilt flight reservation application
Regards,
Manu
Hi Anshoo,
I have used this approach to open notepad and it was working fine earlier :
Window(“Window”).WinButton(“start”).Click
Window(“Window”).Type(“R”)
Dialog(“Run”).WinEdit(“Open:”).Type “notepad”
Now when I run the same code ,in local it works .But fails in server machine with error:
Cannot find the “Open:” object’s parent “Run” (class Dialog). Verify that parent properties match an object currently displayed in your application.
Line (33): “Dialog(“Run”).WinEdit(“Open:”).Type “notepad”".
The dialog is in OR,and it works in local machine.Do you see any familiar server issue here .I have tried with adding the dialog again.
But the problem seems here with Type command not working on Window(“Window”).
Prachi: If you’re testing this scenario in an Remote Desktop session, open the session and run the test. Do not minimize the window or close it and see if it works?
Hello Anshoo Arora,
I am new to QTP. But the way you explain is superb. Thank you. Keep posting such useful articles.
Hi Anshoo,
I have one doubt :
Can we pass array reference or dictionary object reference to Environmental variable ? and if possible can you please tell me more about GlobalDictionary Object ?? I know how to create reserve objects by creating new registry from registry key …
Chintan,
Please see below:
Can we pass array reference or dictionary object reference to Environmental variable? Yes.
If possible can you please tell me more about GlobalDictionary Object? See here.
i will keep U bugging with many issues which i will face ……. now on :))
Anshoo arora … U r simply superb !! i have never seen anyone sparing so much time on his portal and replying everyones query .. U rock man .. keep it up :))
Very useful
This is 2 gud 2 understand the DP n logic in the coding.
It improves the logical thinking about the program.
Hello Anshoo,
I am a newbie to QTP and i was trying it with the flight application.
I did a spy on the Menu object. I noticed that none of the properties holds the values present under the menu object. Ex: File –> New Order.
But yet the QTP recognizes these objects when i run the script.
How does the QTP recognize these objects under file menu?
Regards,
Guruprasad R
It recognizes the items through the Menu label; Menu Child Item. Its the same way QTP recognizes everything else, actually – in a hierarchical manner. I doubt that the values can be spied on, but during replay QTP should replay it just fine.
Hi Anshoo,
This way article is summed up quite nice, easy and simple. Great work !!!
When will add the next article (Automating Windows Calculator Part 2) in this series and update this article wih link to “Automating Windows Calculator Part 2″.
I am looking for some article where I can learn, how to design a KeyWord Dirven Testing Framework for QTP.
Please help. ASAP.
Akash Rastogi
9811170395
Hi Akash,
Thank you for your feedback!!
I am currently working on a few articles and have about 10 drafts which need to be published, including the part 2 of this article. It will be released soon :)
The following article shows the types of frameworks and gives some details as to what they do and how they are created: http://www.ibm.com/developerworks/rational/library/591.html
I hope this helps.
Hi Anshoo,
I am following your tips and tricks frm last 2 mnths.Its really working great for me..
Can we have some brief discussion on arrays ?
Some questions like:
How to use arrays for datatable to retrieve values?
How to use arrays for childobjects?
and some more….
regds,
Sachin
Sure, Sachin. That’s a great idea. I will try to write a post on this topic soon.
Hey Anshoo,
Very good one….
Your articles are helping me a lot in understanding and learning qtp….keep up the good work…hope to see many such good articles in future….
Radhika
Thank you!
Holidays are approaching now Radhika and my submissions are reducing exponentially :)
Hey Anshoo,
the way u program and present logic is very good .
I m following and using urs tricks for last two years.
Expecting u help this community in future also (with out asking any consulting free)
Thank you for your kind words, Anil. I am deeply honored. :)
{ 2 trackbacks }