Friday, May 4, 2007

WinRunner Tips

WinRunner Fundamentals
The 5 major areas to know for WinRunner are listed below with SOME of the subtopics called out for each of the major topics:
1) GUI Map
- Learning objects
- Mapping custom objects to standard objects
2) Record/Playback
- Record modes: Context Sensitive and Analog
- Playback modes: (Batch), Verify, Update, Debug
3) Synchronization
- Using wait parameter of functions
- Wait window/object info
- Wait Bitmap
- Hard wait()
4) Verification/Checkpoints
- window/object GUI checkpoints
- Bitmap checkpoints
- Text checkpoints (requires TLS)
5) TLS (Test Script Language)
- To enhance scripts (flow control, parameterization, data driven test, user defined functions,...

Calling Scripts and Expected Results
When running in non-batch mode, WinRunner will always look in the calling scripts \exp directory for the checks. When running in batch mode, WinRunner will look in the called script's \exp directory.
There is a limitation, though. WinRunner will only look in the called script's \exp directory one call level deep. For example, in bacth mode: script1:
gui_check(...); #will look in script1\exp
call "script2" ();
script2:
gui_check(...); #will look in script2\exp
call "script3" ();
script3:
gui_check(...); #will look in script2\exp (and cause an error)
In non bacth mode:
script1:
gui_check(...); #will look in script1\exp
call "script2" ();
script2:
gui_check(...); #will look in script1\exp (and cause an error)
call "script3" ();
script3:
gui_check(...); #will look in script1\exp (and cause an error)

Run Modes
Batch mode will write results to the individual called test.
Interactive (non-batch) mode writes to the main test.

Data Types
TSL supports two data types: numbers and strings, and you do not have to declare them. Look at the on-line help topic for some things to be aware of:
"TSL Language", "Variables and Constants", "Type (of variable or constant)"
Generally, you shouldn't see any problems with comparisons.
However, if you perform arithmetic operations you might see some unexpected behavior (again check out the on-line help mentioned above). var="3abc4";rc=var + 2; # rc will be 5 :-)

Debugging
When using pause(x); for debugging, wrap the variable with brackets to easily see if "invisible" characters are stored in the variable (i.e., \n, \t, space, or Null) pause("[" & x & "]");
Use the debugging features of WinRunner to watch variables. "invisible" characters will show themselves (i.e., \n, \t, space) Examples:
Variable
pause(x);
pause("[" & x & "]");
x="a1";
a1
[a1]
x="a1 ";
a1
[a1 ]
x="a1\t";
a1
[a1 ]
x="a1\n";
a1
[a1]
x="";

[]


Block Comments
To temporarily comment out a block of code use: if (TRUE) { ... block of code to be commented out!! }

Data Driven Test ddt_* functions vs getline/split
These bothfunctions do almost the same thing. There are some agruably good benefits to using ddt_* , but most of them are focused on the data management. In general you can always keep the data in Excel and perform a Save As to convert the file to a delimited text file.
One major difference is in the performance of playing back a script that has a huge data file. The ddt_* functions currently can not compare to the much faster getline/split method.
But here is an area to consider: READABILITY I personally do not like scripts with too many nested function calls (which the parameterize value method does) because it may reduce the readability for people with out a programming background. Example:
edit_set("FirstName", ddt_val(table, "FirstName"));
edit_set("LastName", ddt_val(table, "LastName"));
So what I typically do is, declare my own variables at the beginning of the script, assign the values to them, and use the variable names in the rest of the script. It doesn't matter if I'm using the getline/split or ddt_val functions. This also is very useful when I may need to change the value of a variable, because they are all initialized at the top of the script (whenever possible). Example with ddt_* functions in a script:
FIRSTNAME=ddt_val(table, "FirstName");
LASTNAME=ddt_val(table, "LastName");
...
edit_set("FirstName", FIRSTNAME);
edit_set("LastName", LASTNAME);
And most of the time I have a driving test which calls another test and passes an array of data to be used to update a form. Example with ddt_* functions before calling another
script:
# Driver script will have
...
MyPersonArray [ ] =
{
"FIRSTNAME" = ddt_val(table, "FirstName");
"LASTNAME" = ddt_val(table, "LastName");
}
call AddPerson(MyPersonArray)
...
# Called script will have
edit_set("FirstName", Person["FIRSTNAME"]);
edit_set("LastName", Person["LASTNAME"]);
So as you can see, there are many ways to do the same thing. What people must keep in mind is the skill level of the people that may inherit the scripts after they are created. And a consistent method should be used throughout the project.


String Vs Number Comparison

String Vs Number comparisons are not a good thing to do.
Try this sample to see why:
c1=47.88 * 6;
c2="287.28";
#Prints a decimal value while suppressing non-significant zeros
#and converts the float to a string.
c3 = sprintf ("%g", c1);

pause ("c1 = [" & c1 & "]\nc2 = [" & c2 & "]\nc3 = [" & c3 & "]\n" & "c1 - c2 =
[" & c1 - c2 & "]\nc1 - c3 = [" & c1 - c3 & "]\nc2 - c3 = [" & c2 - c3 & "]");