I've been using the .net native properties to provide extra support for the controls in the application I'm working on.
An area I've been struggling with is to identify what type of .net control I'm working with. Qtp may recognise it as a swflist but the .net control type could be completely different to another type of swflist. I've found a simple way to determine the control type:
object.ToString
So if you wrap this around a msgbox box you can find out the .net obejct class you're working with:
msgbox swfwindow("a").swflist("abc").object.ToString
When I executed this against a control I have, it tells me that it's a system.windows.forms.checkedlistbox type. Perfect, I can now go and look up the methods for this in the MSDN Library.
This blog aims to detail solutions to everyday challenges involved in test automation using QTP, Quality Center (QC), Excel and Open Source Tools.
Tuesday, 3 April 2012
Wednesday, 21 March 2012
QTP Object Synchronisation
Performing synchronisation in scripts is something that should be straight forward - the .exist(0) method makes this extremely simple. However, things start to get messy if we need to program extra error handling around it - something that should be straight forwards ends up being several lines of code. If you repeat this several times over then it's not being very efficient.
A way around this is to call a generic synchronise routine each time you want to wait for an object to exist. By following this practice you can build custom error handling into the synchronise routine without bloating your main automation code. I've built this into my keyword framework so that I always call it before trying to interact with an object, therefore I know that the object must exist before I try to do anything with it. It keeps my code clean and improves the reliability of my scripts.
A basic version of this is below, you can call it by hard coding the maximum wait value or if you want to abstract it further, define the timeout value in an environment variable.
The intMaxWait variable is the time in seconds you are willing to wait. The function returns a true or false value depending on whether or not the object was found.
How to call it:
Function Code:
A way around this is to call a generic synchronise routine each time you want to wait for an object to exist. By following this practice you can build custom error handling into the synchronise routine without bloating your main automation code. I've built this into my keyword framework so that I always call it before trying to interact with an object, therefore I know that the object must exist before I try to do anything with it. It keeps my code clean and improves the reliability of my scripts.
A basic version of this is below, you can call it by hard coding the maximum wait value or if you want to abstract it further, define the timeout value in an environment variable.
The intMaxWait variable is the time in seconds you are willing to wait. The function returns a true or false value depending on whether or not the object was found.
How to call it:
blnSynced = SynchroniseOnObject(Browser("application a").Page("page b").WebElement("element c"), Environment("CustomTimeout"))
Function Code:
Function SynchroniseOnObject(objRepositoryItem, intMaxWait)
Dim blnObjectFound : blnObjectFound = False
Dim dtStart, intWaitedTime
Dim blnBreak : blnBreak = false
'get the current start time
dtStart = now()
do
'check if the object exists
If objRepositoryItem.Exist(0) Then
blnObjectFound = true
blnBreak = true
Else
'otherwise loop - calculate how long we have waited so far
intWaitedTime = datediff("s",dtStart,now())
If intWaitedTime > intMaxWait then
blnBreak = true
else
'put some code in here to trap any errors,popups etc
End if
End if
loop until blnBreak
SynchroniseOnObject = blnObjectFound
End Function
Thursday, 15 March 2012
QTP: How to post back to the Quality Center Execution Grid during test execution
One of the issues we face is that when our QTP tests fail is that we need to load up the QTP results to see what's happened. If a group of tests have all failed at the same point then usually it's due to the same reasons (typically environmental or a data error). If we can post some of this information back to the QC Exeuction Grid then it potentially saves us time from opening all of the results.
The code below will show you how to do this from within QTP. There are a few things to bear in mind:
The code:
Example:
The code below will show you how to do this from within QTP. There are a few things to bear in mind:
- Our framework uses a custom reporting function through which all pass, fails, warnings etc are passed. Therefore it allows us to single out errors and post them back to QC.
- The QC field has a limitation of 255 chars, so we use this only to post the last error. Our QC field is called "Error Details".
- It's used to give us a quick snapshot as to the cause of the failure so we can determine to rerun or investigate the result further. This isn't intended to replace results analysis - we don't "pass" tests until we've fully investigated the results.
The code:
Sub WriteToQCExecutionGrid(strValue)
Const QCFieldName = "Error Details" 'change this to match your QC field name
Dim strThisTestName
Dim objTSTestFactory
Dim objField
Dim objTestList, objTest
Dim blnTestFound : blnTestFound = false
Dim strInternalFieldName
Dim objQCTestInstance
'setup default values
strInternalFieldName = ""
'See if we're connected to QC
If not qcutil.IsConnected Then
exit sub
End if
'See it we're connected to a test lab test set
If (qcutil.CurrentTestSet is nothing) Then
exit sub
end if
'Connect to the ts test factory - this represents the execution grid
Set objTSTestFactory = qcutil.CurrentTestSet.TSTestFactory
'Now search through the fields to see if we can find one called Error Details"
For each objField in objTSTestFactory.Fields
If (objField.Property.UserLabel = QCFieldName) then
strInternalFieldName = objField.Name
Exit for
End if
Next
'If we didn't find the field name, exit
If strInternalFieldName = "" Then exit sub
strThisTestName = qcutil.CurrentTestSetTest.Name
'Now find this test in the execution grid
Set objTestList = objTSTestFactory.NewList("")
For Each objTest In objTestList
If (objTest.Name = strThisTestName) Then
'Test was found, so update flag and exit
Set objQCTestInstance = objTest
blnTestFound = true
Exit for
End If
Next
If not blnTestFound Then
exit sub
End If
'objQCTestInstance will now hold the test that we need to update
objQCTestInstance.Field(gstrInternalFieldName) = strValue
objQCTestInstance.post
End Sub
Example:
Call WriteToQCExecutionGrid("Failed to Load Webpage")
Tuesday, 14 February 2012
QTP: Getting the properties of childobjects
I've been doing a lot of work with childobjects, and one of the issues I've faced when working with the returned collection is determining what runtime properties each object in the collection has. Once you know what properties the object has, it makes it easier to filter your childobject descriptions or choose the right object in the collection to work with.
Unfortunately QTP has lousy debug capabilities in this area so I started researching ways in which you can display the properties of QTP objects and I came across this useful post.
I tweaked this a little bit to produce a function that prints out all of the object properties to the debug window. When combined with some code to iterate the childobjects you can quickly see what all the properties are. This has been tested with QTP 11.
The code
First of all, here's the function to print out all of the object properties
Then combine with some code that retrieves a collection of childobjects from a QTP object:
The result is that all of the properties of the children are output to the print window.
Unfortunately QTP has lousy debug capabilities in this area so I started researching ways in which you can display the properties of QTP objects and I came across this useful post.
I tweaked this a little bit to produce a function that prints out all of the object properties to the debug window. When combined with some code to iterate the childobjects you can quickly see what all the properties are. This has been tested with QTP 11.
The code
First of all, here's the function to print out all of the object properties
Sub PrintObjectProperties(objQTPObject)
'This article helped with this function:
'http://motevich.blogspot.com/2008/11/qtp-object-indentification-properties.html
Const HKEY_LOCAL_MACHINE = &H80000002
Dim objReg, strKeyPath
Dim arrObjectProperties, i
Set objReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Mercury Interactive\QuickTest Professional\MicTest\Test Objects\" & objQTPObject.GetROProperty("micclass") & "\Properties"
objReg.EnumValues HKEY_LOCAL_MACHINE, strKeyPath, arrObjectProperties
'now we've got an array of the properties, output all of the runtime properties
Print objQTPObject.ToString
Print "micclass:" & objQTPObject.GetROProperty("micclass")
If IsNull(arrObjectProperties) Then
Print "** Object RO Properties could not be found for this class**"
Else
For i = 0 to UBound(arrObjectProperties)
Print arrObjectProperties(i) & ":" & objQTPObject.GetROProperty(arrObjectProperties(i))
Next
End If
End Sub
Then combine with some code that retrieves a collection of childobjects from a QTP object:
Dim objDesc,objDescCol
Dim objQTPObject
Dim n
Set objQTPObject = Browser("A").Page("B")
Set objDesc = Description.Create
'Add any other description filters here
Set objDescCol = objQTPObject.ChildObjects(objDesc)
If objDescCol.count > 0 Then
For n = 0 to (objDescCol.count-1)
Print "Child Object " & n
Call PrintObjectProperties(objDescCol(n))
Print ""
Next
End If
The result is that all of the properties of the children are output to the print window.
Thursday, 9 February 2012
SwfListView: Determining the image in a listview using QTP
Some applications use an image in a listview to display information about the status of the item. Unfortunately, QTP does not provide any methods to access this information using GetROProperty.
By using the .object property we can get access to the exposed .net properties and methods of the listview.
Take the following screenshot:
The application is using a red and green icon to display the status. What we want to do is know which icon is being displayed. The following code will output this information to the debug window:
In my example, ImageIndex is set to 1 when the green icon is shown.
For more information and to see what other properties/methods are available, see the ListView and ListViewItem msdn documentation.
By using the .object property we can get access to the exposed .net properties and methods of the listview.
Take the following screenshot:
The application is using a red and green icon to display the status. What we want to do is know which icon is being displayed. The following code will output this information to the debug window:
Set oItems = SwfWindow("Application A").SwfListView("lvwListView").Object.Items
For n = 0 to oItems.count -1
print "Item index " & n & ", ImageKey=" & oItems.Item(n).ImageKey
print "Item index " & n & ", ImageIndex=" & oItems.Item(n).ImageIndex
Next
Note that we are using two properties here - imagekey and imageindex. This is because the development team may implement this image in two different ways, so one of these pieces of information will tell you what you need to know.In my example, ImageIndex is set to 1 when the green icon is shown.
For more information and to see what other properties/methods are available, see the ListView and ListViewItem msdn documentation.
Tuesday, 7 February 2012
Executing Coded UI Tests from Quality Center
A few months ago I was exploring the features and practicalities of using Coded UI for automation. One consideration to take into account was whether or not coded UI tests could be executed from Quality Center.
First of all, why would you want to do this? Well, the QA process at the client site was all geared around Quality Center - test cases, metrics, defects etc so to go down a pure CodedUI route would mean switching all tooling and processes over to TFS. If you've worked in large organisations you'll appreciate that's a fairly long roadmap!
An iterim solution to was to bridge this gap by seeing if we could execute CodedUI tests from Quality Center.
In this article I will show you the proof of concept I managed to implement. We never went down the CUI route so I haven't been able to spend any more time refining this, but it will get you off the ground and help you explore the possibilities around this integration. This article assumes you have some experience using Visual Studio and Coded UI.
First of all, why would you want to do this? Well, the QA process at the client site was all geared around Quality Center - test cases, metrics, defects etc so to go down a pure CodedUI route would mean switching all tooling and processes over to TFS. If you've worked in large organisations you'll appreciate that's a fairly long roadmap!
An iterim solution to was to bridge this gap by seeing if we could execute CodedUI tests from Quality Center.
In this article I will show you the proof of concept I managed to implement. We never went down the CUI route so I haven't been able to spend any more time refining this, but it will get you off the ground and help you explore the possibilities around this integration. This article assumes you have some experience using Visual Studio and Coded UI.
The goals
In order for this to work, the following criteria needs to be supported by the solution:
- CUI Test Cases must be represented in Quality Center.
- CUI Test Cases must be launched by the automatic runner featur
- The execution status of the test must be captured.
- A meaningful execution report / logfile must be attached to the results to support analysis.
The limitations
There were a couple of design factors to take into account:
- Our CUI tests were designed on a 1 to 1 basis, i.e 1 CUI test represented 1 test case. Multiple iterations were not factored into the design. If your CUI test does use multiple iterations, then you will need to adjust the results analysis function to determine the overall run status for the test. There may also be some clever ways to change the command line execution to run specific iterations.
- A QC remote agent feature is not supported so an instance of Quality Center needs to be run on each machine where you are executing the test. I suggest using the standalone QC client exe (the one that doesn't use IE) so that CUI doesn't get confused with the QC browser.
Implementation
To make this article easier to digest, I've split it up into 4 main stages:
- Installing mstest.exe on the client machines.
- Compiling the CUI test and placing the dll on the client machine.
- Creating a VAPI-XP test in Quality Center
- Executing the CUI test and analysing the results
1 - Installing mstest.exe on the client machines
mstest.exe is required to execute the coded ui tests, it's a command line tool which you use to launch the tests. We will invoke mstest.exe from Quality Center and tell it which coded ui test to execute.
You will need to install the agent as an interactive process. This Microsoft Article explains more. If you don't have the CD it looks like you can download the agent here.
2 - Compiling the CUI test and placing the dll on the client machine
The next step is to compile your tests and save them onto the client machine. The basics of how to do this are as follows:
- Load your CUI project in Visual Studio.
- Right click the project and select “build”.
- In the output window, note the directory that the dll is compiled to.
- Copy the entire directory to the the host machine where you will be executing the test on(ensure you place it on the C: drive of the host machine, this may have been a system policy in place where I worked but I couldn't launch the tests from any other drive).
Note: If you plan to run a test on a machine where Visual Studio is not installed, you will need to compile it with all of the supporting dll's copied into the local folder, as per the screenshot below:
3 - Create a VAPI-XP test in the Quality Center test plan
You will need to create a test in Quality Center that represents the CUI Test. This is so that you can run it from the test lab. To do this, create a VAPI-XP test and then write some vbscript code that calls the CUI test:
1) Navigate to the QC Test Plan
2) Select "Tests" > "New Test".
- Type: VAPI-XP Test
- Name: Give it a relavent name
5) Click on Finish.
8) Now you will need to modify the code. The following lines of code will need to be changed in accordance with your setup:
- Dim strPathMSTestExe : strPathMSTestExe = "<path to where mstest.exe is installed>"
- Dim strTestContainerDLL : strTestContainerDLL = "<path to the compiled test dll>"
- Dim strResultsDirectory : strResultsDirectory = "<path to a directory where the results can be saved>"
- Dim strTestName : strTestName = "<the name of the coded ui test to run>"
Once you've done this, the test is ready to execute from the test lab.
4 - Executing the CUI Test and Analysing the Results
To execute the test, simply add it to a Quality Center test set and run it locally (I'm assuming that having come this far you can manage this!).
Remember the limitation we have is that it can only be run locally (unless you want to program some sort of agent yourself). Therefore I recommend running QC from the standalone client so that the CUI test doesn't get confused with any QC IE sessions that may be open.
I have programmed a few functions to analyse the results (the .trx file), retrieve any attachments and upload them to the QC. These are attached to each individual run .The functions performing this are called:
- GetResultsXMLStatus
- AttachFileToResults
- GetArrayOfAttachments
These can be found at the bottom of the vbscript code.
Note: This method is based on our setup that one test equals one iteration. If you run multiple iterations within a single test then you may need to implement your own way of analysing the results.
Closing Comments
This article demonstrates a proof of concept that CUI tests can be executed through Quality Center. Unfortunately I'm no longer engaged on a project using CodedUI so I haven't been able to take this further.
I welcome any comments, useful suggestions or enhancements you've been able to make. Hopefully this should give you enough help to get off the ground!
Monday, 30 January 2012
QTP Notify: a simple utility designed to display notifications in the system tray
QTP Notify is a simple utility designed to display notifications in the system tray. The purpose of it is to display useful information when a test is executing in way that does not take focus away from the application under test. This can be useful for debugging tests or understanding how far through execution a test is without interfering with the desktop.
| Add caption |
The download contains 3 files:
- The application (QTPNotifier.exe)
- The QTP function that calls the notification (RaiseNotification), and
- An Example QTP 11 test.
Setting Up
To setup and integrate this with your tests:
- Copy the QTPNotifier.exe application to your computer or network drive.
- Include the RaiseNotification function in your framework.
- Modify the "NPATH" constant in the function so that it points towards the location where you saved QTPNotifier.exe.
- In your test scripts call the RaiseNotification function, an example would be: Call RaiseNotification("Title Test","Message Test")
How it works:
The application polls the directory where it's saved to and looks for a text file with the format "<computername>notify.txt". When it finds the file, it reads the first line as the title and the second line as the message. It deletes the file and then displays a notification bubble in the notification area. The QTPNotifier.exe application will stay alive for another 60 seconds and repeat if another message is found. If no notification has been raised in the last 60 seconds the application will naturally terminate.
Things to note:
- Theres a small overhead each time you call this whilst the function searches for running processes (might be a second on some machines). This is useful as the QTP Notify application needs messages to have at least 100 milliseconds between each notification.
- Sometimes the notification appears behind the current window - this is a known issue with Windows XP, usually a reboot fixes this.
- If you are relying on low level mouse moves and clicks then you might click the notification bubble by accident if the mouse is clicked in the bottom right area. You could modify the function to disable itself if a certain environment variable is set.
- It's not designed to be robust or perfect...but it does the job for me!
Subscribe to:
Posts (Atom)





