| <?xml version="1.0" encoding="UTF-8"?> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <!DOCTYPE html |
| PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
| <html lang="en-us" xml:lang="en-us"> |
| <head> |
| <meta name="DC.Type" content="topic"/> |
| <meta name="DC.Title" content="Creating applications for testing"/> |
| <meta name="DC.Format" content="XHTML"/> |
| <meta name="DC.Identifier" content="WS2db454920e96a9e51e63e3d11c0bf69084-7ec5_verapache"/> |
| <title>Creating applications for testing</title> |
| </head> |
| <body id="WS2db454920e96a9e51e63e3d11c0bf69084-7ec5_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7ec5_verapache"><!-- --></a> |
| |
| <div> |
| <p>You can create applications and components that can be |
| tested with automated testing tools such as HP QuickTest Professional™ (QTP). The information in this topic is |
| intended for Flex developers who write applications |
| that are tested by Quality Control (QC) professionals who use these |
| testing tools. For information on installing and running the Flex |
| plug-in with QTP, QC professionals should see <em>Testing Adobe Flex Applications with HP QuickTest Professional</em>.</p> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ffb_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ffb_verapache"><!-- --></a> |
| <h2 class="topictitle2">About automating applications with |
| Flex</h2> |
| |
| |
| <div> |
| <p>The automation feature provides developers with the ability |
| to create applications that use the automation APIs. You can use |
| these APIs to create automation agents or to ensure that your applications |
| are ready for testing. In addition, the automation feature includes |
| support for the QTP automation tool.</p> |
| |
| <p>When working with the automation APIs, you should understand |
| the following terms: </p> |
| |
| <ul> |
| <li> |
| <p> |
| <em>automation agent</em> (or, simply, <em>agent</em>) — |
| An agent facilitates communication between an application and an |
| automation tool. The Flex Automation Package includes a plugin that |
| acts as an agent between your applications and the QTP testing tool.</p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <em>automation tool</em> — Automation tools are applications |
| that use the data that is derived through the agent. These tools |
| include QTP, Omniture, and Segue.</p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <em>delegates</em> — Flex framework components are instrumented |
| by attaching a delegate class to each component at run time. The <em>delegate class</em> defines |
| the methods and properties required to perform instrumentation.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The following illustration shows the relationship between an |
| application, an agent, and an automation tool.</p> |
| |
| <div class="figborder"> |
| <img src="images/fc_automationtool_agent_flexapp.png" alt="The relationship between a Flex application, an agent, and an automation tool."/> |
| </div> |
| |
| <p>As this illustration shows, the automation tool uses an agent |
| to communicate with the application built with Flex. The agent can |
| be an ActiveX control or other type of utility that fascilitates |
| the interaction between the tool and the application.</p> |
| |
| <p>The Flex automation feature includes the following:</p> |
| |
| <ul> |
| <li> |
| <div class="p">Automation libraries — The SWC files in the libs/automation |
| directory are the implementations of the automation API for the |
| Flex framework components. The following table describes these SWC |
| files. |
| <div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all"> |
| |
| |
| <thead align="left"> |
| <tr> |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e114"> |
| <p>SWC file</p> |
| |
| </th> |
| |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e120"> |
| <p>Description</p> |
| |
| </th> |
| |
| </tr> |
| |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for the core Flex |
| classes. This includes the Halo component set.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_agent.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the classes for creating a custom |
| agent.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_dmv.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for the Flex charting |
| and AdvancedDataGrid classes.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_air.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for AIR.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_airspark.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for the Spark components |
| that are used in AIR.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_spark.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for the Spark component |
| set.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>automation_flashflexkit.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the delegates for the FlashFlexKit.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>qtp.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the classes that allow QTP to communicate |
| with an application built with Flex.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e114 "> |
| <p>qtp_air.swc</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e120 "> |
| <p>Provides the classes that allow QTP to communicate |
| with AIR applications.</p> |
| |
| </td> |
| |
| </tr> |
| |
| </tbody> |
| |
| </table> |
| </div> |
| |
| </div> |
| |
| </li> |
| |
| <li> |
| <p>QTP files — The QTP files let QTP and applications built |
| with Flex communicate directly. You can only use these files if |
| you also have QTP. These files include the QTP plug-in, a QTP demonstration |
| video, a QTP-specific environment XML file, and the QTP-specific |
| libraries, qtp.swc and qtp_air.swc. For more information, see <em>Testing Adobe Flex Applications with HP QuickTest Professional</em>.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fda_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fda_verapache"><!-- --></a> |
| <h2 class="topictitle2">Tasks and techniques for testable applications |
| overview</h2> |
| |
| |
| <div> |
| <p>Flex developers should review the information about tasks |
| and techniques for creating testable applications, and then update |
| their applications accordingly. QC testing professionals who use |
| QTP should use the documentation provided in the separate book, <em>Testing Adobe Flex Applications with HP QuickTest Professional</em>. |
| That document is available for download with the Flex plug-in for |
| QTP.</p> |
| |
| <p>Use the following general steps to create a testable application:</p> |
| |
| <ol> |
| <li> |
| <p>Review the guidelines for creating testable applications. |
| For more information, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a4a_verapache">Creating |
| test-friendly applications</a>.</p> |
| |
| </li> |
| |
| <li> |
| <p>Prepare the application to load the automation classes at |
| run time or compile time.</p> |
| |
| <ul> |
| <li> |
| <p>To create an application |
| that loads the automation classes at run time, you compile it as |
| normal. At run time, you load your application into a wrapper SWF |
| file that has the automation libraries built in. This wrapper SWF |
| file uses the SWFLoader to load your application SWF file that you |
| plan to test only at run time. For more information, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a48_verapache">Using |
| run-time loading</a>. </p> |
| |
| </li> |
| |
| <li> |
| <p>To compile an application that includes the automation classes, |
| you include the needed automation libraries at compile time. Compile |
| the application with the automation SWC files by using the compiler's <samp class="codeph">include-libraries</samp> option. |
| For information on the compilation process, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a4d_verapache">Using compile-time |
| loading</a>.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </li> |
| |
| <li> |
| <p>Prepare customized components for testing. If you have custom |
| components that extend UIComponent, make them testable. For more |
| information, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a51_verapache">Instrumenting |
| custom components</a>.</p> |
| |
| </li> |
| |
| <li> |
| <p>Create an HTML wrapper that follows proper application naming |
| practices. For more information, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf67b82-7fe7_verapache">Writing |
| the wrapper</a>.</p> |
| |
| </li> |
| |
| <li> |
| <p>Deploy the application's assets to a web server. Assets can |
| include the SWF file; HTML wrapper and related files; external assets |
| such as theme files, graphics, and video files; module SWF files; |
| resource modules; CSS SWF files; and run-time shared libraries (RSLs). |
| For information about what files to deploy with your application, |
| see <a href="flx_deployingoverview_dp.html#WS2db454920e96a9e51e63e3d11c0bf69084-7f1a_verapache">Deployment |
| checklist</a>.</p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a4d_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a4d_verapache"><!-- --></a> |
| <h2 class="topictitle2">Using compile-time loading</h2> |
| |
| |
| <div> |
| <p>When you embed functional testing classes in your application |
| SWF file at compile time, you increase the size of the SWF file. |
| If the size of the application SWF file is not important, you can |
| use the same SWF file for functional testing and deployment. If |
| the size of the SWF file is important, you typically generate two SWF |
| files: one with functional testing classes embedded and one without. </p> |
| |
| <p>To compile a testable application, you must reference the necessary |
| automation SWC files with the <samp class="codeph">include-libraries</samp> compiler |
| option. Typically, this includes the automation.swc and automation_spark.swc |
| files. If your application uses charts or the AdvancedDataGrid classes, |
| you must also add the automation_dmv.swc file. You might also be |
| required to add automation tool-specific SWC files; for example, |
| for QTP, you must also add the qtp.swc file to your application's |
| library path. For a complete list of automation SWC files, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf67b82-7ffb_verapache">About automating |
| applications with Flex</a>.</p> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b1677-2e6cad071266c6f12bf-8000_verapache"><a name="WS02f7d8d4857b1677-2e6cad071266c6f12bf-8000_verapache"><!-- --></a> |
| <h3 class="topictitle3">Including automation SWC files</h3> |
| |
| |
| <div> |
| <p>To include the SWC file in your application, you can add |
| them to the compiler's configuration file or as a command-line option. |
| For the SDK, the configuration file is located at <em>sdk_install_dir</em>/frameworks/flex-config.xml. |
| To add the automation.swc and automation_spark.swc libraries, for |
| example, add the following lines to the configuration file:</p> |
| |
| <pre class="codeblock"> <include-libraries> |
| <library>/libs/automation/automation.swc</library> |
| <library>/libs/automation/automation_spark.swc</library> |
| </include-libraries></pre> |
| |
| <p>You must uncomment the <samp class="codeph">include-libraries</samp> code |
| block. By default it is commented out in the configuration file.</p> |
| |
| <p>You can also specify the location of the SWC files when you use |
| the command-line compiler with the <samp class="codeph">include-libraries</samp> compiler |
| option. The following example adds the automation.swc and automation_spark.swc |
| files to the application: </p> |
| |
| <pre class="codeblock"> mxmlc -include-libraries+=../frameworks/libs/automation/automation.swc; |
| ../frameworks/libs/automation/automation_spark.swc MyApp.mxml</pre> |
| |
| <p>Explicitly setting the <samp class="codeph">include-libraries</samp> option |
| on the command line overwrites, rather than appends, any existing |
| libraries that you include in the configuration file. As a result, |
| if you add the automation.swc and automation_spark.swc files by |
| using the <samp class="codeph">include-libraries</samp> option on the command |
| line, ensure that you use the += operator. This does not overwrite |
| the existing libraries that might be included.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b1677-2e6cad071266c6f12bf-7fff_verapache"><a name="WS02f7d8d4857b1677-2e6cad071266c6f12bf-7fff_verapache"><!-- --></a> |
| <h3 class="topictitle3">Deploying the application</h3> |
| |
| |
| <div> |
| <p>When you create the final release version of your application, |
| you recompile the application without the references to the automation |
| SWC files.</p> |
| |
| <p>If you do not deploy your application to a server, but instead |
| request it by using the file protocol, you must put the SWF file |
| into the local-trusted sandbox. This requires configuration information |
| that is separate from the SWF file and the wrapper. For more information |
| that is specific to QTP, see <em>Testing Adobe Flex Applications with HP QuickTest Professional</em>.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a48_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a48_verapache"><!-- --></a> |
| <h2 class="topictitle2">Using run-time loading</h2> |
| |
| |
| <div> |
| <p>You can use the run-time testing files rather than compiling |
| the automation libraries into your applications. This lets you test |
| SWF files that have already been compiled without automated testing |
| support. It also helps keep the SWF file size small. To do this, |
| you use a SWF file that <em>does</em> include the automated testing libraries. |
| In that SWF file, the SWFLoader class loads your application's SWF |
| file which does not include the testing libraries. The result is |
| that you can test the target SWF file in a testing tool such as |
| QTP, even though the application SWF file was not compiled with |
| automated testing support.</p> |
| |
| <p>The Flex SDK includes the following files necessary for run-time |
| loading in the /sdks/4.6.0/templates/automation-runtimeloading-files |
| directory:</p> |
| |
| <ul> |
| <li> |
| <p>RunTimeLoading.html — The HTML wrapper that loads the |
| run-time loader SWF file. This template includes code that converts |
| the <samp class="codeph">automationswfurl</samp> query string parameter to |
| a <samp class="codeph">flashVars</samp> variable that it passes to the application. |
| You use this query string parameter to specify the name of the application |
| you want to load and test.</p> |
| |
| </li> |
| |
| <li> |
| <p>runtimeloading.mxml — The source code for the runtimeloading.swf |
| file that you compile. The SWF file acts as a wrapper for your application. |
| This SWF file includes the testing libraries so that you do not |
| have to compile them into your application SWF file.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>To use run-time loading:</p> |
| |
| <ol> |
| <li> |
| <p>Compile the runtimeloading.swf application from the runtimeloading.mxml file. |
| You can use the batch file in the /sdks/4.6.0/templates/automation-runtimeloading-files |
| directory. Execute this batch file from the sdks/4.6.0/frameworks |
| directory. This batch file ensures that your runtimeloading.swf |
| file includes the automation SWC files. You might need to add or remove |
| SWC files to this file, depending on what features your application uses.</p> |
| |
| </li> |
| |
| <li> |
| <p>Deploy the runtimeloading.swf, RunTimeLoading.html, and your |
| application's SWF file to a web server. </p> |
| |
| </li> |
| |
| <li> |
| <div class="p">Request the RunTimeLoading.html file and pass the name of |
| your SWF file as the value to the <samp class="codeph">automationswfurl</samp> query |
| string parameter. For example:<pre class="codeblock"> http://localhost/RunTimeLoading.html?automationswfurl=MyApp.swf</pre> |
| |
| </div> |
| |
| </li> |
| |
| </ol> |
| |
| <p>You can also create a custom HTML wrapper to use with the run-time |
| loading feature, but it must use proper object naming. If you are |
| using the SDK, you can use the wrapper template in the <em>flex_sdk</em>/templates/swfobject |
| directory to create a wrapper for your application. When using a |
| wrapper, the value of the <samp class="codeph">id</samp> attributes can not |
| contain any periods or hyphens.</p> |
| |
| <p>If you want to recompile the runtimeloading.swf file without |
| the batch file, be sure to include automated testing support by |
| adding the appropriate automation SWC files with the <samp class="codeph">include-libraries</samp> compiler |
| option. </p> |
| |
| <p>The batch file for compiling the runtimeloading.swf file is Windows |
| only. To compile the SWF file on Mac OS or Linux, you can use the |
| command line compiler or write your own batch file.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a4a_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a4a_verapache"><!-- --></a> |
| <h2 class="topictitle2">Creating test-friendly applications</h2> |
| |
| |
| <div> |
| <p>As a Flex developer, there are some techniques that you |
| can employ to make applications as "test friendly" as possible. |
| One of the most important tasks that you can perform is to make |
| sure that objects are identifiable in the testing tool's scripts. |
| This means that you should explicitly set the value of the <samp class="codeph">id</samp> property |
| or whatever property the testing tool uses to identify the object. |
| Also be sure to use a meaningful string for that property so that |
| the testing scripts are more readable. Finally, use unique IDs for |
| each control so that the tool does not encounter ambiguous references.</p> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fed_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fed_verapache"><!-- --></a> |
| <h3 class="topictitle3">Providing meaningful identification |
| of objects</h3> |
| |
| |
| <div> |
| <p>When working with testing tools such as QTP, a QC professional |
| only sees the visual representation of objects in your application. |
| A QC professional generally does not have access to the underlying |
| code. When a QC professional records a script, it's very helpful |
| to see IDs that help the tester identify the object clearly. You |
| should take some time to understand how testing tools interpret |
| applications and determine what names to use for the test objects |
| in the test scripts. </p> |
| |
| <p>In most cases, testing tools use a visual cue, such as the label |
| of a Button control, to identify the control in the script. Sometimes, |
| however, testing tools use the Flex <samp class="codeph">id</samp> property |
| of an MXML tag to identify an object in the test script; if there |
| is no value for the <samp class="codeph">id</samp> property, testing tools |
| use other properties, such as the <samp class="codeph">childIndex</samp> property. |
| In addition, the automation APIs provide an <samp class="codeph">automationName</samp> property |
| that you can use to explicitly set the ID of an object as it appears |
| in the tool's scripts.</p> |
| |
| <p>You should give all testable MXML components an ID to ensure |
| that the test script has a unique identifier to use when referring |
| to that Flex control. You should also try to make these identifiers |
| as human-readable as possible to make it easier for a QC professional |
| to identify that object in the testing script. For example, set |
| the <samp class="codeph">id</samp> property of a Panel container inside a TabNavigator |
| to <em>submit_panel</em> rather than <em>myPanel</em> or <em>p1</em>. </p> |
| |
| <p>In some cases, agents do not use the <samp class="codeph">id</samp> property, |
| but it is a good practice to include it to avoid naming collisions |
| or confusion. For more information about how QTP identifies Flex |
| objects, see <em>Testing Adobe Flex Applications with HP QuickTest Professional</em>.</p> |
| |
| <p>You should also set the value of the <samp class="codeph">automationName</samp> property |
| for all objects that are part of the application's test. The value |
| of this property appears in the testing scripts. Providing a meaningful |
| name makes it easier for QC professionals to identify that object. |
| For more information about using the <samp class="codeph">automationName</samp> property, |
| see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a4b_verapache">Setting |
| the automationName property</a>. </p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff7_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff7_verapache"><!-- --></a> |
| <h3 class="topictitle3">Avoiding renaming objects</h3> |
| |
| |
| <div> |
| <p>Automation agents rely on the fact that some object's properties |
| should not be changed during run time. If you change the application |
| property that is used by the agent as the object name at run time, |
| unexpected results can occur. </p> |
| |
| <p>For example, if you create a Button control without an <samp class="codeph">automationName</samp> property, |
| and you do not set the value of its <samp class="codeph">label</samp> property |
| during initialization, and then later set the value of the <samp class="codeph">label</samp> property, |
| the agent might get confused. This is because agents often use the |
| value of the <samp class="codeph">label</samp> property of a Button control |
| to identify it in its object repository if the <samp class="codeph">automationName</samp> property |
| is not set. If you later set the value of the <samp class="codeph">label</samp> property, |
| or change the value of an existing <samp class="codeph">label</samp> while |
| the QC professional is recording a test, an automation tool such |
| as QTP will create a new object in its repository instead of using |
| the exising reference.</p> |
| |
| <p>As a result, you should try to understand what properties are |
| used to identify objects in the agent, and try to avoid changing |
| those properties at run time. You should set unique, human-readable <samp class="codeph">id</samp> or <samp class="codeph">automationName</samp> properties |
| for all objects that are included in the recorded script.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache"><!-- --></a> |
| <h3 class="topictitle3">Coding containers</h3> |
| |
| |
| <div> |
| <p>Containers are different from other kinds of controls because |
| they are used both to record user interactions (such as when a user |
| moves to the next pane in an Accordion container) and to provide |
| layout logic. </p> |
| |
| <div class="section" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff6_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff6_verapache"><!-- --></a><h4 class="sectiontitle">Adding |
| and removing containers from the automation hierarchy</h4> |
| |
| <p>In |
| general, the automated testing tools reduce the amount of detail |
| about nested containers in their scripts. They remove containers |
| that have no impact on the results of the test or on the identification |
| of the controls from the script. This applies to containers that |
| are used exclusively for layout, such as the <a href="https://flex.apache.org/asdoc/spark/components/HGroup.html" target="_blank">HGroup</a>, <a href="https://flex.apache.org/asdoc/spark/components/VGroup.html" target="_blank">VGroup</a> and <a href="https://flex.apache.org/asdoc/mx/containers/Canvas.html" target="_blank">Canvas</a> containers. </p> |
| |
| <div class="p">The |
| following image shows the layout for a simple form-based application. |
| The components with gray backgrounds appear in the automation tool's |
| scripts because they can be interacted with by the user. Components |
| with white backgrounds do not appear in the tool's scripts because |
| they only provide layout logic.<div class="figborder"><span class="figdesc">Automation flowchart</span> |
| |
| <img src="images/fc_automation_flowchart.png"/> |
| </div> |
| |
| </div> |
| |
| <p>In some cases, |
| containers that are being used in multiple-view navigator containers, |
| such as the <a href="https://flex.apache.org/asdoc/mx/containers/ViewStack.html" target="_blank">ViewStack</a>, <a href="https://flex.apache.org/asdoc/mx/containers/TabNavigator.html" target="_blank">TabNavigator</a> or <a href="https://flex.apache.org/asdoc/mx/containers/Accordion.html" target="_blank">Accordion</a> containers, |
| do appear in the automation hierarchy. In these cases, they are |
| added to the automation hierarchy to provide navigation.</p> |
| |
| <p>Many |
| composite components use containers, such as VGroup or HGroup, to organize |
| their children. These containers do not have any visible impact |
| on the application. So, these containers are usually excluded from |
| the test scripts because there is no user interaction and no visual |
| need for their operations to be recordable. By excluding a container |
| from being tested, the test scripts are shorter and more readable.</p> |
| |
| <p>To |
| exclude a container from being recorded (but not exclude its children), |
| set the container's <samp class="codeph">showInAutomationHierarchy</samp> property |
| to <samp class="codeph">false</samp>. This property is defined by the <a href="https://flex.apache.org/asdoc/mx/core/UIComponent.html" target="_blank">UIComponent</a> class, |
| so all containers that subclass UIComponent have this property. |
| Children of containers that are not visible in the hierarchy appear |
| as children of the next highest visible parent. You can also use |
| this property to exclude controls that you want to omit from testing, |
| such as a Help button or decorative object.</p> |
| |
| <p>The default value |
| of the <samp class="codeph">showInAutomationHierarchy</samp> property depends on |
| the type of container. For containers that have visual elements |
| or support user interaction, such as lists, Panel, Accordion, Application, |
| DividedBox, and Form, the default value is <samp class="codeph">true</samp>. For |
| containers used exclusively for layout, such as Group, Canvas, Box, |
| and FormItem, the default value is <samp class="codeph">false</samp>.</p> |
| |
| <p>The |
| following example forces the VGroup containers to be included in |
| the test script's hierarchy:</p> |
| |
| <pre class="noswf"><?xml version="1.0"?> |
| <!-- agent/NestedButton.mxml --> |
| <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx"> |
| <s:Panel title="ComboBox Control Example"> |
| <s:layout> |
| <s:VerticalLayout/> |
| </s:layout> |
| <s:HGroup id="hg"> |
| <s:VGroup id="vg1" showInAutomationHierarchy="true"> |
| <mx:Canvas id="c1"> |
| <s:Button id="b1" |
| automationName="Nested Button 1" |
| label="Click Me"/> |
| </mx:Canvas> |
| </s:VGroup> |
| <s:VGroup id="vg2" showInAutomationHierarchy="true"> |
| <mx:Canvas id="c2"> |
| <s:Button id="b2" |
| automationName="Nested Button 2" |
| label="Click Me 2"/> |
| </mx:Canvas> |
| </s:VGroup> |
| </s:HGroup> |
| </s:Panel> |
| </s:Application> </pre> |
| |
| </div> |
| |
| <div class="section" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff9_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff1_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff9_verapache"><!-- --></a><h4 class="sectiontitle">Working |
| with multiview containers</h4> |
| |
| <p>You should avoid using the same |
| label on multiple tabs in multiview containers, such as TabNavigator |
| and Accordion containers. Although the compiler allows you to use |
| the same labels for each view, this is generally not an acceptable |
| UI design practice and can cause problems with control identification |
| in your testing environment. QTP, for example, uses the <samp class="codeph">label</samp> properties |
| of multiview containers to identify those views to testers. When |
| two labels are the same, QTP uses different strategies to uniquely |
| identify the tabs, which can result in a confusing name list.</p> |
| |
| <p>Also, |
| dynamically adding children to multiview containers can cause delays |
| that might confuse the testing tool. You should try to avoid this.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fef_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fef_verapache"><!-- --></a> |
| <h2 class="topictitle2">Testing sub-applications</h2> |
| |
| |
| <div> |
| <p>When testing applications that load sub-applications, you |
| should be aware of the different types of applications that a main |
| application can load. These include applications that:</p> |
| |
| <div class="p"> |
| <ul> |
| <li> |
| <p>Were compiled with the same version of the compiler |
| as the main application (single-versioned applications).</p> |
| |
| </li> |
| |
| <li> |
| <p>Were compiled with different versions of the compiler in |
| different application domains (multi-versioned applications).</p> |
| |
| </li> |
| |
| <li> |
| <p>Are loaded into different security domains (sandboxed applications). |
| These applications can be multi-versioned.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| <p>When testing applications that load other applications, there |
| is a single point of communication between the automation tool and |
| the applications built with Flex. This point is the main application. |
| It acts as a gateway between the sub-applications and the automation |
| tool. All events dispatched by the sub-applications are routed through |
| the main application to the tool. And conversely, all calls from |
| the tool are sent to the main application. The main application |
| is responsible for routing those messages to the sub-applications.</p> |
| |
| <p>When creating applications that will be tested, compile each |
| sub-application and the main application with its own tool library, |
| automation manager, and delegates. In other words, compile the application |
| against the automation libraries.</p> |
| |
| <div class="p">When recording an application that loads sub-applications, the |
| tool typically uses the <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationManager2.html" target="_blank">IAutomationManager2</a>'s <samp class="codeph">getUniqueApplicationId()</samp> method. This |
| method returns a unique ID for each application. The resulting scripts contain |
| longer strings to identify objects, but you can see the heirarchy |
| of the applications in them. For example, a Spark Button control |
| in a sub-application might be referenced as follows:<pre class="codeblock">FlexApplication("loader1").FlexApplication("local2.swf").SparkButton("Submit Form");</pre> |
| |
| </div> |
| |
| <p>A script that was written for the main application can be reused |
| within a multi-application environment. You might be required to |
| provide the application ID to the operations so that the target |
| application can be uniquely identified.</p> |
| |
| <div class="p">Support for sub-application testing is built into your applications |
| by default. As a developer, you do not need to add custom code to |
| ensure that multi-application tests work. However, if you write |
| a custom agent for a multi-application environment, keep the following |
| in mind:<ul> |
| <li> |
| <div class="p">Multi-versioned applications should use the sandbox |
| root application to dispatch events. This is required for events |
| that are communicated across application boundaries. You can use |
| the following code to get a reference to the sandbox root:<pre class="codeblock">private var sandboxRoot:IEventDispatcher; |
| var sm:ISystemManager = Application.application.systemManager; |
| sandboxRoot = sm.getSandboxRoot();</pre> |
| |
| </div> |
| |
| </li> |
| |
| <li> |
| <p>Untrusted (or sandboxed) applications use the SWFBridge to |
| communicate across security domain boundaries. Each application |
| has a SWFBridge. The SWFBridge has a child that corresponds to the |
| sub-application that was loaded with a SWFLoader in that application.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fe7_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fe7_verapache"><!-- --></a> |
| <h2 class="topictitle2">Writing the wrapper</h2> |
| |
| |
| <div> |
| <p>In most cases, the testing tool requests a file from a |
| web server that embeds the application. This file, known as the <em>wrapper</em>, |
| is often written in HTML, but can also be a JSP, ASP, or other file |
| that browsers interpret. You can request the SWF file directly in |
| the testing tool by using the file protocol, but then you must ensure that |
| the SWF file is trusted.</p> |
| |
| <p>When you careate a custom wrapper, your wrapper's <samp class="codeph"><object></samp> tag |
| must have an <samp class="codeph">id</samp> attribute, and the value of the <samp class="codeph">id</samp> attribute |
| can not contain any periods or hyphens. The convention is to set |
| the <samp class="codeph">id</samp> to match the name of the root MXML file |
| in the application.</p> |
| |
| <p>When you use the SWFObject 2 wrapper as a template, you must |
| set the id of the application on the <samp class="codeph">attributes.id</samp> property.</p> |
| |
| <div class="tip"><span class="tiptitle">Tip:</span> You are not required to change the value of the |
| name in the <samp class="codeph"><embed></samp> tag because <samp class="codeph"><embed></samp> is |
| used by Netscape-based browsers that do not support the testing |
| feature. The <samp class="codeph"><object></samp> |
| <em> tag is used by Microsoft Internet Explorer.</em> |
| </div> |
| |
| <p>Ensure that the object tag's <samp class="codeph">id</samp> attribute is |
| the same in the <samp class="codeph"><script></samp> and the <samp class="codeph"><noscript></samp> blocks |
| of the wrapper.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ffd_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ffd_verapache"><!-- --></a> |
| <h2 class="topictitle2">Understanding the automation framework</h2> |
| |
| |
| <div> |
| <p>The automation interfaces and the flow of the automation |
| framework change as you initialize, record, and play back an automatable |
| event.</p> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff4_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff4_verapache"><!-- --></a> |
| <h3 class="topictitle3">About the automation interfaces</h3> |
| |
| |
| <div> |
| <p>The Flex class hierarchy includes the following interfaces |
| in the mx.automation.* package that enable automation:</p> |
| |
| |
| <div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all"> |
| |
| |
| <thead align="left"> |
| <tr> |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e1033"> |
| <p>Interface</p> |
| |
| </th> |
| |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e1039"> |
| <p>Description</p> |
| |
| </th> |
| |
| </tr> |
| |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationClass.html" target="_blank">IAutomationClass</a> and <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationClass2.html" target="_blank">IAutomationClass2</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface for a component class |
| descriptor.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationEnvironment.html" target="_blank">IAutomationEnvironment</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Provides information about the objects and |
| properties of automatable components needed for communicating with |
| agents.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationEventDescriptor.html" target="_blank">IAutomationEventDescriptor</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface for an event descriptor.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationManager.html" target="_blank">IAutomationManager</a> and <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationManager2.html" target="_blank">IAutomationManager2</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface expected from an AutomationManager |
| by the automation module.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationMethodDescriptor.html" target="_blank">IAutomationMethodDescriptor</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface for a method descriptor.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationMouseSimulator.html" target="_blank">IAutomationMouseSimulator</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Describes an object that simulates mouse |
| movement so that components capturing the mouse use the simulated |
| versions of the mouse cursor instead of the live Flash Player version.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationObject.html" target="_blank">IAutomationObject</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface for a delegate object |
| implementing automation for a component.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationObjectHelper.html" target="_blank">IAutomationObjectHelper</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Provides helper methods for the IAutomationObject |
| interface.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationPropertyDescriptor.html" target="_blank">IAutomationPropertyDescriptor</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Describes a property of a test object as |
| well as properties of an event object.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1033 "> |
| <p> |
| <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationTabularData.html" target="_blank">IAutomationTabularData</a> |
| </p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e1039 "> |
| <p>Defines the interface for components that |
| provide their content information in a tabular form.</p> |
| |
| </td> |
| |
| </tr> |
| |
| </tbody> |
| |
| </table> |
| </div> |
| |
| <p>For more information about each of these interfaces, see the |
| class's description in the <a href="https://flex.apache.org/asdoc/" target="_blank">ActionScript 3.0 Reference for Apache Flex</a>.</p> |
| |
| </div> |
| |
| <div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fe0_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fe0_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the IAutomationObjectHelper |
| interface</h4> |
| |
| |
| <div> |
| <p>The IAutomationObjectHelper interface helps the components |
| accomplish the following tasks:</p> |
| |
| <ul> |
| <li> |
| <p>Replay mouse and keyboard events; the helper generates |
| proper sequence of player level mouse and key events. </p> |
| |
| </li> |
| |
| <li> |
| <p>Generate AutomationIDPart for a child: AutomationIDPart would |
| be requested by the Automation for representing a component instance |
| to agents.</p> |
| |
| </li> |
| |
| <li> |
| <p>Find a child matching a AutomationIDPart: Automation would |
| request the component to locate a child matching the AutomationIDPart |
| supplied by an agent to it. </p> |
| |
| </li> |
| |
| <li> |
| <p>Avoid synchronization issues: Agents invoke methods on Automation requesting |
| operations on components in a sequence. Components may not be ready |
| all the time to perform operations.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>For example, an agent can invoke <samp class="codeph">comboBox.Open</samp>, <samp class="codeph">comboBox.select "Item1"</samp> operations |
| in a sequence. Because it takes time for the drop-down list to open |
| and initialize, it is not possible to run the select operation immediately. You |
| can place a wait request during the open operation execution. The |
| wait request should provide a function for automation, which can |
| be invoked to check the ComboBox control's readiness before invoking |
| the next operation.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdf_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdf_verapache"><!-- --></a> |
| <h3 class="topictitle3">Automated testing workflow with |
| the QTP automation tool</h3> |
| |
| |
| <div> |
| <p>Before you automate custom components, you might find it |
| helpful to see the order of events during which Flex's automation |
| framework initializes, records, and plays back events with a tool |
| such as QTP. You should keep in mind that the QTP adapter class' |
| implementation is only one way to use the automation API for automated |
| testing.</p> |
| |
| </div> |
| |
| <div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fde_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fde_verapache"><!-- --></a> |
| <h4 class="topictitle4">Automated testing initialization</h4> |
| |
| |
| <div> |
| <ol> |
| <li> |
| <p>The user launches the application. Automation initialization |
| code associates component delegate classes with component classes. |
| Component delegate classes implement the IAutomationObject interface.</p> |
| |
| </li> |
| |
| <li> |
| <p>AutomationManager is a mixin. Its instance is created in |
| the mixin <samp class="codeph">init()</samp> method. </p> |
| |
| </li> |
| |
| <li> |
| <p>The SystemManager initializes the application. Component |
| instances and their corresponding delegate instances are created. |
| Delegate instances add event listeners for events of interest. </p> |
| |
| </li> |
| |
| <li> |
| <p>QTPAgent class is a mixin. In its <samp class="codeph">init()</samp> method, |
| it registers itself for the <samp class="codeph">FlexEvent.APPLICATION_COMPLETE</samp> event |
| which is dispatched from the SystemManager. On receiving the event, |
| it creates a QTPAdapter object.</p> |
| |
| </li> |
| |
| <li> |
| <p>QTPAdapter sets up the ExternalInterface function map. QTPAdapter |
| loads the QTP Plugin DLLs by creating the ActiveX object to communicate |
| with QTP.</p> |
| |
| </li> |
| |
| <li> |
| <p>The QTPAdapter requests the XML environment information from |
| the plugin and passes it to the AutomationManager.</p> |
| |
| </li> |
| |
| <li> |
| <p>The XML information is stored in a chain of AutomationClass, |
| AutomationMethodDescriptor, and AutomationPropertyDescriptor objects. </p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdd_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdd_verapache"><!-- --></a> |
| <h4 class="topictitle4">Automated testing recording</h4> |
| |
| |
| <div> |
| <ol> |
| <li> |
| <p>The user clicks the Record button in QTP. </p> |
| |
| </li> |
| |
| <li> |
| <p>QTP calls the <samp class="codeph">QTPAdapter.beginRecording()</samp> method. |
| QTPAdapter adds a listener for <samp class="codeph">AutomationRecordEvent.RECORD</samp> from |
| the AutomationManager. </p> |
| |
| </li> |
| |
| <li> |
| <p>The QTPAdapter notifies AutomationManager about this by calling |
| the <samp class="codeph">beginRecording()</samp> method. The AutomationManager |
| adds a listener for the <samp class="codeph">AutomationRecordEvent.RECORD</samp> event |
| from the SystemManager. </p> |
| |
| </li> |
| |
| <li> |
| <p>The user interacts with the application. In this example, |
| suppose the user clicks a Button control.</p> |
| |
| </li> |
| |
| <li> |
| <p>The <samp class="codeph">ButtonDelegate.clickEventHandler()</samp> method |
| dispatches an AutomationRecordEvent event with the <samp class="codeph">click</samp> event |
| and Button instance as properties. </p> |
| |
| </li> |
| |
| <li> |
| <p>The AutomationManager <samp class="codeph">record</samp> event handler |
| determines which properties of the <samp class="codeph">click</samp> event |
| to store, based on the XML environment information. It converts |
| the values into proper type or format. It dispatches the <samp class="codeph">record</samp> event. </p> |
| |
| </li> |
| |
| <li> |
| <p>The QTPAdapter event handler receives the event. It calls |
| the <samp class="codeph">AutomationManager.createID()</samp> method to create |
| the AutomationID object of the button. This object provides a structure |
| for object identification.</p> |
| |
| <p>The AutomationID structure is an |
| array of AutomationIDParts. An AutomationIDPart is created by using |
| IAutomationObject. (The <samp class="codeph">UIComponent.id</samp>, <samp class="codeph">automationName</samp>, <samp class="codeph">automationValue</samp>, <samp class="codeph">childIndex</samp>, |
| and <samp class="codeph">label</samp> properties of the Button control are |
| read and stored in the object. The <samp class="codeph">label</samp> property |
| is used because the XML information specifies that this property |
| can be used for identification for the Button.) </p> |
| |
| </li> |
| |
| <li> |
| <p>The QTPAdapter uses the <samp class="codeph">AutomationManager.getParent()</samp> method to |
| get the logical parent of the Button control. The AutomationIDPart |
| objects of parent controls are collected at each level up to the |
| application level. </p> |
| |
| </li> |
| |
| <li> |
| <p>All these AutomationIDParts are made part of an AutomationID |
| object. </p> |
| |
| </li> |
| |
| <li> |
| <p>The QTPAdapter sends the information in a call to QTP. </p> |
| |
| </li> |
| |
| <li> |
| <p>At this point, QTP might call the <samp class="codeph">AutomationManager.getProperties()</samp> method |
| to get the property values of the Button control. The property type |
| information and codec that should be used to modify the value format |
| are gotten from the AutomationPropertyDescriptor. </p> |
| |
| </li> |
| |
| <li> |
| <p>User stops recording. This is propagated by a call to the <samp class="codeph">QTPAdapter.endRecording()</samp> method. </p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdc_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7fdc_verapache"><!-- --></a> |
| <h4 class="topictitle4">Automated testing playback</h4> |
| |
| |
| <div> |
| <ol> |
| <li> |
| <p>The user clicks the Playback button in QTP.</p> |
| |
| </li> |
| |
| <li> |
| <p>The <samp class="codeph">QTPAdapter.findObject()</samp> method is called |
| to determine whether the object on which the event has to be played |
| back can be found. The AutomationID object is built from the XML |
| data received. The <samp class="codeph">AutomationManager.resolveIDToSingleObject()</samp> method |
| is invoked to see if QTP can find one unique object matching the |
| AutomationID. The <samp class="codeph">AutomationManager.getChildren()</samp> method |
| is invoked from application level to find the child object. The <samp class="codeph">IAutomationObject.numAutomationChildren</samp> property |
| and the <samp class="codeph">IAutomationObject.getAutomationChildAt()</samp> method |
| are used to navigate the application. </p> |
| |
| </li> |
| |
| <li> |
| <p>The <samp class="codeph">AutomationManager.isSynchronized()</samp> and <samp class="codeph">AutomationManager.isVisible()</samp> methods |
| ensure that the object is fully initialized and is visible so that |
| it can receive the event. </p> |
| |
| </li> |
| |
| <li> |
| <p>QTP invokes the <samp class="codeph">QTPAdpater.run()</samp> method |
| to play back the event. The <samp class="codeph">AutomationManager.replayAutomatableEvent()</samp> method |
| is called to replay the event.</p> |
| |
| </li> |
| |
| <li> |
| <p>The AutomationMethodDescriptor for the <samp class="codeph">click</samp> event |
| on the Button is used to copy the property values (if any). </p> |
| |
| </li> |
| |
| <li> |
| <p>The <samp class="codeph">AutomationManager.replayAutomatableEvent()</samp> method invokes |
| the <samp class="codeph">IAutomationObject.replayAutomatableEvent()</samp> method |
| on the delegate class. The delegate uses the <samp class="codeph">IAutomationObjectHelper.replayMouseEvent()</samp> method |
| (or one of the other replay methods, such as <samp class="codeph">replayKeyboardEvent()</samp>) |
| to play back the event. </p> |
| |
| </li> |
| |
| <li> |
| <p>If there are check points recorded in QTP, the <samp class="codeph">AutomationManager.getProperties()</samp> method |
| is invoked to verify the values. </p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a47_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a47_verapache"><!-- --></a> |
| <h2 class="topictitle2">Instrumenting events</h2> |
| |
| |
| <div> |
| <p>When you extend components that are already instrumented, |
| you do not have to change anything to ensure that those components' |
| events can be recorded by a testing tool. For example, if you extend |
| a Button class, the class still dispatches the automation events |
| when the Button is clicked, unless you override the Button control's |
| default event dispatching behavior.</p> |
| |
| <p>Automation events (sometimes known in automation tools such as |
| QTP as <em>operations</em>) are not the same as Flex events. Flex |
| must dispatch an automation event as a separate action. Flex dispatches |
| them at the same time as Flex events, and uses the same event classes, |
| but you must decide whether to make a Flex event visible to the |
| automation tool.</p> |
| |
| <p>Not all events on a control are instrumented. You can instrument |
| additional events by using the instructions in <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a4e_verapache">Instrumenting |
| existing events</a>.</p> |
| |
| <p>If you change the instrumentation of a component, you might also |
| be required to edit that component's entry in the class definitions |
| file. This is described in <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache">Using |
| the class definitions file</a>.</p> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a4e_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a4e_verapache"><!-- --></a> |
| <h3 class="topictitle3">Instrumenting existing events</h3> |
| |
| |
| <div> |
| <p>Events have different levels of relevance for the QC professional. |
| For example, a QC professional is generally interested in recording |
| and playing back a <samp class="codeph">click</samp> event on a Button control. |
| The QC professional is not generally interested in recording all |
| the events that occur when a user clicks the Button, such as the <samp class="codeph">mouseOver</samp>, <samp class="codeph">mouseDown</samp>, <samp class="codeph">mouseUp</samp>, |
| and <samp class="codeph">mouseOut</samp> events. For this reason, when a tester |
| clicks on a Button control with the mouse, testing tools only record and |
| play back the <samp class="codeph">click</samp> event for the Button control |
| and not the other, lower-level events.</p> |
| |
| <p>There are some circumstances where you would want to record events |
| that are normally ignored by the testing tool. But the testing tool's |
| object model only records events that represent the end-user's gesture |
| (such as a click or a drag and drop). This makes a script more readable |
| and it also makes the script robust enough so that it does not fail |
| if you change the application slightly. So, you should carefully |
| consider whether to add a new event to be tested or rely on events |
| in the existing object model.</p> |
| |
| <p>You can see a list of events that the QTP automation tool can |
| record for each component in the <em>QTP Object Type Information</em> (or <em>class definition</em>) |
| documents. The MX Button control, for example, supports the following |
| operations, based on its entry in the TEAFlex.xml file:</p> |
| |
| <ul> |
| <li> |
| <p> |
| <samp class="codeph">ChangeFocus</samp> |
| </p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">Click</samp> |
| </p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">MouseMove</samp> |
| </p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">SetFocus</samp> |
| </p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">Type</samp> |
| </p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>All of these operations except for <samp class="codeph">MouseMove</samp> are |
| automatically recorded by QTP by default. The QC professional must |
| explicitly add the <samp class="codeph">MouseMove</samp> operation to their |
| QTP script for QTP to record play back the related event.</p> |
| |
| <p>However, you can alter the behavior of your application so that |
| this event is recorded by the testing tool. To add a new event to |
| be tested, you override the <samp class="codeph">replayAutomatableEvent()</samp> method |
| of the <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationObject.html" target="_blank">IAutomationObject</a> interface. Because |
| the <a href="https://flex.apache.org/asdoc/mx/core/UIComponent.html" target="_blank">UIComponent</a> class |
| implements this interface, all subclasses of UIComponent (which |
| include all visible Flex controls) can override this method. To |
| override the <samp class="codeph">replayAutomatableEvent()</samp> method, you |
| create a custom class, and override the method in that class.</p> |
| |
| <p>The <samp class="codeph">replayAutomatableEvent()</samp> method has the |
| following signature:</p> |
| |
| <pre class="codeblock"> public function replayAutomatableEvent(<em>event</em>:Event):Boolean</pre> |
| |
| <p>The <em>event</em> argument is the Event object that is being dispatched. |
| In general, you pass the Event object that triggered the event. |
| Where possible, you pass the specific event, such as a MouseEvent, |
| rather than the generic Event object.</p> |
| |
| <p>The following example shows a custom Spark Button control that |
| overrides the <samp class="codeph">replayAutomatableEvent()</samp> method. |
| This method checks for the <samp class="codeph">mouseMove</samp> event and |
| calls the <samp class="codeph">replayMouseEvent()</samp> method if it finds |
| that event. Otherwise, it calls its superclass' <samp class="codeph">replayAutomatableEvent()</samp> method.</p> |
| |
| <pre class="noswf"><?xml version="1.0" encoding="utf-8"?> |
| <!-- agent/CustomButton.mxml --> |
| <s:Button xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx"> |
| <fx:Script> |
| <![CDATA[ |
| import flash.events.Event; |
| import flash.events.MouseEvent; |
| import mx.automation.Automation; |
| import mx.automation.IAutomationObjectHelper; |
| |
| override public function |
| replayAutomatableEvent(event:Event):Boolean { |
| |
| trace('in replayAutomatableEvent()'); |
| |
| var help:IAutomationObjectHelper = Automation.automationObjectHelper; |
| |
| if (event is MouseEvent && event.type == MouseEvent.MOUSE_MOVE) { |
| return help.replayMouseEvent(this, MouseEvent(event)); |
| } else { |
| return super.replayAutomatableEvent(event); |
| } |
| } |
| ]]> |
| </fx:Script> |
| </s:Button></pre> |
| |
| <p>In the application, you call the <a href="https://flex.apache.org/asdoc/mx/automation/AutomationManager.html" target="_blank">AutomationManager</a>'s <samp class="codeph">recordAutomatableEvent()</samp> method |
| when the user moves the mouse over the button. The following application |
| uses this custom class:</p> |
| |
| <pre class="noswf"><?xml version="1.0" encoding="utf-8"?> |
| <!-- agent/CustomButtonApp.mxml --> |
| <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx" |
| xmlns:ns1="*" initialize="doInit()"> |
| <fx:Script> |
| <![CDATA[ |
| import mx.automation.*; |
| |
| public function doInit():void { |
| b1.addEventListener(MouseEvent.MOUSE_MOVE, dispatchLowLevelEvent); |
| } |
| |
| public function dispatchLowLevelEvent(e:MouseEvent):void { |
| var help:IAutomationManager = Automation.automationManager; |
| help.recordAutomatableEvent(b1,e,false); |
| } |
| ]]> |
| </fx:Script> |
| |
| <ns1:CustomButton id="b1" |
| toolTip="Mouse moved over" |
| label="CustomButton"/> |
| |
| </s:Application></pre> |
| |
| <p>If the event is not one that is currently recordable, you also |
| must define the new event for the agent. Typically, you do this |
| by adding a new entry to a class definitions file. For a tool such |
| as QTP, the class definitions are in the TEAFlex.xml file. Automation |
| tools can use files like this to define the events, properties, |
| and arguments for each class of test object. For more information, |
| see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a47_verapache">Instrumenting events</a>. |
| If you wanted to add support for the <samp class="codeph">mouseOver</samp> event |
| in QTP, for example, you add the following to the SparkButton object's |
| entry in the TEAFlex.xml file:</p> |
| |
| <pre class="codeblock"> <Operation Name="MouseOver" PropertyType="Method" ExposureLevel="CommonUsed"> |
| <Implementation Class="flash.events::MouseEvent" Type="mouseOver"/> |
| <Argument Name="keyModifier" IsMandatory="false" DefaultValue="0"> |
| <Type VariantType="Enumeration" |
| ListOfValuesName="FlexKeyModifierValues" Codec="keyModifier"/> |
| <Description>Occurs when the user moves mouse over the component</Description> |
| </Argument> |
| </Operation></pre> |
| |
| <p>In the preceding example, however, the <samp class="codeph">mouseMove</samp> event |
| is already in the SparkButton object's entry in that file, so no |
| editing is necessary. The difference now is that the QC professional |
| does not have to explicitly add the event to their script. After |
| you compile this application and deploy the new TEAFlex.xml file |
| to the QTP testing environment, QTP records the <samp class="codeph">mouseMove</samp> event |
| for all of the CustomButton objects.</p> |
| |
| <p>For more information about the class definitions file, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache">Using |
| the class definitions file</a>.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a45_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a45_verapache"><!-- --></a> |
| <h3 class="topictitle3">Instrumenting custom events</h3> |
| |
| |
| <div> |
| <p>When you extend components, you often add events that are |
| triggered by new functionality of that component. You can instrument |
| custom events by adding a call to the Automation.automationManager2 |
| class's <samp class="codeph">recordCustomAutomationEvent()</samp> method. You |
| usually do this in the same place that you call the <samp class="codeph">dispatchEvent()</samp> method. |
| You do not replace the call to the <samp class="codeph">dispatchEvent()</samp> method.</p> |
| |
| <div class="p">The following example from a custom event class builds a new <a href="https://flex.apache.org/asdoc/mx/automation/events/AutomationRecordEvent.html" target="_blank">AutomationRecordEvent</a> and |
| calls the <samp class="codeph">recordCustomAutomationEvent()</samp> method |
| to ensure that it is recorded:<pre class="codeblock">this.addEventListener(MyComponentEvent.myEvent, myHandler); |
| private function myHandler(event:MyComponentEvent) { |
| var eventToRecord:AutomationRecordEvent = |
| new AutomationRecordEvent(AutomationRecordEvent.CUSTOM_RECORD); |
| eventToRecord.automationObject = this; |
| // Provide the name of the event: |
| eventToRecord.name = "MyCustomEventName"; |
| // Provide the details to be recorded. This should be of basic data types. |
| eventToRecord.args = [MySelectionDetails]; |
| Automation.automationManager2.recordCustomAutomationEvent(eventToRecord); |
| }</pre> |
| |
| </div> |
| |
| <p>For a tool such as QTP to recognize the event as a recordable |
| operation, you must also add the event to the control's entry in |
| the class definitions file (TEAFlex.xml).</p> |
| |
| <div class="p">To replay the custom event, you listen for the AutomationCustomReplayEvent, get |
| the details about it, and replay the event, as the following example |
| shows:<pre class="codeblock">Automation.automationManager2.addEventListener(AutomationCustomReplayEvent.Replay, |
| handleReplay,false, EventPriority.DEFAULT+1); |
| private function handleReplay(event:AutomationCustomReplayEvent):void { |
| if (event.automationObject == this) { |
| // take the name and args: |
| var name:String = event.name; |
| var args:Array = event.args; |
| // Use the above do the required replay: |
| event.preventDefault(); // prevent the default replay |
| } |
| }</pre> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b167742d5ca126714ffc4c-8000_verapache"><a name="WS02f7d8d4857b167742d5ca126714ffc4c-8000_verapache"><!-- --></a> |
| <h3 class="topictitle3">Blocking and overriding events</h3> |
| |
| |
| <div> |
| <p>In some cases, you might want to block or override the |
| default events that are recorded for a component. You might even |
| want to replace them with a different event. This is often the case |
| with events dispatched from custom components.</p> |
| |
| <p>For example, suppose you have an application that uses a custom |
| component that consists of a List and a Button control. When the |
| user selects an item from the list, the application records a <samp class="codeph">change</samp> event. |
| However, if you change the List control to a RadioButtonGroup in |
| your custom component, you no longer want to record the <samp class="codeph">change</samp> event, |
| but rather, you want to record the <samp class="codeph">itemClick</samp> event. </p> |
| |
| <p>The result is that automation scripts can break due to changes |
| in the custom component. To get around this, you can block the events |
| and dispatch a higher-level event that corresponds to the user's |
| gesture rather than the specific event.</p> |
| |
| <div class="p">To block the recording of the default events, create an event |
| listener that listens for all <samp class="codeph">AutomationRecordEvent.RECORD</samp> events. |
| Set its priority to be higher than other listeners. In the handler, |
| call the event's <samp class="codeph">preventDefault()</samp> method, as the |
| following example shows:<pre class="codeblock">Automation.automationManager2.addEventListener(AutomationRecordEvent.RECORD, |
| blockEvents,false, EventPriority.DEFAULT+1); |
| private function blockEvent(event:AutomationRecordEvent):void { |
| // Block all events on list1 and button1: |
| if ((event.automationObject == list1) || (if (event.automationObject == button1)) { |
| event.preventDefault(); |
| } |
| }</pre> |
| |
| </div> |
| |
| <p>You can then dispatch the more generic event that resembles the |
| user's gesture as shown in <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a45_verapache">Instrumenting |
| custom events</a>. </p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a51_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a51_verapache"><!-- --></a> |
| <h2 class="topictitle2">Instrumenting custom components</h2> |
| |
| |
| <div> |
| <p>The process of creating a custom component that supports |
| automated testing is called instrumentation. Flex framework components |
| are instrumented by attaching a delegate class to each component |
| at run time. The <em>delegate class</em> defines the methods and properties |
| required to perform instrumentation. </p> |
| |
| <p>If you extend an existing component that is instrumented, such |
| as a Button control, you inherit its parent's instrumentation, and |
| are not required to do anything else to make that component testable. |
| If you create a component that inherits from UIComponent, you must |
| instrument that class in one of the following ways:</p> |
| |
| <ul> |
| <li> |
| <p>Create a delegate class that implements the required |
| interfaces. </p> |
| |
| </li> |
| |
| <li> |
| <p>Add testing-related code to the component. </p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>You usually instrument components by creating delegate classes. |
| You can also instrument components by adding automation code inside |
| the components, but this is not a recommended practice. It creates |
| tighter coupling between automated testing code and component code, |
| and it forces the automated testing code to be included in a production |
| SWF file.</p> |
| |
| <p>In both methods of instrumenting a component, you must specify |
| any new events to the agent. With QTP, for example, you must add |
| your new component's information to the class definitions file so |
| that QTP recognizes that component. For more information about this |
| file, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache">Using |
| the class definitions file</a>.</p> |
| |
| <p>Consider the following additional factors when you instrument |
| custom components:</p> |
| |
| <ul> |
| <li> |
| <p>Composition. When instrumenting components, you must |
| consider whether the component is a simple component or a composite |
| component. Composite components are components made up of several |
| other components. For example, a TitleWindow that contains form |
| elements is a composite component. </p> |
| |
| </li> |
| |
| <li> |
| <p>Container hierarchy. You should understand how containers |
| are viewed in the automation hierarchy so that the QC professional |
| can easily test the components. Also, you should be aware that you |
| can manipulate the hierarchy to better suit your application by |
| setting some automation-related properties. </p> |
| |
| </li> |
| |
| <li> |
| <p>Automation names. Custom components sometimes have ambiguous |
| or unclear default automation names. The ambiguous names make it |
| more difficult in automation tools to determine what component a |
| script is referring to. Component authors can manually set the value |
| of the <samp class="codeph">automationName</samp> property for all components |
| except item renderers. For item renderers, use the <samp class="codeph">automationValue</samp>.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff3_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff3_verapache"><!-- --></a> |
| <h3 class="topictitle3">Creating a delegate class</h3> |
| |
| |
| <div> |
| <p>To instrument custom components with a delegate, you must |
| do the following:</p> |
| |
| <ul> |
| <li> |
| <p>Create a delegate class that implements the required |
| interfaces. In most cases, you extend the <a href="https://flex.apache.org/asdoc/mx/automation/delegates/core/UIComponentAutomationImpl.html" target="_blank">UIComponentAutomationImpl</a> class. |
| You can instrument any component that implements IUIComponent.</p> |
| |
| </li> |
| |
| <li> |
| <p>Register the delegate class with the <a href="https://flex.apache.org/asdoc/mx/automation/AutomationManager.html" target="_blank">AutomationManager</a>.</p> |
| |
| </li> |
| |
| <li> |
| <p>Define the component in a class definitions XML file.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The delegate class is a separate class that is not embedded in |
| the component code. This helps to reduce the component class size |
| and also keeps automated testing code out of the final production |
| SWF file. </p> |
| |
| <p>All visual Flex controls have their own delegate classes. These |
| classes are in the spark.automation.delegates.components.* package |
| for Spark controls, and the mx.automation.delegates.* package for |
| MX components. The class names follow a pattern of <em>Class_name</em>AutomationImpl. |
| For example, the delegate class for the Spark Button control is |
| spark.automation.delegates.components.SparkButtonAutomationImpl. |
| The delegate class for the MX Button control is mx.automation.delegates.controls.ButtonAutomationImpl.</p> |
| |
| <div class="p">The delegate class defines the following:<ul> |
| <li> |
| <p>The <samp class="codeph">enableAutomation()</samp> method</p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">The replayAutomatableEvent()</samp> method</p> |
| |
| </li> |
| |
| <li> |
| <p>Event listeners</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| <p>All subclasses of <a href="https://flex.apache.org/asdoc/mx/core/UIComponent.html" target="_blank">UIComponent</a> store |
| a reference to their delegate in the <samp class="codeph">automationDelegate</samp> property. |
| This behavior is defined in the UIComponent initializer, which calls |
| the delegate's <samp class="codeph">enableAutomation()</samp> method. If you |
| create a custom component that does not subclass UIComponent, then you |
| must manually call the delegate's <samp class="codeph">enableAutomation()</samp> method |
| in your custom component's initilization code.</p> |
| |
| <p>You map the delegate's unique name and value properties to the <samp class="codeph">automationName</samp> and <samp class="codeph">automationValue</samp> properties. </p> |
| |
| <div class="section" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff3_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff2_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff3_verapache__WS2db454920e96a9e51e63e3d11c0bf67b82-7ff2_verapache"><!-- --></a><h4 class="sectiontitle">Instrument |
| with a delegate class</h4> |
| |
| <ol> |
| <li> |
| <p>Create a delegate class.</p> |
| |
| </li> |
| |
| <li> |
| <p>Mark the delegate class as a mixin by using the <samp class="codeph">[Mixin]</samp> metadata |
| keyword.</p> |
| |
| </li> |
| |
| <li> |
| <p>Register the delegate with the AutomationManager by calling |
| the <samp class="codeph">Automation.registerDelegateClass()</samp> method in |
| the <samp class="codeph">init()</samp> method. The following code is a simple |
| example:</p> |
| |
| <pre class="codeblock"> [Mixin] |
| public class MyCompDelegate { |
| public static init(root:DisplayObject):void { |
| // Pass the component and delegate class information. |
| Automation.registerDelegateClass(MyComp, MyCompDelegate); |
| } |
| }</pre> |
| |
| <p>You pass the custom class and the delegate class |
| to the <samp class="codeph">registerDelegateClass()</samp> method.</p> |
| |
| </li> |
| |
| <li> |
| <p>Add the following code to your delegate class:</p> |
| |
| <ol type="a"> |
| <li> |
| <p>Override the getter for the <samp class="codeph">automationName</samp> property |
| and define its value. This is the name of the object as it usually |
| appears in automation tools such as QTP. If you are defining an |
| item renderer, use the <samp class="codeph">automationValue</samp> property |
| instead.</p> |
| |
| </li> |
| |
| <li> |
| <p>In the constructor, add event listeners for events that the |
| automation tool records.</p> |
| |
| </li> |
| |
| <li> |
| <p>Override the <samp class="codeph">replayAutomatableEvent()</samp> method. |
| The AutomationManager calls this method for replaying events. In |
| this method, return whether the replay was successful. You can use |
| methods of the helper classes to replay common events.</p> |
| |
| <p>For |
| examples of delegates, see the source code for the Flex controls |
| in the spark.automation.delegates.components.* package.</p> |
| |
| </li> |
| |
| </ol> |
| |
| </li> |
| |
| <li> |
| <p>Link the delegate class with the application SWF file in |
| one of these ways:</p> |
| |
| <ul> |
| <li> |
| <p>Add the following <samp class="codeph">includes</samp> compiler |
| option to link in the delegate class:</p> |
| |
| <pre class="codeblock"> mxmlc -includes MyCompDelegate -- FlexApp.mxml</pre> |
| |
| </li> |
| |
| <li> |
| <p>Build a SWC file for the delegate class by using the compc |
| component compiler:</p> |
| |
| <pre class="codeblock"> compc -source-path+=. -include-classes MyCompDelegate -output MyComp.swc</pre> |
| |
| <p>Then |
| include this SWC file with your application by using the following <samp class="codeph">include-libraries</samp> compiler |
| option:</p> |
| |
| <pre class="codeblock"> mxmlc -include-libraries MyComp.SWC -- FlexApp.mxml</pre> |
| |
| <p>This |
| approach is useful if you have many components and delegate classes and |
| want to include them as a single library so that you can share them |
| with other developers.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </li> |
| |
| <li> |
| <p>After you compile your application with the new delegate |
| class, you must define the new interaction for the agent and the |
| automation tool. For QTP, you must add the new component to QTP's |
| custom class definition XML file. For more information, see <a href="flx_functest_components2_fc.html#WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache">Using |
| the class definitions file</a>.</p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a53_verapache"><!-- --></a> |
| <h3 class="topictitle3">Using the class definitions file</h3> |
| |
| |
| <div> |
| <p>The class definitions file contains information about all |
| instrumented components. This file provides information about the |
| components to the automation agent, including what events can be |
| recorded and played back, the name of the component, and the properties |
| that can be tested.</p> |
| |
| <p>An example of a class definitions file is the TEAFlex.xml file, |
| which is specific to the QTP automation tool. This file is included |
| in the Flex Automation Package.</p> |
| |
| <p>The TEAFlex.xml file is located in the "<em>QTP_plugin_install</em>/Adobe |
| Flex 4 Plug-in for HP QuickTest Pro" directory. QTP recognizes any |
| file in that directory that matches the pattern TEAFlex*.xml, where |
| * can be any string. This directory also contains a TEAFlexCustom.xml |
| file that you can use as a starting point for adding custom component |
| definitions.</p> |
| |
| <p>The TEAFlex.xml and FlexEnv.xml class definitions files describe |
| instrumented components with the following basic structure:</p> |
| |
| <pre class="codeblock"> <TypeInformation> |
| <ClassInfo> |
| <Description/> |
| <Implementation/> |
| <TypeInfo> |
| <Operation/> |
| ... |
| </TypeInfo> |
| <Properties> |
| <Property/> |
| ... |
| </Properties> |
| </ClassInfo> |
| </TypeInformation></pre> |
| |
| <p>The top level tag is <samp class="codeph"><TypeInformation></samp>. |
| You define a new class that uses the <samp class="codeph"><ClassInfo></samp> tag, |
| which is a child tag of the <samp class="codeph"><TypeInformation></samp> tag. |
| The <samp class="codeph"><ClassInfo></samp> tag has child tags that further |
| define the instrumented classes. The following table describes these |
| tags:</p> |
| |
| |
| <div class="tablenoborder"><table cellpadding="4" cellspacing="0" summary="" frame="border" border="1" rules="all"> |
| |
| |
| <thead align="left"> |
| <tr> |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e2382"> |
| <p>Tag</p> |
| |
| </th> |
| |
| <th class="cellrowborder" valign="top" width="NaN%" id="d225074e2388"> |
| <p>Description</p> |
| |
| </th> |
| |
| </tr> |
| |
| </thead> |
| |
| <tbody> |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2382 "> |
| <p>ClassInfo</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2388 "> |
| <p>Defines the class that is instrumented, |
| for example, SparkButton. This is the name that the automation tools use |
| for the Spark Button control. (For the MX Button control, the name |
| is FlexButton.)</p> |
| |
| <p>Attributes of this tag include <samp class="codeph">Name</samp>, <samp class="codeph">GenericTypeID</samp>, <samp class="codeph">Extends</samp>, |
| and <samp class="codeph">SupportsTabularData</samp>.</p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2382 "> |
| <p>Description</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2388 "> |
| <p>Defines the text that appears in the automation |
| tool to define the component. This is not implemented in the AutoQuick |
| example, but is implemented for QTP. </p> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2382 "> |
| <p>Implementation</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2388 "> |
| <p>Defines the class name, as it is known by |
| the Flex compiler, for example, Button or MyComponent.</p> |
| |
| <div class="p">There |
| is an optional property of the <samp class="codeph"><Implementation></samp> element, <samp class="codeph">version</samp>. |
| You use the <samp class="codeph">version</samp> property to differentiate controls |
| that are in same package and have the same name, but have differences |
| in their API across the versions. For example:<pre class="codeblock"> <Implementation Class="my.custom.controls::BigButton" version="1.5"/></pre> |
| |
| </div> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2382 "> |
| <p>TypeInfo</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2388 "> |
| <p>Defines events for this class. Each event |
| is defined in an <samp class="codeph"><Operation></samp> child tag, which |
| has two child tags:</p> |
| |
| <div class="p"> |
| <ul> |
| <li> |
| <p>The <samp class="codeph"><Implementation></samp> child |
| tag associates the operation with the actual event.</p> |
| |
| </li> |
| |
| <li> |
| <p>Each operation can also define properties of the event object |
| by using an <samp class="codeph"><Argument></samp> child tag.</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| </td> |
| |
| </tr> |
| |
| <tr> |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2382 "> |
| <p>Properties</p> |
| |
| </td> |
| |
| <td class="cellrowborder" valign="top" width="NaN%" headers="d225074e2388 "> |
| <p>Defines properties of the class. Each property |
| is defined in a <samp class="codeph"><Property></samp> child tag. Inside |
| this tag, you define the property's type, name, and description.</p> |
| |
| <p>For |
| each <samp class="codeph">Property</samp>, if the <samp class="codeph">ForDescription</samp> attribute |
| is <samp class="codeph">true</samp>, the property is used to uniquely identify |
| a component instance in the automation tool; for example, the <samp class="codeph">label</samp> property |
| of a Button control. QTP lists this property as part of the object |
| in QTP object repository.</p> |
| |
| <p>If the <samp class="codeph">ForVerfication</samp> attribute |
| is <samp class="codeph">true</samp>, the property is visible in the properties |
| dialog box in QTP.</p> |
| |
| <p>If the <samp class="codeph">ForDefaultVerification</samp> tag |
| is <samp class="codeph">true</samp>, the property appears selected by default |
| in the dialog box in QTP. This results in verification of the property |
| value in the checkpoint.</p> |
| |
| </td> |
| |
| </tr> |
| |
| </tbody> |
| |
| </table> |
| </div> |
| |
| <p>The following example adds a new component, MyComponent, to the |
| class definition file. This component has one instrumented event, <samp class="codeph">click</samp>:</p> |
| |
| <pre class="codeblock"> <TypeInformation xsi:noNamespaceSchemaLocation="ClassesDefintions.xsd" Priority="0" PackageName="TEA" Load="true" id="Flex" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> |
| <ClassInfo Name="MyComponent" GenericTypeID="mycomponent" |
| Extends="FlexObject" SupportsTabularData="false"> |
| <Description>FlexMyComponent</Description> |
| <Implementation Class="MyComponent"/> |
| <TypeInfo> |
| <Operation Name="Select" PropertyType="Method" |
| ExposureLevel="CommonUsed"> |
| <Implementation Class="myComponentClasses::MyComponentEvent" Type="click"/> |
| </Operation> |
| </TypeInfo> |
| <Properties> |
| <Property Name="automationClassName" ForDescription="true"> |
| <Type VariantType="String"/> |
| <Description>This is MyComponent.</Description> |
| </Property> |
| <Property Name="automationName" ForDescription="true"> |
| <Type VariantType="String"/> |
| <Description>The name used by tools to id an object.</Description> |
| </Property> |
| <Property Name="className" ForDescription="true"> |
| <Type VariantType="String"/> |
| <Description>To be written.</Description> |
| </Property> |
| <Property Name="id" ForDescription="true" ForVerification="true"> |
| <Type VariantType="String"/> |
| <Description>Developer-assigned ID.</Description> |
| </Property> |
| <Property Name="index" ForDescription="true"> |
| <Type VariantType="String"/> |
| <Description>The index relative to its parent.</Description> |
| </Property> |
| </Properties> |
| </ClassInfo> |
| ... |
| </TypeInformation></pre> |
| |
| <p>You can edit the class definitions file to add a new recordable |
| event to an existing component. To do this, you insert a new <samp class="codeph"><Operation></samp> in |
| the control's <samp class="codeph"><TypeInfo></samp> block. This includes |
| the implementation class of the event, and any arguments that the |
| event might take. </p> |
| |
| <p>The following example adds a new event, <samp class="codeph">MouseOver</samp>, |
| with several arguments to the Button control:</p> |
| |
| <pre class="codeblock"> <TypeInfo> |
| <Operation ExposureLevel="CommonUsed" Name="MouseOver" PropertyType="Method"> |
| <Implementation Class="flash.events::MouseEvent" Type="mouseOver"/> |
| <Argument Name="inputType" IsMandatory="false" |
| DefaultValue="mouse"> |
| <Type VariantType="String"/> |
| </Argument> |
| <Argument Name="shiftKey" IsMandatory="false" DefaultValue="false"> |
| <Type VariantType="Boolean"/> |
| </Argument> |
| <Argument Name="ctrlKey" IsMandatory="false" DefaultValue="false"> |
| <Type VariantType="Boolean"/> |
| </Argument> |
| <Argument Name="altKey" IsMandatory="false" DefaultValue="false"> |
| <Type VariantType="Boolean"/> |
| </Argument> |
| </Operation> |
| </TypeInfo></pre> |
| |
| <p>When you finish editing the class definitions file, you must |
| distribute the new file to the automation tool users. For QTP, users |
| must copy this file manually to the "<em>QTP_plugin_install</em>\Adobe |
| Flex 4 Plug-in for HP QuickTest Pro" directory. When you replace |
| the class definitions file in the QTP environment, you must restart QTP.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS2db454920e96a9e51e63e3d11c0bf69084-7a4b_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf69084-7a4b_verapache"><!-- --></a> |
| <h3 class="topictitle3">Setting the automationName property</h3> |
| |
| |
| <div> |
| <p>The <samp class="codeph">automationName</samp> property defines the |
| name of a component as it appears in testing scripts. The default |
| value of this property varies depending on the type of component. |
| For example, a Button control's <samp class="codeph">automationName</samp> is the |
| label of the Button control. Sometimes, the <samp class="codeph">automationName</samp> is |
| the same as the control's <samp class="codeph">id</samp> property, but this |
| is not always the case.</p> |
| |
| <p>For some components, Flex sets the value of the <samp class="codeph">automationName</samp> property |
| to a recognizable attribute of that component. This helps QC professionals recognize |
| that component in their scripts. For example, a Spark Button labeled "Process |
| Form Now" appears in the testing scripts as <samp class="codeph">SparkButton("Process Form Now")</samp>.</p> |
| |
| <p>If you implement a new component, or subclass an existing component, |
| you might want to override the default value of the <samp class="codeph">automationName</samp> property. |
| For example, UIComponent sets the value of the <samp class="codeph">automationName</samp> to |
| the component's <samp class="codeph">id</samp> property by default, but some |
| components use their own methods of setting its value.</p> |
| |
| <p>The following example sets the <samp class="codeph">automationName</samp> property |
| of the ComboBox control to "Credit Card List"; rather than using |
| the <samp class="codeph">id</samp> property, the testing tool typically uses |
| "Credit Card List" to identify the ComboBox in its scripts:</p> |
| |
| <pre class="noswf"><?xml version="1.0"?> |
| <!-- agent/SimpleComboBox.mxml --> |
| <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx"> |
| <fx:Script> |
| <![CDATA[ |
| [Bindable] |
| public var cards: Array = [ |
| {label:"Visa", data:1}, |
| {label:"MasterCard", data:2}, |
| {label:"American Express", data:3} |
| ]; |
| |
| [Bindable] |
| public var selectedItem:Object; |
| ]]> |
| </fx:Script> |
| <s:Panel title="ComboBox Control Example"> |
| <s:layout> |
| <s:VerticalLayout/> |
| </s:layout> |
| |
| <mx:ComboBox id="cb1" dataProvider="{cards}" width="150" |
| close="selectedItem=ComboBox(event.target).selectedItem" |
| automationName="Credit Card List"/> |
| |
| <s:VGroup width="250"> |
| <s:Label width="200" color="blue" |
| text="Select a type of credit card."/> |
| <s:Label text="You selected: {selectedItem.label}"/> |
| <s:Label text="Data: {selectedItem.data}"/> |
| </s:VGroup> |
| </s:Panel> |
| </s:Application> </pre> |
| |
| <p>If you do not set the value of the <samp class="codeph">automationName</samp> property, |
| the name of an object that appears in a testing tool is sometimes |
| a property that can change while the application runs. If you set |
| the value of the <samp class="codeph">automationName</samp> property, testing |
| scripts use that value rather than the default value. For example, by |
| default, QTP uses a Button control's <samp class="codeph">label</samp> property |
| as the name of the Button in the script. If the label changes, the |
| script can break. You can prevent this from happening by explicitly |
| setting the value of the <samp class="codeph">automationName</samp> property.</p> |
| |
| <p>Buttons that have no label, but have an icon, are recorded by |
| their index number. In this case, you should ensure that you set |
| the <samp class="codeph">automationName</samp> property to something meaningful |
| so that the QC professional can recognize the Button in the script. |
| This might not be necessary if you set the <samp class="codeph">toolTip</samp> property |
| of the Button because some tools such as QTP use that value if there |
| is no label.</p> |
| |
| <p>After the value of the <samp class="codeph">automationName</samp> property |
| is set, you should not change the value during the component's life |
| cycle.</p> |
| |
| <p>For item renderers, use the <samp class="codeph">automationValue</samp> property |
| rather than the <samp class="codeph">automationName</samp> property. You do |
| this by overriding the <samp class="codeph">createAutomationIDPart()</samp> method |
| and returning a new value that you assign to the <samp class="codeph">automationName</samp> property, |
| as the following example shows:</p> |
| |
| <pre class="codeblock"> <mx:List xmlns:mx="http://www.adobe.com/2006/mxml"> |
| <fx:Script> |
| <![CDATA[ |
| import mx.automation.IAutomationObject; |
| override public function |
| createAutomationIDPart(item:IAutomationObject):Object { |
| var id:Object = super.createAutomationIDPart(item); |
| id["automationName"] = id["automationIndex"]; |
| return id; |
| } |
| ]]> |
| </fx:Script> |
| </mx:List></pre> |
| |
| <p>This technique works for any container or list-like control to |
| add index values to their children. There is no method for a child |
| to specify an index for itself.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff5_verapache"><a name="WS2db454920e96a9e51e63e3d11c0bf67b82-7ff5_verapache"><!-- --></a> |
| <h2 class="topictitle2">Instrumenting composite components</h2> |
| |
| |
| <div> |
| <p>Composite components are custom components made up of two |
| or more components. A common composite component is a form that |
| contains several text fields, labels, and buttons. Composite components |
| can be MXML files or ActionScript classes.</p> |
| |
| <p>By default, you can record operations on all instrumented child |
| controls of a container. If you have a Button control inside a custom |
| TitleWindow container, the QA professional can record actions on |
| that Button control just like on any Button control. You can, however, |
| create a composite component in which some of the child controls |
| are instrumented and some are not. To prevent the operations of |
| a child component from being recorded, you override the following methods:</p> |
| |
| <ul> |
| <li> |
| <p> |
| <samp class="codeph">numAutomationChildren</samp> getter</p> |
| |
| </li> |
| |
| <li> |
| <p> |
| <samp class="codeph">getAutomationChildAt()</samp> |
| </p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The <samp class="codeph">numAutomationChildren</samp> property is a read-only |
| property that stores the number of automatable children that a container |
| has. This property is available on all containers that have delegate |
| implementation classes. To exclude some children from being automated, |
| you return a number that is less than the total number of children.</p> |
| |
| <p>The <samp class="codeph">getAutomatedChildAt()</samp> method returns the |
| child at the specified index. When you override this method, you |
| return null for the unwanted child at the specified index, but return |
| the other children as you normally would.</p> |
| |
| <div class="p">The following custom composite component is written in ActionScript. |
| It consists of a VGroup container with three buttons (OK, Cancel, |
| and Help). You cannot record the operations of the Help button. |
| You can record the operations of the other Button controls, OK and |
| Cancel. The following example sets the values of the OK and Cancel |
| buttons' <samp class="codeph">automationName</samp> properties. This makes |
| those button controls easier to recognize in the automated testing |
| tool's scripts.<pre class="noswf">// agent/MyVGroup.as |
| package { // Empty package |
| import mx.core.UIComponent; |
| import spark.components.VGroup; |
| import spark.components.Button; |
| import mx.automation.IAutomationObject; |
| import spark.automation.delegates.components.SparkGroupAutomationImpl; |
| |
| public class MyVGroup extends VGroup { |
| public var btnOk : Button; |
| public var btnHelp : Button; |
| public var btnCancel : Button; |
| |
| public function MyVGroup():void { // Constructor |
| } |
| |
| override protected function createChildren():void { |
| super.createChildren(); |
| |
| btnOk = new Button(); |
| btnOk.label = "OK"; |
| btnOk.automationName = "OK_custom_form"; |
| addElement(btnOk); |
| |
| btnCancel = new Button(); |
| btnCancel.label = "Cancel"; |
| btnCancel.automationName = "Cancel_custom_form"; |
| addElement(btnCancel); |
| |
| btnHelp = new Button(); |
| btnHelp.label = "Help"; |
| btnHelp.showInAutomationHierarchy = false; |
| addElement(btnHelp); |
| } |
| |
| override public function get numAutomationChildren():int { |
| return 2; //instead of 3 |
| } |
| |
| override public function |
| getAutomationChildAt(index:int):IAutomationObject { |
| switch(index) { |
| case 0: |
| return btnOk; |
| case 1: |
| return btnCancel; |
| } |
| return null; |
| } |
| } // Class |
| } // Package</pre> |
| |
| </div> |
| |
| <div class="p">The following application uses the MyVGroup custom component:<pre class="noswf"><?xml version="1.0"?> |
| <!-- agent/NestedButton.mxml --> |
| <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" |
| xmlns:s="library://ns.adobe.com/flex/spark" |
| xmlns:mx="library://ns.adobe.com/flex/mx" |
| xmlns:comps="*"> |
| <s:Panel title="Composite VGroup with Custom Automation Settings"> |
| <s:layout> |
| <s:VerticalLayout/> |
| </s:layout> |
| |
| <comps:MyVGroup/> |
| |
| </s:Panel> |
| </s:Application> </pre> |
| |
| </div> |
| |
| <p>To make this solution more portable, you could create a custom |
| Button control and add a property that determines whether a Button |
| should be testable. You could then set the value of this property |
| based on the Button instance (for example, <samp class="codeph">btnHelp.useInAutomation = false</samp>), |
| and check against it in the overridden <samp class="codeph">getAutomationChildAt()</samp> method, |
| before returning null or the button instance.</p> |
| |
| <div class="p">For better performance, you can use the <samp class="codeph">getAutomationChildren()</samp> method |
| rather than the <samp class="codeph">getAutomationChildAt()</samp> method; |
| for example:<pre class="codeblock">var childList:Array = getAutomationChildren(); |
| var n:int = childList ? childList.length : 0; |
| for (var i:int = 0; i < n; i++) { |
| var child:IAutomationObject = childList[i]; |
| ... |
| }</pre> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested1" id="WS02f7d8d4857b16772609039712671d4cb2b-8000_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-8000_verapache"><!-- --></a> |
| <h2 class="topictitle2">Custom agents</h2> |
| |
| |
| <div> |
| <p>The Automation Framework defines a single API that has |
| two parts:</p> |
| |
| <ul> |
| <li> |
| <p>Component API — Components must implement this API to |
| support automation features. Developers can choose to put the code |
| either in the main component itself or in a mixin class. Mixin classes |
| implement this API for Flex components. </p> |
| |
| </li> |
| |
| <li> |
| <p>Agent API — Agents use this API to communicate with the component |
| API. </p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>Component developers implement the component API for their component once |
| and then the component is ready to converse with any agent. Agent |
| developers implement the agent API for their specific feature or |
| tool and it is able to work with any application built with Flex. |
| For more information, see <a href="flx_functest_components2_fc.html#WS02f7d8d4857b16772609039712671d4cb2b-7ffe_verapache">About |
| the automation APIs</a>.</p> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b16772609039712671d4cb2b-7fff_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7fff_verapache"><!-- --></a> |
| <h3 class="topictitle3">Uses for agents</h3> |
| |
| |
| <div> |
| <p>You can use agents to gather metrics information, to use |
| automated testing, and to run applications at different locations |
| at the same time.</p> |
| |
| <div class="section"><h4 class="sectiontitle">Metrics</h4> |
| |
| <p>You might want to analyze how |
| your online applications are being used. By gathering metrics information, |
| you can answer the following questions:</p> |
| |
| <ul> |
| <li> |
| <p>What product |
| views are most popular?</p> |
| |
| </li> |
| |
| <li> |
| <p>When do users abandon the checkout process?</p> |
| |
| </li> |
| |
| <li> |
| <p>What is a typical path through my application?</p> |
| |
| </li> |
| |
| <li> |
| <p>How many product views does a user look at during a session?</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| <div class="section"><h4 class="sectiontitle">Automated testing</h4> |
| |
| <p>Maintaining the quality |
| of a large software application is difficult. Verifying lots of functionality |
| in any individual build can take a QA engineer many hours or even days, |
| and much of the work between builds is repetitive. To alleviate |
| this difficulty, automated testing tools have been created that |
| can use applications and verify behavior without human intervention. |
| Major application environments such as Java and .NET have testing |
| tool support from vendors such as QTP and Segue. </p> |
| |
| <p>By using |
| the Flex automation API, you can:</p> |
| |
| <ul> |
| <li> |
| <p>Record and replay |
| events in a separate tool</p> |
| |
| </li> |
| |
| <li> |
| <p>Manage communication between components and agents</p> |
| |
| </li> |
| |
| </ul> |
| |
| </div> |
| |
| <div class="section"><h4 class="sectiontitle">Co-browsing</h4> |
| |
| <p>You might want to run the |
| same application at different locations and view the application |
| at the same time. By using the automation API, you can ensure that the |
| applications are synchronized as users navigate through the them. |
| User interaction at any location can be played at other locations |
| and other users can see the action in real time.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b16772609039712671d4cb2b-7ffe_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ffe_verapache"><!-- --></a> |
| <h3 class="topictitle3">About the automation APIs</h3> |
| |
| |
| <div> |
| <p>There are four main parts that enable the automation framework |
| in Flex:</p> |
| |
| <ul> |
| <li> |
| <p>Core Flex API</p> |
| |
| </li> |
| |
| <li> |
| <p>Automation APIs</p> |
| |
| </li> |
| |
| <li> |
| <p>Agent class (also known as an adapter)</p> |
| |
| </li> |
| |
| <li> |
| <p>Automation tools</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The following illustration shows the relationship between these |
| parts: </p> |
| |
| <div class="figborder"> |
| <img src="images/ag_automation_api.png" alt="Automation API diagram."/> |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ffd_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ffd_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the SystemManager class</h4> |
| |
| |
| <div> |
| <p>The <a href="https://flex.apache.org/asdoc/mx/managers/SystemManager.html" target="_blank">SystemManager</a> class |
| is one of the highest level classes in an application built with |
| Flex. Every application built with Flex has a SystemManager class. |
| It is the parent of all displayable objects in the application, |
| such as the main spark.components.Application instance and all pop-up |
| windows, ToolTip instances, cursors, and so on. </p> |
| |
| <p>SystemManager calls the <samp class="codeph">init()</samp> method on all |
| mixins. The SystemManager class is responsible for creating the |
| AutomationManager class as well as the Agent and the delegate classes. |
| The SystemManager class is also responsible for adding the Application |
| object to Adobe<sup>®</sup> Flash<sup>®</sup> Player |
| or Adobe<sup>®</sup> AIR™ stage (root).</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ffc_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ffc_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the AutomationManager class</h4> |
| |
| |
| <div> |
| <p>The <a href="https://flex.apache.org/asdoc/mx/automation/AutomationManager.html" target="_blank">AutomationManager</a> class |
| is a Singleton that extends the EventDispatcher class. It implements |
| the <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationManager.html" target="_blank">IAutomationManager</a>, <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationObjectHelper.html" target="_blank">IAutomationObjectHelper</a>, |
| and <a href="https://flex.apache.org/asdoc/mx/automation/IAutomationMouseSimulator.html" target="_blank">IAutomationMouseSimulator</a> interfaces.</p> |
| |
| <p>AutomationManager is a mixin, so its <samp class="codeph">init()</samp> method |
| is called by the SystemManager class when the application is initialized. |
| In the <samp class="codeph">init()</samp> method, the AutomationManager class |
| adds an event listener for the <samp class="codeph">Event.ADDED</samp> event. This |
| event is dispatched by Flash Player or AIR whenever a display object |
| is added to the display list. When that happens, Flash Player or |
| AIR calls the <samp class="codeph">childAddedHandler()</samp> method:</p> |
| |
| <pre class="codeblock"> root.addEventListener(Event.ADDED, childAddedHandler, false, 0, true);</pre> |
| |
| <p>In the <samp class="codeph">childAddedHandler()</samp> method, the AutomationManager |
| class:</p> |
| |
| <ul> |
| <li> |
| <p>Creates a new instance of a delegate for each display |
| object.</p> |
| |
| </li> |
| |
| <li> |
| <p>Adds the display object to a delegate class map. This maps |
| the display object to a delegate instance; for example:</p> |
| |
| <pre class="codeblock"> Automation.delegateDictionary[componentClass] = Automation.delegateDictionary[className];</pre> |
| |
| <p>The |
| delegate class map is a property of the Automation class.</p> |
| |
| </li> |
| |
| <li> |
| <p>Ensures that all children of the new display object are added |
| to the class map as well.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>In the <samp class="codeph">recordAutomatableEvent()</samp> method, the |
| AutomationManager:</p> |
| |
| <ul> |
| <li> |
| <p>Creates an <samp class="codeph">AutomationRecordEvent.RECORD</samp> event.</p> |
| |
| </li> |
| |
| <li> |
| <p>Dispatches the <samp class="codeph">RECORD</samp> events. The agent |
| listens for these events. </p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The <samp class="codeph">recordAutomatableEvent()</samp> method is called |
| by the delegates.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ffb_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ffb_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the Automation class</h4> |
| |
| |
| <div> |
| <p>During application initialization, an instance of the <a href="https://flex.apache.org/asdoc/mx/automation/Automation.html" target="_blank">Automation</a> class |
| is created. This is a static class that maintains a map of its delegate |
| class to its component class. </p> |
| |
| <p>This object does the following for recording events:</p> |
| |
| <ul> |
| <li> |
| <p>Provides access to the AutomationManager class</p> |
| |
| </li> |
| |
| <li> |
| <p>Creates a <samp class="codeph">delegateDictionary</samp> as a static |
| property</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>For example, there is a MyButton class that extends the Button |
| class, but it does not have its own delegate class (MyButton might |
| not add any new functionality to be recorded or played back). When |
| the AutomationManager encounters an instance of the MyButton class, |
| it checks with the Automation class for a corresponding delegate |
| class. When it fails to find one, it uses the <samp class="codeph">getSuperClassName()</samp> method |
| to get the super class of the MyButton class, which is the Button |
| class.</p> |
| |
| <p>The AutomationManager then tries to find the delegate for this |
| Button class. At that point, the AutomationManager adds a new entry |
| into the delegate-component class for the MyButton class, associating |
| it with the ButtonDelegateAutomationImpl class, so that next time |
| the AutomationManager can find this mapping without searching the |
| inheritance hierarchy.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ffa_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ffa_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the delegate classes</h4> |
| |
| |
| <div> |
| <p>The delegate classes provide automation hooks to the Flex |
| components. The delegate classes are in the spark.automation.delegates.* |
| and mx.automation.delegates.* packages. They extend the UIComponentAutomationImpl |
| class. The delegates for the Spark components are named Spark<em>ControlName</em>AutomationImpl. |
| The delegates for the MX components are named <em>ControlName</em>AutomationImpl. |
| For example, the Spark Button control's delegate class is SparkButtonAutomationImpl.</p> |
| |
| <p>The delegate classes register themselves with their associated |
| Automation class by providing the component class and their own |
| class as input. The AutomationManager class uses the Automation |
| class-to-delegate class map to create a delegate instance that corresponds |
| to a component instance in the <samp class="codeph">childAddedHandler()</samp> method.</p> |
| |
| <p>The delegate classes are mixins, so their <samp class="codeph">init()</samp> method |
| is called by the SystemManager class. The <samp class="codeph">init()</samp> method |
| of the delegate classes:</p> |
| |
| <ol> |
| <li> |
| <p>Calls the <samp class="codeph">registerDelegateClass()</samp> method |
| of the Automation class. This method maps the class to an automation |
| component class; for example:</p> |
| |
| <pre class="codeblock"> var className:String = getQualifiedClassName(compClass); |
| delegateDictionary[className] = delegateClass;</pre> |
| |
| </li> |
| |
| <li> |
| <p>Adds event listeners for the mouse and keyboard events; for |
| example:</p> |
| |
| <pre class="codeblock"> obj.addEventListener(KeyboardEvent.KEY_UP, btnKeyUpHandler, false, EventPriority.DEFAULT+1, true); |
| obj.addEventListener(MouseEvent.CLICK, clickHandler, false, EventPriority.DEFAULT+1, true);</pre> |
| |
| </li> |
| |
| </ol> |
| |
| <p>These event handlers call the AutomationManager class's <samp class="codeph">recordAutomatableEvent()</samp> method, |
| which in turn dispatches the <samp class="codeph">AutomationRecordEvent.RECORD</samp> events |
| that the automation agent listens for.</p> |
| |
| <p>All core framework and charting classes have delegate classes |
| already created. You are not required to create any delegate classes |
| unless you have custom components that dispatch events that you |
| want to automate. In this case, you must create a custom delegate |
| class for inclusion in your application.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ff9_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ff9_verapache"><!-- --></a> |
| <h4 class="topictitle4">About the agent</h4> |
| |
| |
| <div> |
| <p>The agent facilitates communication between the application |
| built with Flex and automation tools such as QTP and Segue.</p> |
| |
| <p>When recording, the agent class is typically responsible for |
| implementing a persistence mechanism in the automation process. |
| It gets information about events, user sessions, and application |
| properties and typically writes them out to a database, log file, |
| LocalConnection, or some other persistent storage method. </p> |
| |
| <p>When you create an agent, you compile it and its supporting classes |
| into a SWC file. You then add that SWC file to your application |
| by using the <samp class="codeph">include-libraries</samp> command-line compiler |
| option. This compiles the agent into the application, regardless |
| of whether you instantiate that agent in the application at compile |
| time.</p> |
| |
| <p>A custom agent class must be a mixin, which means that its <samp class="codeph">init()</samp> method |
| is called by the SystemManager class. The <samp class="codeph">init()</samp> method |
| of the agent:</p> |
| |
| <ul> |
| <li> |
| <p>Defines a handler for the <samp class="codeph">RECORD</samp> events.</p> |
| |
| </li> |
| |
| <li> |
| <p>Defines the environment. The environment indicates what components |
| and their methods, properties, and events can be recorded with the |
| automation API.</p> |
| |
| </li> |
| |
| </ul> |
| |
| <p>A typical custom agent class uses an XML file that contains Flex |
| component API information. The agent typically loads this information |
| with a call to the <samp class="codeph">URLRequest()</samp> constructor, as |
| the following example shows:</p> |
| |
| <pre class="codeblock"> var myXMLURL:URLRequest = new URLRequest("AutomationGenericEnv.xml"); |
| myLoader = new URLLoader(myXMLURL); |
| automationManager.automationEnvironment = new CustomEnvironment(new XML(source));</pre> |
| |
| <p>In this example, the source is an XML file that defines the Flex |
| metadata (or environment information). This metadata includes the |
| events and properties of the Flex components.</p> |
| |
| <p>Note that representing events as XML is agent specific. The general-purpose automation |
| API does not require it, but the XML file makes it easy to adjust |
| the granularity of the events that are recorded. </p> |
| |
| <p>You are not required to create an instance of your adapter in |
| the <samp class="codeph">init()</samp> method. You can also create this instance |
| in the <samp class="codeph">APPLICATION_COMPLETE</samp> event handler if your |
| agent requires that the application must be initialized before it |
| is instantiated.</p> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b16772609039712671d4cb2b-7ff8_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ff8_verapache"><!-- --></a> |
| <h3 class="topictitle3">Understanding the automation flow</h3> |
| |
| |
| <div> |
| <p>When the application is initialized, the <a href="https://flex.apache.org/asdoc/mx/automation/AutomationManager.html" target="_blank">AutomationManager</a> object |
| is created. In its <samp class="codeph">init()</samp> method, it adds a listener |
| for <samp class="codeph">Event.ADDED</samp> events. </p> |
| |
| <p>The following image shows the order of events when the application |
| is initialized and the AutomationManager class constructs the delegate |
| map. </p> |
| |
| <div class="figborder"> |
| <img src="images/ag_automation_flow.png" alt="The order of events when the application is initialized and the AutomationManager class constructs the delegate map."/> |
| </div> |
| |
| <ol> |
| <li> |
| <p>The SystemManager class creates the display list, a tree |
| of visible objects that make up your application.</p> |
| |
| </li> |
| |
| <li> |
| <p>Each time a new component is added, either at the root of |
| the display list or as a child of another member of the display |
| list, SystemManager dispatches an <samp class="codeph">Event.ADDED</samp> event.</p> |
| |
| </li> |
| |
| <li> |
| <p>The AutomationManager listens for the <samp class="codeph">ADDED</samp> event. |
| In its <samp class="codeph">ADDED</samp> event handler, it calls methods on |
| the Automation class. It then instantiates the delegate for that |
| class.</p> |
| |
| </li> |
| |
| <li> |
| <p>The Automation class maps each component in the display list |
| to its full class name. </p> |
| |
| </li> |
| |
| <li> |
| <p>When it is created, the delegate class adds a reference to |
| its instance in the delegate class map. The delegate class then |
| handles events during record and play-back sequences.</p> |
| |
| <p>The |
| delegate is now considered <em>registered</em> with the component. |
| It adds event listeners for the component's events and calls the |
| AutomationManager when the component triggers those events.</p> |
| |
| </li> |
| |
| </ol> |
| |
| <p>After the components in the display list are instantiated and |
| mapped to instances of their delegate classes, the AutomationManager |
| is ready to listen for events and forward them to the agent for |
| processing.</p> |
| |
| <p>The following image shows the flow of operation when a user performs |
| an action that is a recordable event. In this case, the user clicks |
| a Button control in the application.</p> |
| |
| <div class="figborder"> |
| <img src="images/ag_button_control.png" alt="Flow of operation for a recordable event."/> |
| </div> |
| |
| </div> |
| |
| <div class="nested3" id="WS02f7d8d4857b16772609039712671d4cb2b-7ff7_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ff7_verapache"><!-- --></a> |
| <h4 class="topictitle4"/> |
| |
| |
| <div> |
| <ol> |
| <li> |
| <p>The user clicks the Button control in the application. |
| The SystemManager dispatches a <samp class="codeph">MouseEvent.CLICK</samp> event.</p> |
| |
| </li> |
| |
| <li> |
| <p>The SparkButtonAutomationImpl class, the Button control's |
| automation delegate, listens for <samp class="codeph">click</samp> events. |
| In the delegate's <samp class="codeph">click</samp> event handler, the delegate |
| calls the AutomationManager <samp class="codeph">recordAutomationEvent()</samp> method. |
| (It is likely that the button also defines a <samp class="codeph">click</samp> event |
| handler to respond to the user action, but that is not shown.) </p> |
| |
| </li> |
| |
| <li> |
| <p>The AutomationManager's <samp class="codeph">recordAutomationEvent()</samp> method dispatches |
| an <samp class="codeph">AutomationRecordEvent.RECORD</samp> event. In that |
| event, the <samp class="codeph">replayableEvent</samp> property points to the |
| original <samp class="codeph">click</samp> event.</p> |
| |
| </li> |
| |
| <li> |
| <p>The custom agent class listens for <samp class="codeph">RECORD</samp> events. |
| When it receives the <samp class="codeph">RECORD</samp> event, it uses the <samp class="codeph">replayableEvent</samp> property |
| to access the properties of the original event.</p> |
| |
| </li> |
| |
| <li> |
| <p>The agent records the event properties in a database, logs |
| the event properties, or gets information about the user before |
| recording them.</p> |
| |
| </li> |
| |
| </ol> |
| |
| </div> |
| |
| </div> |
| |
| </div> |
| |
| <div class="nested2" id="WS02f7d8d4857b16772609039712671d4cb2b-7ff6_verapache"><a name="WS02f7d8d4857b16772609039712671d4cb2b-7ff6_verapache"><!-- --></a> |
| <h3 class="topictitle3">Creating agents</h3> |
| |
| |
| <div> |
| <p>You create an agent as a SWC file and link it into the |
| application by using the <samp class="codeph">include-libraries</samp> compiler |
| option. You can link multiple agents in any number of SWC files |
| to the same application. However, to use multiple agents at the |
| same time, you must use the same environment configuration files |
| for all agents.</p> |
| |
| <p>The general process for creating a custom agent is:</p> |
| |
| <ul> |
| <li> |
| <p>Mark the agent class as a mixin; this triggers a call |
| to a static <samp class="codeph">init()</samp> method from the SystemManager |
| class on application start up.</p> |
| |
| </li> |
| |
| <li> |
| <p>Get a reference to the <a href="https://flex.apache.org/asdoc/mx/automation/AutomationManager.html" target="_blank">AutomationManager</a> class.</p> |
| |
| </li> |
| |
| <li> |
| <p>Add event listeners for the <samp class="codeph">APPLICATION_COMPLETE</samp> and <samp class="codeph">RECORD</samp> events.</p> |
| |
| </li> |
| |
| <li> |
| <p>Load the environment information (Flex metadata that describes |
| the objects and operations of the application). Environment information |
| can be an XML file or it can be in some other data format.</p> |
| |
| </li> |
| |
| <li> |
| <p>Define a static <samp class="codeph">init()</samp> method that creates |
| an instance of the agent.</p> |
| |
| </li> |
| |
| <li> |
| <p>Define a method that handles <samp class="codeph">RECORD</samp> events. |
| In that method, you can access:</p> |
| |
| <ul> |
| <li> |
| <p>Automation details |
| such as the automation name</p> |
| |
| </li> |
| |
| <li> |
| <p>User information such as the FlexSession object (through |
| a RemoteObject)</p> |
| |
| </li> |
| |
| <li> |
| <p>The event that triggered the <samp class="codeph">RECORD</samp> event |
| and its target</p> |
| |
| </li> |
| |
| </ul> |
| |
| </li> |
| |
| </ul> |
| |
| <p>The <samp class="codeph">RECORD</samp> event handler in the agent gets an <samp class="codeph">AutomationRecordEvent</samp> whose |
| target is the object on which recording happened. The <samp class="codeph">automationManager.createID()</samp> method |
| converts the object to a string that can be recorded on the screen. |
| Some tools may require the entire automation hierarchy that needs |
| to be generated in this method.</p> |
| |
| <p>You also use the custom agent class to enable and disable recording |
| of automation events.</p> |
| |
| </div> |
| |
| </div> |
| |
| <div> |
| <p><strong>Navigation</strong></p> |
| <p><a href="index.html">Using Flex</a> » <a href="flx_p8_qa_automation.html">Testing and automation</a></p> |
| </div> |
| |
| <p>Adobe, Adobe AIR, Adobe Flash Platform and Adobe Flash Player are either registered trademarks or trademarks of Adobe Systems Incorporated in the United States and/or other countries and are used by permission from Adobe. No other license to the Adobe trademarks are granted.</p> |
| </div> |
| |
| |
| </body> |
| </html> |