Test action types


Overview

Test actions represent atomic pieces of logic which execute a single test step (e.g. click a web UI element or make an HTTP request to execute an API call). In the test automation literature test actions are typically referred to as "keywords" and the corresponding test practice is called "keyword-driven" testing. Test actions execute sequentially, in the order they were specified in the test definition. Each test action can take 0 or more input arguments and may produce one or more output values that can be used in subsequent actions.

OpenTest defines three types of test actions: regular actions, script actions and macro actions.

Regular actions

Most regular test actions you’ll need to use are provided as part of the core OpenTest package, but new actions can be added with custom plugins. Regular test actions are implemented as Java classes that inherit from the TestAction base class.

To call a regular test action, use the following syntax:

- description: This is a sample test action call
  action: org.getopentest.actions.SampleAction
  args:
    argument1: value1
    argument2: value2

The three properties of a regular test action are:

  • description (optional): A human-readable description of what the action is looking to accomplish in the context of your particular test. The action description is used in logs and test execution reports, so providing a clear and accurate description makes it a lot easier to understand the execution flow and troubleshoot failed tests.

  • action: This is the fully qualified name of the Java class that implements the test action logic (package name and class name, separated by a dot). For example, to run the Click action from the org.getopentest.selenium package, you would use org.getopentest.selenium.Click.

  • args (optional): The arguments passed to the test action. While some test actions are simple enough and need no arguments (e.g. the Selenium SwitchToLastWindow action), most test actions require additional information in order to execute successfully, like the locator of a web UI element to click on, or the text to type in a textbox. Arguments can be simple data types like strings or numbers, but can also be complex types, like collections of name-value pairs (hash maps).

Script actions

JavaScript code can be inserted anywhere in the test flow by using script actions. Just like the other test action types, script actions can also provide a description property that explains what the action does. The JavaScript code to execute must be provided as a string value in the script property of the test action. Here’s a script action that delays execution for 2 seconds using the $delay function exposed by OpenTest:

- description: Delay execution for two seconds
  script: $delay(2000)

For non-trivial scripts, the YAML multiline syntax can be used to organize the script neatly over multiple lines. In YAML, multiline strings can be represented using the "|" (pipe) character:

- description: Click buttons with IDs "button1" to "button100"
  script: |
    for (var buttonNo = 1; buttonNo <= 100; buttonNo++) {
        $runAction("org.getopentest.selenium.Click", {
            locator: { id: "button" + buttonNo }
        });
    }

Macro actions

A macro action may contain any sequence of test actions (both regular and script actions, as well as other macro actions) that is stored in a separate file and can be called from multiple tests or from multiple places in the same test. The main purpose of macro actions is roughly the same as the purpose of using subroutines in most programming languages: they help avoid code duplication and increase readability. For example, most applications require the user to log in before executing the work that is specific to a particular test case. The proper way to perform the user authentication would be to create a macro action called "Login" and then call that macro at the beginning of each test that requires authentication, using this syntax:

- macro: Login

To create the Login macro, add a new file named Login.yaml in the macros subdirectory of your test repo, with the following content:

test-repo-path/macros/Login.yaml
description: Perform the steps necessary to authenticate a user
actions:
  - description: Call the authentication API
    action: org.getopentest.actions.HttpRequest
    args:
      url: https://some.url.here/authenticate?user=john&password=mypasswd
      verb: GET


  # ... perform other necessary actions here

Like all test actions, macros can take arguments and can produce output values. To pass arguments to a macro action, use the same syntax as for a regular action:

- macro: Login
  args:
    username: john_doe
    password: sk67E8qL

To read the arguments that a macro was called with, you can use the $macroArgs JavaScript function (more details in the JavaScript API reference). In order to write an output value from a macro action, you can use the $macroOutput function. Let’s assume we have an HTTP API that we must call to authenticate to a web service, which returns this JSON data: {"authToken": "kf74F43KL9gSd9dP"}. The sample code below is a macro that makes use of the username and password arguments and create an output value named authToken, containing the authetication token returned by the HTTP API. The code also makes use of some other features like the local data store, the $output and the $format APIs, which are documented separately, so don’t worry if you don’t understand all the code in the snippet at this point.

test-repo-path/macros/Login.yaml
description: Authenticate the user
actions:
  - script: |
      // Build the authentication URL and store it in a variable
      var authenticationUrl = $format(
        "https://some.url.here/authenticate?user={0}&password={1}",
        $macroArgs.username,
        $macroArgs.password)

  - description: Call the authentication API
    action: org.getopentest.actions.HttpRequest
    args:
      url: authenticationUrl
      verb: GET
      $localData:
        authToken: $output.body.authToken

  - script: $macroOutput.authToken = $localData.authToken;

Once we have this macro, we can call it in all the tests that require authentication with the following syntax:

- macro: Login
  args:
    username: john_doe
    password: sk67E8qL
    $localData:
        authToken: $output.authToken

- script: $log("The authentication token is " + $localData.authToken)

Writing macros usually requires slightly more advanced skills and an above-average understanding of the system under test, so it’s recommended that they are implemented by the more experienced members of a team. Building a solid, properly designed set of macros can significantly speed up test development, makes the test suite easier to maintain and has a big impact on the long-term success of the test automation effort.