Writing Script Extensions

Tasks ››
Parent Previous Next

Writing Script Extensions

Script Extension Points

When the original functionality of testIDEA is not enough, we can extend it by writing Python functions and scripts. There exist three kinds of script extension points:

All extensions should be implemented as methods in extension script file. The only exception are GUI script extensions, which are described in section GUI extensions.

Configuration of script environment

Configuration for execution of scripts is accessible with command File | Properties | Scripts:

Each parameter is described in its tool-tip.

Note: Path to Python interpreter is the same as used by winIDEA. If you need to change it, please see winIDEA dialog Tools | Options, tab Scripts.

Test case extensions

These extensions can be defined for each test case. This means, that each test case may specify different script methods to be executed during test case run. These methods are defined in file and class specified in configuration.

There exist six extension points in test case:

Writing the script extension

Python script file with extension functions can be written manually from scratch, or by wizard. The description of manual script creation is following, while the wizard is described in a separate section.

Script functions should be implemented as methods of class in Python module. First we create a file with extension py. File name is also the name of the module. This name should be specified in the Imported modules field in the configuration dialog above. This way testIDEA can tell Python interpreter where to find our code.

Next we write a class in the created file. It is a normal Python class with methods. Names of the methods must be the same as given in test case. The number of parameters must also match.

Example of class with one extension method:

     class SampleExtension:
         def __init__(self, mccMgr = None):
             pass
         def initTarget(self):
             print 'Executing initTarget()'
   

Since we'll usually need isystem.connect calls to access the target, it is a good idea to import the module and initialize access object in extension class constructor, for example:

   import isystem.connect as ic
   class SampleExtension:
       def __init__(self, mccMgr = None):
           """
           Normally we'll connect to winIDEA, which is running the test, so that
           target state can be accessed/modified by this script.
           """
           if mccMgr == None:
               # Executed when called from testIDEA.
               # Connection can't be passed between processes.
               self.mccMgr = None
               self.connectionMgr = ic.ConnectionMgr()
               self.connectionMgr.connectMRU()
               self.debug = ic.CDebugFacade(self.connectionMgr)
           else:
               # Executed when called from generated script - connection is reused.
               self.mccMgr = mccMgr
               self.connectionMgr = mccMgr.getConnectionMgr('')
               self.debug = mccMgr.getCDebugFacade('')
           self.testCtrl = None
   
       def initTarget(self):
           print 'Executing initTarget()'
           for i in  range(0, 10):
               self.debug.modify(ic.IConnectDebug.fMonitor, 'g_charArray1[' + str(i) + ']',
                                 str(i*i))
   

Note that for access to test local variables declared in testIDEA, we have to use instance of class CTestCaseController. See below for procedure of getting this object. If this class is saved to file sampleTestExtensions.py, we configure testIDEA as shown in the image above. Similar class can be found in Python SDK: examples\winIDEA\sampleTestExtensions.py.

How can extension methods provide feedback?

There are several kinds of information a method can provide, and each has its own purpose:

Extension (tag)

Variable name

Initialize Target (initTarget)

_isys_initTargetInfo

Initialize Variables (initFunc)

_isys_initFuncInfo

Verify Variables (endFunc)

_isys_endFuncInfo

Restore Target (restoreTarget)

_isys_restoreTargetInfo

Stubs (stub: script)

_isys_stubInfo

Test Points (testPoint: script)

_isys_testPointInfo

Example of setting a variable in Python script:

         self._isys_initTargetInfo = 'information from initTarget()'
     

Variables are set to None by testIDEA after extension function returns.

When not set to None, type of these variables should always be string.

Return values and info variables of each function can be seen in tool-tips of decorations next to extension function name in section Scripts in testIDEA. Red decoration means error, green one means information is available, while no decoration means no error and no information:

Important: Standard output (print statements) should be used for debugging only, and script info and return values should be at most few lines long. This way reports and information in testIDEA UI will be readable. For more extensive measurements scripts should use files.

How to access target variables

One of the tasks for script functions is evaluating values of target variables and modifying them. By the term target variables this manual refers to one of the following:

All target variables can be accessed with an instance of isystem.connect class CTestCaseController. Before testIDEA calls script extension functions it sets Python variable _isys_testCaseHandle to the value of current test case handle. To instantiate CTestCaseController inside script extension functions use the following Python code:

   def myExtFunction(self, testSpec):
       if self.testCtrl == None:
           self.testCtrl = ic.CTestCaseController(self.connectionMgr,
                                                  self._isys_testCaseHandle)

To access target variables use the following example:

       # 'nItems' is the name of parameter specified in 'Parameters' field of the
       # 'Stubs' section in testIDEA. 'srv' is the name of return value as
       # specified in the same section.
       # Format specifier 'd' in 'nItems,d' ensures that the returned string
       # always contains decimal value.
         
       nItems_t = int(self.testCtrl.evaluate('nItems,d'))
       print 'nItems = ', nItems_t
       self.testCtrl.modify('srv', str(nItems_t * 2))
       

Tip: To avoid confusion, it is highly recommended to use a prefix or postfix for all Python variables, which are related to target variables. For example, above we have used postfix _t to mark that Python variable nItems_t is related to target variable nItems.

How to access test specification

If test specification data in the script function is needed, then the first parameter in testIDEA should be specified as variable _isys_testSpec. This parameter is initialized to the instance of CTestSpecification, which contains all information about the test case executed.

Reserved identifiers

All identifier names (variable, function, module, ... names) starting with string _isys_ are reserved. It is strongly advised to not use such names for custom identifiers, to avoid problems with the future versions of testIDEA.

Script extensions wizard

The wizard for script extensions is accessible with menu command iTools | Script Extensions Wizard. It creates an initial script file, which can be customized according to our requirements, and sets names of script functions in the selected test case. If no test case is selected, then only script is generated. It is recommended to create the script in the winIDEA project directory (where xjrf file is located), because then Python paths for module loading do not have to be modified.

Test execution extensions

These extensions are defined as methods in file and class specified in configuration. They are called at the following occasions:

           def isys_getTestReportCustomData(self, reportConfig):
           
                # get revisions as mapping
                data = {'_appRev': 12355, 'bootloaderRev': '1.05g'}
                # create string of 'key: value' pairs suitable for test report
                dataAsList = [(k + ': ' + str(v)) for k, v in data.items()]
                self._isys_customScriptMethodInfo = '\n'.join(dataAsList)
         

If key starts with an underscore, it is saved to test report, but it is not saved to iyaml file. Other key/value pairs are saved also to iyaml file.

Return value should be None if no error occurred, error message as string otherwise.
This function has a predefined name - there is no setting in testIDEA.

Parameter reportConfig in script functions called during report saving contains report configuration as string in iyaml format, for example:

   testIDEAVersion: 9.12.279
   winIDEAVersion: 9.12.279
   reportContents: full
   outFormat: xml
   fileName: 'report\reportFull.xml'
   iyamlFileName: d:\bb\trunk\sdk\targetProjects\testIDEADemo.iyaml
   xsltFull: ' isystemTestReport.xslt'
   xmlLogoImage: file://D:\bb\trunk\Eclipse\testidea\si.isystem.itest.plugin.core\i
   cons\itest_window_128.gif
   xmlReportHeader: |-
     Test Report
   cssFile:  blue.css
   csvSeparator: ','
   isCSVHeaderLine: true
   isXLSVerticalHeader: false
   isIncludeTestSpec: true
   isAbsPathForLinks: true
   htmlViewMode: all
   testInfo:
     Date: 2016-05-16
     Time: 16:11:04
     Subversion rev.: 58135
     description: release build
     hardware: cortex
     wiWorkspacePath:
     bootloader: '1.05g'
     _appRev: '12.35'
 

GUI extensions

These script extensions appear in menu iTools, and must be selected explicitly by user to be executed. To refresh the list in the menu, execute command iTools | Refresh. Two kinds of GUI extensions exist:

Methods in extension script file

These methods should be defined in the script extension file and class, which are set in File | Properties | Scripts. All methods, which start with prefix _isys_cmd_ are listed in menu iTools. When called, all methods receive name of the iyaml file in the currently active editor as parameter.

Example:

   def isys_cmd_printHi(self, iyamlFile):
       print("HI! Script method executed, parameter = ", iyamlFile)
   

For function output the same rules as for other extension functions defined in this file apply. Method result can be printed to stdout or stored to variable self._isys_customScriptMethodInfo. Any text printed to stderr or return value other than None mean error. See file basicTutorialExtensions.py, which comes with SDK for examples.

Standalone scripts

Python scripts (extension *.py), which are located in the same directory as iyaml file, are listed in the menu iTools. To get script directory, iyaml file which was opened in an active editor when command iTools | Refresh was executed, is used.

To avoid inconveniently long lists in the menu, scripts are sorted alphabetically, and only the first ten are used. One possible naming convention for scripts, which we want to run from testIDEA, would be to start their names with an underscore ('_') character.

Scripts can be run in three modes: