Reusing Code

There’s no way to get around it: Repetition is a fact of life in testing. Fortunately, there are several easy ways to let scripts and handlers do the repeating for you:

Calling Scripts from Other Scripts

One of the most common ways to reuse code is to call a script from a different script. To call a script, insert the script's name in your code, followed by any parameters that the script requires. The script call can be treated as if the script itself were a command or a function. For detailed information about calling other scripts, see Running Other Scripts and Handlers.

Following are examples of calling scripts from within a script:

CycleWindows // Calls a simple script name as a command

 

ConnectionScript "Old SUT", "New SUT" // Calls a simple script name with parameters

 

put CaptureTheScreen("SomePrefix",1) into myScreenCapture

// Calls a script as a function with parameters and puts the result in a variable

Whether you use the command call or the function call depends on the script itself. Both types can take input parameters, in which case the called script needs to begin with a params declaration. The function call also returns values, in which case the called script must include a return statement.

If you use a simple script name (with no spaces or special characters) and store scripts in the same suite or a helper suite, you can use the script name as a Run command, followed by any parameters it requires.

For a script in an unrelated suite, or a script with spaces or special characters in its name, you can type the Run command, followed by the script path:

Run "/Users/Seiji/Documents/EggPlant Suites/Validation.suite/Scripts/ConnectionScript"

// Calls the Run command to open a script from an unrelated suite

Because of this ability to call a script from within another script, it's useful to think about writing scripts in segments that perform specific tasks or actions. This "modular" approach allows you the most opportunity to reuse scripts in different contexts. In such a case, your "main" script would include code for test or environment specifics but would call out to a different script to complete generic tasks.

More detailed information about using handlers and helper suites, which are both features that can help with code reuse and modular design, can be found below.

Code Refactoring

Sometimes as you're writing scripts, you might find that a section of the script could be useful in other contexts or for other scripts. For instance, you've written a procedure that performs an action on your SUT that you'll need to repeat frequently, such as returning to the desktop. You might need to perform the action at different points in the script, and if you're using the same SUT in different tests, you might be able to use the same procedure in different scripts.

You can use the Extract New Script feature to perform code refactoring and create a new script from a section of code. To use this feature, select (or highlight) the code in the Script Editor that you want to reuse, then right-click and select Extract New Script. You can also find this option on the menu at Edit > Extract New Script. When you choose this option, a couple of things happen:

  • The code you selected in the Script Editor is removed and placed in a new script, initially called Untitled. You can see that the new script is added to the Scripts list, although it isn't opened.
  • In place of the code in the Script Editor, you'll see the name of the new script, which is highlighted so that you can rename it to something descriptive for the procedure. When you apply a name in the Script Editor, the name changes in the Scripts list as well.
Note: The editor won't let you use the same name for different scripts. If you try to rename a script with a name that already exists, or if you use invalid character, the selection box turns red to let you know.

If the code you select to extract includes variables that are referenced outside that section of code, the Extract New Script feature handles how those values are passed:

  • Any variables that are used in the selection that also exist earlier in the script are added as the new script's params declaration. The new script is called as a command, so in the Script Editor, the variable will be listed after the new script name as a parameter when it executes.

    ExtractedScript MyVar

  • Any variables that are used in the selection that also exist later in the script are added as the new script's return declaration. In this case, the new script is called as a function instead of a command, and the returned value is put into the variable:

    put ExtractedScript(MyVar) into MyOutVar

The Extract New Script feature handles multiple input and output variables. In fact, you can extract complex sections of code into new scripts with this method. Keep in mind, however, that you should try to make your scripts modular so that they can be reused in many different contexts.

Remember, the newly created script can be called by its name from other scripts in addition to the one from which it was extracted. For detailed information about calling other scripts, see Calling Scripts from Other Scripts above or the Running Other Scripts and Handlers page.

Handlers

To reuse code within the same script, you can also write a handler, which is essentially a subscript. A handler is a part of your main script that you can call anytime, as if you were calling another script.

Example: CaptureTheScreen handler

to CaptureTheScreen prefix, count // Starts the handler

set fileName to prefix & "ScreenShot" & count // Puts prefixScreenShotCount into fileName

set tempFile to "/tmp/" & fileName // Puts "/tmp/filename" into tempFile

CaptureScreen tempFile //Captures a screenshot

return fileName // Sets fileName as the function return value

end CaptureTheScreen //Ends the handler

Returning Results of a Handler

If a script or handler returns a value, like this one, you can access the value by calling the Results function in the next line. So, using the example above, you can call the handler and access the result as shown below.

Example: Returning results of a handler

CaptureTheScreen "MacTest", 6 // Calls the CaptureTheScreen handler

Set newFile to the result // Puts the returned value into a variable

Handlers as Commands or Functions

Because the CaptureTheScreen handler is a generic handler, it could also be called as a function. The major difference in use is that a command is a complete statement by itself, and may be used without regard for whether it returns a value, while a function must be called as part of an expression.

Example: Calling handlers as commands and functions

CaptureTheScreen "MacTest", 6 // Called as a command; runs the handler

put CaptureTheScreen ("MacTest",6) // Called as a function; returns the value of the handler. Note parentheses.

Calling a handler from another script

There are three ways to call a handler from another script:

  1. Call the script name with a possessive ‘s, followed by the name of the handler and its parameters.
  2. Call the script name, adding a dot and the name of the handler to it.
  3. Call the handler name, followed by the word of and the script name.

Example: Calling a handler from another script

run Logging's CaptureTheScreen "MacTest", 6 // Calls handler with script name and possessive 's

run Logging.CaptureTheScreen "MacTest", 6 // Calls handler in the form script.handler

run CaptureTheScreen of Logging "MacTest", 6 // Calls handler with handler "of" script

Helper Suites

You can make any of the scripts, images or handlers in a suite available for reuse to scripts in other suites by adding that suite as a "helper suite." An Eggplant Functional script searches for images and other scripts in its own suite first. If you add helper suites, it then searches those suites when it cannot find the specified image or script in its own suite.

To add a helper suite:

  1. Click the Settings button at the bottom of the Suites window.
  2. When the Settings tab opens, click Add at the bottom of the Helper Suites pane to add one or more helper suites. A file system browser dialog opens for you to navigate to and select the suites you want to specify as helper suites.

To create a new helper suite, you can use one of two methods.

  1. From the File menu, select New Helper Suite OR from the Helper Suites pane, click New.
  2. Name the new suite and choose where to save it.

    Helper suites addition panel

    Helper Suites Pane

Suite Location Pathing

Referencing the paths to different suites can be tricky, especially if you are using relative paths, or checking the suites and files in and out of source control. There are few different ways you can handle these paths. One option is to write your script to get the suite location and store it in a variable as shown in the following statements:

Example:

put SuiteInfo().path // Returns the path to suite containing this script

Example:

put the folder of me // Returns the full path to the Scripts folder containing this script

See Using a Relative Path for a Helper Suite to learn more.

Suite Global Properties

As an alternative to using helper suites, Eggplant Functional provides the following global properties to specify suites a script can search before or after it searches its own suite:

  • the InitialSuites global property allows you to specify a list containing the suite or suites a script should search before it searches its own suite.
  • the FinalSuites global propery allows you to specify a list containing the suite or suites a script can search after it searches its own suite.

Example:

set the InitialSuites to (DSD & "myFirstSuite.suite", DSD & "mySecondSuite.suite")

Example:

set the FinalSuites to (DSD & "mySuite.suite", DSD & "myOtherSuite.suite")

In the code above, DSD is a variable used to represent the Default Suite Directory. You would have to set the variable to the appropriate path for this directory (or to the location for your specific suites) before running these lines of code.

Helper Suites Organization in Eggplant Functional

The following video describes organizational features in Eggplant Functional, including those related specifically to helper suites.

Cross-Platform Applications

The articles in this section explain how you can build upon your current scripts to expand your testing to multiple operating systems.

Creating Platform- and Language-Specific Suites

At first, it might seem easy to create a whole new set of scripts for every platform you need to test, but keeping those scripts consistent as your application evolves can be a real challenge.

A friendlier long-term solution is to start with a base script, and call an outside script for each mechanic that changes between operating systems. You can write the script differently for each platform-specific suite, and then tell the script which suite to use for any given run.

Example: Quit scripts

In a Windows suite:

TypeText ControlKey & AltKey & "x"

in a Mac suite:

TypeText CommandKey & "q"

In this example, the script name Quit could be called as a command in your base script. Whether it runs the Windows version or the Mac version just depends on which suite you designate.

Designating the Correct Suite

The InitialSuites global property tells a script which suite (or suites) to check first when it is looking for script or image resources. (These suites even precede the suite in which the current script is running.) If you name more than one initial suite, remember that each suite’s helpers (and their helpers) are searched before the next "top level" suite.

In the example above, you could be sure that your base script would find the correct Quit script by setting the InitialSuites value to the appropriate suite.

Example: the InitialSuites

Set the InitialSuites to ("Windows") // Names the Windows suite as the first suite to check for resources

Quit // Runs the first Quit script found

Note: Like all global properties, the InitialSuites can be changed at any point during a script. (Initial refers to the initial suite that is searched, not the initial state of the script.)

Using Multilingual Text Images

Whenever an interface element can be identified by its text alone, you can use a generated Text Image rather than a captured image in your script. This can save a lot of time creating multiple language suites.

For example, suppose you have to click the same Open button in an application with English, French, and Spanish versions. You could always capture a separate image of the button for each language, but it would be faster to generate a single Text Image and adjust the text as needed.

Example: using language-specific Text Images

Click (text: "Open", textStyle: "Button")

Click (text: "Ouvrir", textStyle: "Button")

Click (text: "Abierto", textStyle: "Button")

One Step Further—Translation Scripts

You can use your language-specific suites even more efficiently by putting a translation script in each one, as shown below.

Example: Translate script

params EnglishWord// Takes an English word...

set translation to {Hello: "Bonjour",Open: "Ouvrir",Yes: "Oui"} // Sets the translation variable to a property list, in which each English key is assigned a French value

return translation's (EnglishWord) // Returns the French value of the English key that was passed in

Now, to generate a Text Image in your base script, you could set the Text value to be the returned value of the "Translate" script.

Example: Calling the translate script

Set the InitialSuites to ("French") // Ensures that the "Translate" script comes from the French suite

Click (text: Translate ("Hello")) // Runs the "Translate" script with "Hello" as the EnglishWord parameter. Uses the returned value of "Translate" as the Text value in this property list.

When you are using a translation script, don’t forget to create a version that works for your base language! Even though you don’t really need to have your own language translated back to you, your base scripts do need something to do when they encounter the Translate call. The base-to-base "Translate" script does not need to go through the motions of translating anything; just taking a parameter and returning the same parameter is enough.

Example: Translate script

params BaseWord// Takes a word...

return BaseWord// Returns the same word.

Testing Across Desktop and Mobile Devices

This example uses a single master script to call four sub-scripts that test against the Evernote application on an Android device, as well as through a browser on a desktop machine and through the desktop version of the application.

For complete information about using parameters, see Parameters and Results.

Main Script (EvernoteTest.script)

//This script makes a note in Evernote on an Android device and then checks that the note was processed and shows up in a web browser on a Windows 7 VM//

//Populate variables (could also be drawn from a data file or database)

Put "Bananas" into MyFruit

Put "Carrots" into MyVeggie

AddItemsFromAndroid MyFruit, MyVeggie --Call script to add items to a grocery list from an Android device

CheckItemsInBrowser MyFruit, MyVeggie --Call script to connect to a Win 7 VM and login to Evernote online to see if the items updated

CheckItemsInDesktopApp MyFruit, MyVeggie --Call script that uses the Evernote desktop application to verify the list items

ClearList MyFruit, MyVeggie --Clear the List for Next Test Run

First Called Script (AddItemsFromAndroid.script)

//This script goes into Evernote on Android and adds items to the grocery list

Params Fruit, Veggie

Log "Entering Items in List via Android"

Connect GalaxyS3 //Connect to the device

Tap "AppMenu" //Navigate to the Evernote app

Tap "Evernote" //Navigate to the list

Tap "NoteIcon"

Tap "GroceryList"//Edit the list and add the items

Tap "EditIcon"

WaitFor 30.0, "Check"

TypeText Fruit, return

TypeText Veggie, return

//Save the list and navigate back to the home page

Tap "Check"

Wait 1

Tap "ElephantIcon"

TypeText HomeKey //Navigates to the home page using the home button on the device

WaitFor 30.0, "ChromeIcon" //Verifies that the home page of the device is displayed

Second Called Script (CheckItemsInBrowser.script)

//This script connects to a Win 7 VM and verifies the list items in Evernote through a web browser

Params Fruit, Veggie

Log "Checking the list items in a browser"

Connect Win7Demo //Connect to Win 7 VM

//Navigate to Evernote.com

DoubleClick "GoogleChrome"

WaitFor 30.0, "GoogleMenuLogo"

TypeText "Evernote.com",return

//Log In and make sure grocery list is selected

Click "SignIn"

TypeText "<email address>"

TypeText TabKey

TypeText "<password>"

Click "SignInButton"

Click "GroceryList"

//Find the Date Created and Log it

Put ReadText ("CreatedTLDate","CreatedBRDate") into DateCreated

Log "This List was Created on: " & DateCreated

//Find the Date Last Modified and Log it

Put ReadText ("ModifiedTLDate","ModifiedBRDate") into DateModified

Log "This List was Last Modified on: " & DateModified

//Read the Contents of Grocery List

Put ReadText ("TLList","BRList") into ListContents

Log "The list contained: " & ListContents

//Check to see if Fruit was properly synced

If ListContents contains Fruit

then

log "The list contained " & Fruit

else

logWarning "The item " & Fruit & " was not displayed"

end if

//Check to see if Veggie was properly synced

If ListContents contains Veggie

then

log "The list contained " & Veggie

else

logWarning "The item " & Veggie & " was not displayed"

end if

//Close out of Browser

Click "CloseButton"

Third Called Script (CheckItemsInDesktopApp.script)

//This script connects to a Win 7 VM and verifies the list items in the Evernote desktop application//

Params Fruit, Veggie

//Declares parameters. For an example on passing parameters, please see "Passing Parameters and Calling Functions"

Log "Checking the list items in the Evernote desktop application"

Connect Win7Demo //Connect to Win 7 VM

//Open Evernote desktop application and make sure Grocery List is selected

DoubleClick "EvernoteDesktopApp"

If not imagefound (30.0, "GroceryListSelected")

then

Click "GroceryList"

Click foundImageLocation()

end if

//Sync the list to update any modifications

Click "ToolsMenu"

Click "Sync"

Wait 5

Put ReadText ("CreatedTLDate","CreatedBRDate") into AppDateModified

Log "This List was Created on: " & AppDateModified

//Find the Date Created and Log it

Put ReadText ("CreatedTLDate","CreatedBRDate") into AppDateCreated

Log "This List was Created on: " & AppDateCreated

//Find the Date Last Modified and Log it

Put ReadText ("ModifiedTLDate","ModifiedBRDate") into AppDateModified

Log "This List was Last Modified on: " & AppDateModified

//Read the Contents of Grocery List

Put ReadText ("TLList","BRList") into AppListContents

Log "The list contained: " & AppListContents

//Check to see if Fruit was properly synced

If AppListContents contains Fruit

then

log "The list contained " & Fruit

else

logWarning "The item " & Fruit & " was not displayed"

end if

//Check to see if Veggie was properly synced

If AppListContents contains Veggie

then

log "The list contained " & Veggie

else

logWarning "The item " & Veggie & " was not displayed"

end if

//Close out of Browser

Click "CloseButton"

Last Called Script: Cleanup Script (ClearList.script)

//This script accesses Evernote via Android and clears the contents

Params Fruit, Veggie //Declares parameters

Log "Clearing the list on the Android device"

Connect GalaxyS3 //Connect to the device

//Navigate to the Evernote app

Tap "AppMenu"

Tap "EverNote"

//Navigate to the list and go into edit mode

Tap "NoteIcon"

Tap "GroceryList"

Tap "EditIcon"

WaitFor 30.0, "Check"

//Delete Item 1

TypeText ShiftKey, DownArrow

Click "DeleteButton"

//Delete Item 2

TypeText ShiftKey, DownArrow

Click "DeleteButton"

//Save the list and navigate back to the home page

Tap "Check"

Wait 1

Tap "ElephantIcon"

TypeText HomeKey

WaitFor 30.0, "ChromeIcon"

Running from a Master Script

The Schedules pane of the Suite Window has a convenient graphical interface for organizing and running batches of scripts; however, when you need to run scripts more dynamically, you have to write a master script.

The most powerful feature of a master script is the RunWithNewResults command, with which you can build upon returned script results to generate the future schedule.

RunWithNewResults works by taking another script as a parameter. The parameter script generates its own results, and returns them to the master script. The benefit of this is that you can schedule script runs conditionally, based on the return values of previous executions. You can run any number of scripts through a master script, and manage the results as well.

The following example script highlights the functionality of master scripts. First, it runs an initial test. If that test fails, it sends an email warning to a system administrator; otherwise it proceeds to execute a series of tests, storing the results in a text string that it logs at the end.

Example: Master Script

set TestList to ("Test1", "Test2", "Test3") // Creates a series of script executions.

 

RunWithNewResults "InitialTest"

 

set Outcome to the result

 

if the status of Outcome is not "Success" then

 

// If the result of "InitialTest" is not "Success", gets the date and time of the run...

 

convert Outcome's runDate to date and long time

 

sendMail (to: "administrator@yourcompany.com", from: "JoeTester@yourcompany.com", subject: "Initial Test Failed", body: "Test run at" && rundate of Outcome && "had" && errors of Outcome && "errors")

 

// Sends email to report the date and errors of the execution. (&& joins text strings with a space between them.)

 

else

 

// Otherwise...

 

repeat with each testScript of TestList

 

// For every script in TestList,

 

RunWithNewResults testScript // Runs the script, then...

 

set Outcome to the result // puts the results into Outcome

 

put testScript & ":" && status of Outcome && Return after currentReport

 

// Adds "Script: Status", then a return character to currentReport

 

if the status of Outcome is "Failure" then

 

// If the status property is Failure...

 

run "CleanupScript" // runs CleanupScript

 

end if

 

end repeat // Ends after the final test in TestList

 

Log "Final Results" // Logs "Final Results"

 

repeat with each line of currentReport

 

log it // Logs each line in currentReport

 

end repeat

 

end if

 

This topic was last updated on June 21, 2019, at 02:49:49 PM.

Eggplant icon Eggplantsoftware.com | Documentation Home | User Forums | Support | Copyright © 2019 Eggplant