QTP – Automating Windows Calculator

by Anshoo Arora on October 28, 2009 | QTP/UFT | 31 Comments

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:

Function Library with TypeKey and CalculatedValue

Function Library with TypeKey and CalculatedValue

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
Execution Result

Execution Result

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.

Subscribe to Relevant Codes (by Anshoo Arora)
Hello! We're always posting interesting articles on Relevant Codes.
Why not subscribe so you don't miss out?

Leave a Comment

{ 29 comments… read them below or add one }

Pragya July 26, 2012 at 12:10 am

When are we getting the second part of this article Anshoo?

Pragya

Reply

Anshoo Arora July 26, 2012 at 1:35 pm

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 :(

Reply

Ramesh March 26, 2012 at 2:07 pm

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.

Reply

Ramesh March 12, 2012 at 2:52 pm

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

Reply

Anshoo Arora March 15, 2012 at 9:27 am

Ramesh: You can map each control to its window_id. It seems to be unique..

Reply

Ramesh March 12, 2012 at 2:48 pm

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

Reply

Anshoo Arora March 15, 2012 at 9:25 am

Ramesh, Win7 calculator may be more suitable with OR.. your observation is correct – there are no properties associated with any controls.

Reply

Pragya December 30, 2011 at 12:59 am

Hi Anshu. please let me know when we will be getting advanced topic on this article. Looking forward for your early response.

Reply

Sneha December 31, 2011 at 11:53 am

Happy New Year to All QTP Lovers, and Especially Anshoo Arora.

Reply

Manu Sekhar S September 29, 2011 at 11:40 am

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

Reply

prachi June 14, 2011 at 6:31 am

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”).

Reply

Anshoo Arora June 24, 2011 at 11:07 am

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?

Reply

Preeti November 27, 2010 at 12:39 am

Hello Anshoo Arora,

I am new to QTP. But the way you explain is superb. Thank you. Keep posting such useful articles.

Reply

Chintan shah September 8, 2010 at 9:18 am

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 …

Reply

Anshoo Arora September 8, 2010 at 11:25 am

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.

Reply

chintan shah August 25, 2010 at 6:52 am

i will keep U bugging with many issues which i will face ……. now on :))

Reply

chintan shah August 25, 2010 at 3:48 am

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 :))

Reply

niki August 25, 2010 at 12:07 am

Very useful

Reply

Nikhil April 28, 2010 at 11:23 pm

This is 2 gud 2 understand the DP n logic in the coding.
It improves the logical thinking about the program.

Reply

Guruprasad April 22, 2010 at 7:08 am

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

Reply

Anshoo Arora April 25, 2010 at 3:17 pm

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.

Reply

Akash Rastogi March 5, 2010 at 12:53 am

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

Reply

Anshoo Arora March 5, 2010 at 2:51 pm

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.

Reply

sachin November 13, 2009 at 10:54 pm

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

Reply

Anshoo Arora November 14, 2009 at 12:55 pm

Sure, Sachin. That’s a great idea. I will try to write a post on this topic soon.

Reply

Radhika November 9, 2009 at 1:42 pm

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

Reply

Anshoo Arora November 9, 2009 at 4:32 pm

Thank you!

Holidays are approaching now Radhika and my submissions are reducing exponentially :)

Reply

Anil October 31, 2009 at 2:53 am

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)

Reply

Anshoo Arora October 31, 2009 at 7:58 pm

Thank you for your kind words, Anil. I am deeply honored. :)

Reply

{ 2 trackbacks }

Previous post:

Next post: