Dion Johnson use the martial arts metaphor four common issues with automated tests and how test automation specialiasts can "train" their scripts to identify, capture, and handle these problems. In this week's column, Dion talks about how to make develop test automation scripts that are flexible and reusable.
The martial arts are composed of various methods of combat that serve the purpose of defeating an opponent or defending oneself from a threat. Automated test scripts have an opponent, and that opponent is the application that the scripts are created to test. This opponent tries to prevent the automated scripts from winning the match by stopping the successful execution and detection of existing errors in the application. As test automators, it is our job to train those scripts for dynamic, hand-to-hand combat with the application.
Often test automators push automated test scripts into combat with the assumption that the application is simply going to let the script win. We assume that data never gets corrupted, scripts never need to be maintained, unexpected events never happen, and each test objective has only a single path. For this reason, scripts often fail easily, require excessive maintenance, and repeatedly overlook simple defects.
Application behavior is dynamic, so it's time that we train our automated scripts to be more dynamic via the techniques provided in the automation martial arts known simply as "Taekwondo-mation"! Taekwondo-mation comprises relatively simple techniques that can be employed without the implementation of an overly complex framework.
Taekwondo-mation, like many of the martial arts, places a focus on four key principles:
- Flexibility-Dynamically inputting data
- Balance-Inputting dynamic data
- Self-defense-Exception handling
- Strikes-Dynamic path handling
I will discuss each of these principles in future articles, but this article focuses on the principle of flexibility.
In Taekwondo-mation, flexibility addresses the ability to stretch a minimal amount of scripting as far as it will go. Dynamically inputting data, which simply refers to the ability to input or verify a lot of data with minimal scripting, greatly increases the elasticity of the scripts. Elasticity is important because time and resources often are limited for automated script development. Reducing time and effort involved in the script development and maintenance helps to make more scripting and analysis possible, which ultimately will help to increase the coverage achieved by the scripts.
This principle is similar to a data-driven automation approach. Data-driven testing addresses the ability to input multiple values into a field by parameterizing the field's inputs. The approach being introduced now actually suggests parameterizing the fields themselves, as well as the inputs. This level of parameterization provides the ability to input a variable number of data elements with a single statement.
The flexibility principle should not be confused with keyword automation framework. Keyword automation still typically requires each and every input to have a separate line in the keyword file. The technique being proposed here can be used to reduce the amount of statements necessary for automating a test, whether using standard scripting or keyword automation.
Let's examine the typical data-driven approach to inputting data. The data may be maintained in an external file, as in table 1.
Table 1: Data Table
The information then may be entered into the application with statements that resemble those in figure 1.
Figure 1: Standard Input Code Structure
Using a data-driven approach allows all three rows of data to be entered using the same group of inputs, but each input into a specific object still requires a separate statement (illustrated in the highlighted statements in figure 1). This can be particularly arduous when there are a lot of fields that require input on a given page. Not to mention that if it becomes necessary to come back to the page and verify the data still exists in these fields, another set of statements must be added to the test to verify each field. Not only is this laborious, but also it really clutters the script, thus decreasing readability. Taekwondo-mation's flexibility techniques provide the ability to reduce the above statements to the much simpler set of statements shown in figure 2.
Figure 2: Taekwondo-mation Input Code Structure
This is made possible by creating a reusable function that leverages the information that is in the data table and the information that exists in the object map(s) for that application. (Note: This could be accomplished even if you don't utilize an object map, but here we'll focus on how to accomplish it with an object map.) An object map (also known as an object repository) is a file that stores information about the application objects that may be automated in a script. This file contains the properties associated with a particular object and assigns a logical name to that object. For example, the First Name text box and Phone list box in an application may appear in an object map as follows:
Note that the logical name for the First Name text box is FirstName, while the associated properties of this object are the Class, Id, and Name properties. (Also note that this article doesn't use actual syntax, but rather pseudo-syntax simply to convey the essence of what the actual syntax should accomplish. Refer to the documentation related to your tool of choice and the data source to determine what the actual syntax should be.) The name and properties of the object are what allow an automated test to find and perform actions on an object in the application. Provided that the name of the Parameter in the data table is identical to the Logical name in the object map, a function easily can be created to do the bulk of the input logic for you. This function may resemble the figure 3.
Figure 3: Input_All_Data Function Structure
This function is what would be called in line 3 of figure 2. Below is an explanation of this function.
Step 1: Define Function and Pass Appropriate Parameters
In this step, the function is defined with three arguments:
- Page-Since object maps typically segment objects by page, it is necessary to identify on which page the objects exist.
- dataTable-This will indicate to the function what data source must be opened for retrieving the data.
- currentRow-This is the current row number in the data source from which data will be retrieved.
Step 2: Open Data Table
This step opens the data source and makes it accessible to the function.
Step 3: Get Total Number of Input Columns
This step gets the total number of input columns in the data source. For example, table 1 has six columns (excluding the first column with the numbers in it). The syntax for actually performing this will vary depending on the data source and the tool used to access the data source. For example, when accessing Microsoft Excel via VBScript, the CreateObject function can be used for invoking Excel, followed by Workbooks.Open to open a specific table.
Step 4: Create Column Loop
This loop will be responsible for accessing each data element in a single row and inputting the data into the application.
Step 5: Get Column Header
The parameter name given at the top of a column must be obtained, because this name will be used for finding the appropriate object in the object repository. As previously mentioned, the syntax for getting the column header will vary depending on the data source and the automation tool used for accessing the data source.
Step 6: Get Object and Object Class
This step is crucial in determining how to input the value into the object. There are often different statements or keywords for inputting data into different types of application objects. For example, inputting data into a textbox may require a set statement, while inputting data into a list box may require a select statement. Once the object's class is determined, the function can be instructed on how to input data into that object.
Step 7: Input Data
This step represents a branching construct (e.g., a select/case branching construct), that takes the object class captured in the previous statement and determines what syntax will be required to input data into an object based on that class. For example, the statement may resemble figure 4.
Figure 4: Input Branching Construct
Note that the major input field types are addressed in the branching construct and that the statements used for inputting the data associated with the table parameter varies depending on the object class.
Steps 8 & 9: End Loop and Function
Steps 8 and 9 close out the loop and the function respectively.
Once this type of function is created, it is reusable, simple to maintain, and powerful. A similar function can be created to verify data values, so now multiple input fields can have data entered and verified with only a couple of statements added to a test script.
Stay tuned for Part II of the Taekwondo-mation series, where I will explore the principle of Balance (inputting random data).
Read Training Test Automation Scripts for Dynamic Combat: Balance - Part II
Read Training Test Automation Scripts for Dynamic Combat: Self Defense - Part III
Read Training Test Automation Scripts for Dynamic Combat: Strikes - Part IV