Studio:Using Scripts to Automate Software Testing: Difference between revisions

From STRIDE Wiki
Jump to navigation Jump to search
No edit summary
m (Text replace - 'Category:Scripting' to 'Category:Studio:Scripting')
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
Much of what software developers generally dislike about testing can be overcome with better automation. Not only does automation reduce repetition, it will also help to ensure the accuracy and repeatability of tests. Because STRIDE makes your embedded application's interfaces accessible in the scripting language of your choice, using scripts is an ideal way to better automate testing.
This entry shows how to use a script running in [[STRIDE Studio]] to test a function. The basic technique is also applicable to less-frequently-used messaging interfaces.


The subject of this topic defines how to use scripts to supply inputs to a function, component, or application over one or more interfaces. These interfaces can be messaging-based or function-based. In STRIDE terminology, the script tends to be the ''User'' of the interface or interfaces. (In contrast, [[Using Scripts to Simulate Missing Software Units]] tends to involve scripts that are the ''Owner'' of an interface or interfaces.)
In STRIDE terminology, the script is the ''User'' of the interface. (In contrast, [[Using Scripts to Simulate Missing Software Units]] involves a script that is the ''Owner'' of an interface.)


Via its objects, methods, and properties, '''ascript''' is the bridge between the interfaces in your embedded application and your favorite scripting language. A complete list of the objects, methods, and properties for use in your scripts can be found in the Online Help installed with STRIDE Studio. The objective of this topic is to focus on those objects, methods, and properties you will need to automate the testing of your software.
The script's injected '''[[AutoScript|ascript]]''' object instance provides the bridge between the interfaces in your embedded application and your favorite scripting language.
 
Note: To test a function, component, or application using a script, the corresponding interface(s) must be [accessible to STRIDE]. In addition, you will need an [intercept module] if any of the interfaces cross platform boundaries.


=Example=
=Example=
In this example, we will be testing a target-based function that takes an integer as an argument, and returns an enumeration indicating whether the passed-in number is a leap year.


<source lang="cpp">
In an actual testing scenario, the function would be implemented on your target system. Also, the example header file would be added to your workspace and the script file would be created and added to your workspace.
/*
    The Gregorian calendar has 97 leap years every 400 years:


        Every year divisible by 4 is a leap year, except:.
==Header File==
        - a year divisible by 100 is not a leap year except:
Below is the sample <code>.h</code> file that defines the interface we will be testing. Typically, this is a header file from the target codebase.
            - a year divisible by 400 is a leap year after all.


    For simplicity, any year prior to the introduction of the Gregorian Calendar
Notice that it is annotated with SCL <code>#pragma</code>s to provide needed metadata to the STRIDE compiler. When SCL <code>#pragma</code>s are inline with the source, we generally surround them with <code>#ifdef</code>s to prevent them from being seen by your code compiler.
    (1582) is considered to be NOT a leap year.  
*/


<source lang="c">
#ifndef _LEAPYEAR_H_
#ifndef _LEAPYEAR_H_
#define _LEAPYEAR_H_
#define _LEAPYEAR_H_
Line 47: Line 42:


#ifdef _SCL
#ifdef _SCL
// tell the STRIDE compiler that the IsLeapYear should be captured (i.e. instrumented)
// Tell the STRIDE compiler that the IsLeapYear should be captured (i.e. instrumented).
// Capturing the function allows it to be called from a script
#pragma scl_function(IsLeapYear)
#pragma scl_function(IsLeapYear)
// tell the STRIDE compiler that the return value of IsLeapYear is constrained to
// Tell the STRIDE compiler that the return value of IsLeapYear is constrained to
// the enumeration eIsLeapYear
// the enumeration eIsLeapYear
#pragma scl_values(IsLeapYear(), eIsLeapYear)
#pragma scl_values(IsLeapYear(), eIsLeapYear)
Line 57: Line 53:
</source>
</source>


<source lang="javascript">
In a testing scenario, this header file is processed by the STRIDE compiler to produce a metadata database, and an Intercept Module (IM) is generated. The IM comprises a set of source files that provide proxy/stub functionality for the captured functions. The IM files become part of your target code build.
// create a new test in the parent suite
 
var test = testSuite.Tests.Add("Leap Year Test");
Note that once built, STRIDE compilation and IM generation only needs to be done if the function signature changes.


// initialize the test input values
You can now use a script to interact with the captured function.
var arInput = new Array(1600, 1604, 1996, 2000);


// get the function user instance
==Test Scripts==
var f = ascript.Functions.Item("IsLeapYear").User;
The following example test scripts demonstrate how to set up and call a remote function. They also show rudimentary use of the '''testSuite''' object to report on test results.


var nIndex;
The scripts provide identical functionality: a common pattern of exercising the target function by calling it in a loop iterating through a set of inputs. The function's return value is validated and the test result set accordingly.


// iterate through the members of arInput
Note that we use a single test case to test the entire set of input values, and we bail out of the test at the first failure. Another approach is to create a test case for each input value.
for (nIndex in arInput) {
    // set the parameter value
    f.ParameterList.uYear = arInput[nIndex];
   
    // call the function synchronously; the STRIDE runtime will route the call to the
    // currently registered function owner
    f.Call();
   
    // test the return value; note that the value is returned as the name of the enumerator
    if (f.ReturnValue == "YES") {
        test.Status = "PASS";
    }
    else {
        test.Status = "FAIL";
        break;
    }
}
</source>


===Perl Test===
<source lang="perl">
<source lang="perl">
# standard STRIDE preamble for Perl
use strict;
use strict;
use Win32::OLE;
use Win32::OLE;
Win32::OLE->Option(Warn => 3);
Win32::OLE->Option(Warn => 3);


# create a new test in the parent suite
my $test = $main::testSuite->Tests->Add("Leap Year Positive Test");
my $test = $main::testSuite->Tests->Add("Leap Year Positive Test");


# initialize the test input values
my @input = (1600, 1604, 1996, 2000);
my @input = (1600, 1604, 1996, 2000);


# get the function user instance
my $f = $main::ascript->Functions->Item("IsLeapYear")->User;
my $f = $main::ascript->Functions->Item("IsLeapYear")->User;


# iterate through the members of arInput
for my $i (0..$#input)
for my $i (0..$#input)
{
{
    # set the parameter value
     $f->ParameterList->{uYear} = $input[$i];
     $f->ParameterList->{uYear} = $input[$i];


    # call the function synchronously; the STRIDE runtime will route the call to the
    # currently registered function owner
     $f->Call();
     $f->Call();


    # test the return value; note that the value is returned as the name of the enumerator
     if ($f->ReturnValue eq "YES") {
     if ($f->ReturnValue eq "YES") {
         $test->{Status} = "PASS";
         $test->{Status} = "PASS";
Line 116: Line 103:
</source>
</source>


===JScript Test===
<source lang="javascript">
// create a new test in the parent suite
var test = testSuite.Tests.Add("Leap Year Test");
// initialize the test input values
var arInput = new Array(1600, 1604, 1996, 2000);
// get the function user instance
var f = ascript.Functions.Item("IsLeapYear").User;
var nIndex;
// iterate through the members of arInput
for (nIndex in arInput) {
    // set the parameter value
    f.ParameterList.uYear = arInput[nIndex];
   
    // call the function synchronously; the STRIDE runtime will route the call to the
    // currently registered function owner
    f.Call();
   
    // test the return value; note that the value is returned as the name of the enumerator
    if (f.ReturnValue == "YES") {
        test.Status = "PASS";
    }
    else {
        test.Status = "FAIL";
        break;
    }
}
</source>


[[Category:Scripting]]
[[Category:Studio:Scripting]]

Latest revision as of 23:46, 20 August 2009

This entry shows how to use a script running in STRIDE Studio to test a function. The basic technique is also applicable to less-frequently-used messaging interfaces.

In STRIDE terminology, the script is the User of the interface. (In contrast, Using Scripts to Simulate Missing Software Units involves a script that is the Owner of an interface.)

The script's injected ascript object instance provides the bridge between the interfaces in your embedded application and your favorite scripting language.

Example

In this example, we will be testing a target-based function that takes an integer as an argument, and returns an enumeration indicating whether the passed-in number is a leap year.

In an actual testing scenario, the function would be implemented on your target system. Also, the example header file would be added to your workspace and the script file would be created and added to your workspace.

Header File

Below is the sample .h file that defines the interface we will be testing. Typically, this is a header file from the target codebase.

Notice that it is annotated with SCL #pragmas to provide needed metadata to the STRIDE compiler. When SCL #pragmas are inline with the source, we generally surround them with #ifdefs to prevent them from being seen by your code compiler.

#ifndef _LEAPYEAR_H_
#define _LEAPYEAR_H_

// first year of the gregorian calendar
#define FIRST_GREGORIAN_YEAR 1582

typedef enum 
{
    NO,
    YES,
} eIsLeapYear;


/**
 * Tests whether the passed-in year is a leap year
 * 
 * @param nYear  The year to be tested. Valid values are from
 *               FIRST_GREGORIAN_YEAR to 0xffffffff inclusive
 * 
 * @return YES - the passed-in year is a leap year
 *         NO - the passed-in year is not a leap year, or is pre-gregorian
 */
eIsLeapYear IsLeapYear(unsigned int uYear);


#ifdef _SCL
// Tell the STRIDE compiler that the IsLeapYear should be captured (i.e. instrumented).
// Capturing the function allows it to be called from a script
#pragma scl_function(IsLeapYear)
// Tell the STRIDE compiler that the return value of IsLeapYear is constrained to
// the enumeration eIsLeapYear
#pragma scl_values(IsLeapYear(), eIsLeapYear)
#endif

#endif // _LEAPYEAR_H_

In a testing scenario, this header file is processed by the STRIDE compiler to produce a metadata database, and an Intercept Module (IM) is generated. The IM comprises a set of source files that provide proxy/stub functionality for the captured functions. The IM files become part of your target code build.

Note that once built, STRIDE compilation and IM generation only needs to be done if the function signature changes.

You can now use a script to interact with the captured function.

Test Scripts

The following example test scripts demonstrate how to set up and call a remote function. They also show rudimentary use of the testSuite object to report on test results.

The scripts provide identical functionality: a common pattern of exercising the target function by calling it in a loop iterating through a set of inputs. The function's return value is validated and the test result set accordingly.

Note that we use a single test case to test the entire set of input values, and we bail out of the test at the first failure. Another approach is to create a test case for each input value.

Perl Test

# standard STRIDE preamble for Perl
use strict;
use Win32::OLE;
Win32::OLE->Option(Warn => 3);

# create a new test in the parent suite
my $test = $main::testSuite->Tests->Add("Leap Year Positive Test");

# initialize the test input values
my @input = (1600, 1604, 1996, 2000);

# get the function user instance
my $f = $main::ascript->Functions->Item("IsLeapYear")->User;

# iterate through the members of arInput
for my $i (0..$#input)
{
    # set the parameter value
    $f->ParameterList->{uYear} = $input[$i];

    # call the function synchronously; the STRIDE runtime will route the call to the
    # currently registered function owner
    $f->Call();

    # test the return value; note that the value is returned as the name of the enumerator
    if ($f->ReturnValue eq "YES") {
        $test->{Status} = "PASS";
    }
    else {
        $test->{Status} = "FAIL";
        last;
    } 
}

JScript Test

// create a new test in the parent suite
var test = testSuite.Tests.Add("Leap Year Test");

// initialize the test input values
var arInput = new Array(1600, 1604, 1996, 2000);

// get the function user instance
var f = ascript.Functions.Item("IsLeapYear").User;

var nIndex;

// iterate through the members of arInput
for (nIndex in arInput) {
    // set the parameter value
    f.ParameterList.uYear = arInput[nIndex];
    
    // call the function synchronously; the STRIDE runtime will route the call to the
    // currently registered function owner
    f.Call();
    
    // test the return value; note that the value is returned as the name of the enumerator
    if (f.ReturnValue == "YES") {
        test.Status = "PASS";
    }
    else {
        test.Status = "FAIL";
        break;
    }
}