Robot Framework User Guide

Version 2.6.3

Copyright © Nokia Siemens Networks 2008-2011

Table of Contents

1   Getting started

1.1   Introduction

Robot Framework is a Python-based, extensible keyword-driven test automation framework for end-to-end acceptance testing and acceptance-test-driven development (ATDD). It can be used for testing distributed, heterogeneous applications, where verification requires touching several technologies and interfaces.

1.1.1   Why Robot Framework?

  • Enables easy-to-use tabular syntax for creating test cases in a uniform way.
  • Provides ability to create reusable higher-level keywords from the existing keywords.
  • Provides easy-to-read result reports and logs in HTML format.
  • Is platform and application independent.
  • Provides a simple library API for creating customized test libraries which can be implemented natively with either Python or Java.
  • Provides a command line interface and XML based output files for integration into existing build infrastructure (continuous integration systems).
  • Provides support for Selenium for web testing, Java GUI testing, running processes, Telnet, SSH, and so on.
  • Supports creating data-driven test cases.
  • Has built-in support for variables, practical particularly for testing in different environments.
  • Provides tagging to categorize and select test cases to be executed.
  • Enables easy integration with source control: test suites are just files and directories that can be versioned with the production code.
  • Provides test-case and test-suite -level setup and teardown.
  • The modular architecture supports creating tests even for applications with several diverse interfaces.

1.1.2   High-level architecture

Robot Framework is a generic, application and technology independent framework. It has a highly modular architecture illustrated in the diagram below.

src/GettingStarted/architecture.png

Robot Framework architecture

The test data is in simple, easy-to-edit tabular format. When Robot Framework is started, it processes the test data, executes test cases and generates logs and reports. The core framework does not know anything about the target under test, and the interaction with it is handled by test libraries. Libraries can either use application interfaces directly or use lower level test tools as drivers.

1.1.3   Screenshots

Following screenshots show examples of the test data and created reports and logs.

src/GettingStarted/testdata_screenshots.png

Test case files

src/GettingStarted/screenshots.png

Reports and logs

1.1.4   Getting more information

Project pages

The number one place to find more information about Robot Framework is the project web site at http://robotframework.org. This User Guide is naturally available there but you can also find more documentation, an issue tracker, downloads, source code and links to other related projects. Robot Framework is hosted on Google Code which provides excellent free services for open source projects.

Mailing lists

There are several Robot Framework mailing lists where to ask and search for more information. The mailing list archives are open for everyone (including the search engines) and everyone can also join these lists freely. Only list members can send mails, though, and to prevent spam new users are moderated which means that it might take a little time before your first message goes through. Do not be afraid to send question to mailing lists but remember How To Ask Questions The Smart Way.

robotframework-users
General discussion about all Robot Framework related issues. Questions and problems can be sent to this list. Used also for information sharing for all users.
robotframework-announce
An announcements-only mailing list where only moderators can send messages. All announcements are sent also to the robotframework-users mailing list so there is no need to join both lists.
robotframework-devel
Discussion about Robot Framework development.
robotframework-commit
Automatically generated mails about commits to the version control system, build results, new and edited issues, and so on. Can be used to follow Robot Framework development.

1.3   Installation and uninstallation

1.3.1   Introduction

There are several ways to install Robot Framework:

Installing from source
You can get the source code either as a source distribution package or directly from version control system. In the former case, first extract the package somewhere, and as a result, you have a directory named robotframework-<version>. Detailed instructions follow, but in short, what you need to do is to go to the created directory and run the python setup.py install command.
Using Windows installer
There is a special graphical installer for Windows operating system.
Using Easy Install
If Python package managing tool Easy Install is available, installing Robot Framework is as easy as running command easy_install robotframework.
Using One Click Installer
If you are using Windows XP and you do not have preconditions (Python and optional Jython) installed, you can use One Click Installer to do all the needed installations.
Standalone jar distribution
If you need to run tests with only Jython, the easiest way to install everything is to downloading the standalone robotframework-<version>.jar, which contains both Jython and Robot Framework.

Installation packages are available from http://downloads.robotframework.org, and source code from http://source.robotframework.org.

Note

At the momemt it is not possible to install Robot Framework using pip. For more information see issue 885.

1.3.2   Preconditions

Robot Framework runs both on Python and Jython, and you need to have at least one of them to be able to use it. However, some of the provided installers only work with Python, so installing it is always recommended.

Python installation

Starting from Robot Framework 2.5, Python 2.5 is the minimum supported Python version. Earlier versions support Python 2.3 or newer. On most UNIX-like systems, you have Python installed by default. If you are on Windows or otherwise need to install Python yourself, your best place to start is probably the Python homepage. There you can download a suitable installer and get more information about the installation and Python in general.

Note

Robot Framework is currently not compatible with Python 3.x versions. Python 3.0 was intentionally backwards incompatible with earlier Python releases and Robot Framework has not yet been ported to support it.

Note

On Windows, and especially on Windows Vista, it is recommended to install Python to all users, and to run the installation as an administrator.

Jython installation

Using test libraries implemented with Java or using Java tools directly requires running Robot Framework on Jython, which in turn requires Java Runtime Environment (JRE). Jython 2.5 requires Java 1.5 or newer. Both Oracle/Sun and IBM Java implementations are supported.

Starting from Robot Framework 2.5, the minimum supported Jython version is 2.5. Earlier Robot Framework versions support also Jython 2.2.

Installing Jython is a fairly easy procedure, and the first step is getting an installer from the Jython homepage. Note that the installer is an executable JAR package, which you need to run as java -jar jython_installer-<version>.jar. Depending on your system, the installer runs either in graphical or textual mode, but in both cases, the actual installation procedure is very easy.

There are three ways to install Robot Framework so that it can be run with Jython.

  1. With all supported Jython versions, it is possible to install Robot Framework using Python and still start execution using Jython. When installing Robot Framework with Python, its installer tries to find the Jython executable on the system to create the jybot runner script correctly. Jython is found if:

    • Jython can be executed in the system directly (i.e. it is in the PATH).

    • An environment variable JYTHON_HOME is set and it points to the Jython installation directory.

    • The installer finds the Jython installation directory from the system. On Windows, it is searched from the C:\ and D:\ drives, and on other systems from the /usr/local and /opt directories. The directory is found if it is under the searched directories mentioned above, or one level deeper. For example, the following Jython installation directories would be found by the installer:

      C:\APPS\Jython2.5.1
      D:\Jython251
      /usr/local/jython2.5.1
      /opt/whatever/Jython251
      
  2. With Jython 2.5, it is possible to install Robot Framework without having Python available by installing from source.

  3. It is possible to do manual installation.

1.3.3   Installation

Installing from source

You can get Robot Framework source code either directly from version control or as a source distribution package that needs to be extracted somewhere. In both cases, you should have a directory containing the source code, documentation, tools, templates, and so on.

You should be able to install Robot Framework to any environment where Python runs using a source distribution. The installation is done by running the following command from the command line in the extracted directory:

python setup.py install

setup.py is a standard Python installer script. It can take several parameters allowing, for example, installation into non-default locations not requiring administrative rights. It is also used for creating distribution packages.

install.py is a custom uninstallation script for Robot Framework. It can also be used for installation, but it simply uses setup.py, and thus is totally equivalent to the command above.

It is possible to install Robot Framework 2.5 also using Jython. In this case the pybot runner script is not created.

With the installation you get a rather long output, and something like the following text should appear at the end. The actual output obviously depends on your environment.

Creating Robot Framework runner scripts...
Installation directory: /usr/lib/python2.5/site-packages/robot
Python executable: /usr/bin/python
Jython executable: /cygdrive/c/jython2.5/jython.bat (found from system)
Pybot script: /usr/bin/pybot
Jybot script: /usr/bin/jybot
Rebot script: /usr/bin/rebot

Using Windows installer

There are separate graphical installers for 32 bit (more common) and 64 bit Windows systems. The former installer has name in format robotframework-<version>.win32.exe and the latter robotframework-<version>.win-amd64.exe. The installation itself requires only double clicking the appropriate installer and following instructions.

After the installation you probably want to set the environment so that Robot Framework runner scripts can be executed easily. Notice that the framework is automatically installed under the Python installation and that location cannot be altered at this point.

Note

With Python 2.6 and 2.7 you need to add the Python installation directory into PATH environment variable before running the Robot Framework installer. Setting up environment section has more information about setting environment variables.

Note

On Windows Vista and Windows 7 installing Robot Framework requires administrator privileges. Select Run as administrator from the context menu when starting the installer.

Using Easy Install

An obvious precondition for using Easy Install is to have it installed, and you can refer to its documentation on how to do that on your operating system. The command to install Robot Framework with Easy Install depends on whether you want to install the latest version or some specific version:

easy_install robotframework         # latest version
easy_install robotframework==2.1.3  # specified version

Tip

If you need to use a proxy to access the Internet, you can tell Easy Install to use it by setting the http_proxy environment variable.

Note

Easy Install has a "feature" that unless a specific version is given, it installs the latest possible version even if that is an alpha or beta release. For example, if there is 2.6 beta 1 available, running easy_install robotframework will install it and not the latest stable version. A workaround is giving the version explicitly like in easy_install robotframework==2.5.7.

On Windows the pybot, jybot and rebot runner scripts are not updated when using Easy Install. A workaround is running robot_postinstall.py script manually afterwards. The installation output tells where the post-install script is located, and you can either double click it or run it from the command line. Path to the script depends on your Python installation, but the command to run should be something like python C:\Python25\Scripts\robot_postinstall.py.

Updating the runner scripts is slightly fragile process in general and it may not work with Easy Install on all environments. If the runner scripts do not work after installation, they need to fixed manually.

Using One Click Installer

The One Click Installer installs Robot Framework and its preconditions Python and Jython (optional). It also automatically sets up environment so that Robot Framework runner scripts, as well as Python and Jython executables are in PATH.

Note

The One Click Installer works only on Windows XP (32 bit).

The One Click Installer requires that you have downloaded all the required component installers and have them in the same directory with it. More detailed instructions and details about the supported installers are available at One Click Installer's documentation.

Note

You should use this installer ONLY if you do not previously have Python or Jython installed. In that case, and also if you want to have a custom installation, you need to install the needed components separately.

Manual installation

If you do not want to install Python, or for some other reason do not want to use any automatic way of installing Robot Framework, you can always do it manually following these steps:

  1. Get the source code. All the code is in a directory (a module in Python) called robot. If you have a source distribution or a version control checkout, you can find it from the src directory, but you can also get it from an earlier installation.
  2. Copy the source code where you want to.
  3. Create the needed runner scripts. If you have a source package or a checkout, you can get templates from src/bin directory.

Standalone jar distribution

Starting from Robot Framework 2.5.2, it is also distributed as a standalone robotframework-<version>.jar, which contains both Jython and Robot Framework. It is an easy way to get everything if you do not need to run tests with Python. After you have downloaded the jar file, you can execute it like:

java -jar robotframework-2.5.2.jar --help
java -jar robotframework-2.5.2.jar mytests.txt
java -jar robotframework-2.5.2.jar --variable name:value mytests.txt

If you need to post-process outputs, rebot must be given as the first argument to the jar file:

java -jar robotframework-2.5.2.jar rebot --help
java -jar robotframework-2.5.2.jar rebot output.xml
java -jar robotframework-2.5.2.jar rebot --name Combined outputs/*.xml

Where files are installed

When an automatic installer is used, the Robot Framework code is copied into a directory containing external Python modules. The actual location is platform-specific, but on computers with a UNIX-like operating system, it is normally something like /usr/lib/[PythonVer]/site-packages, and on Windows it is [PythonInstallationDir]\Lib\site-packages. The actual Robot Framework code is in a directory named robot, or when using Easy Install in directory robotframework[RobotVer].py[PythonVer].egg/robot.

Robot Framework runner scripts (pybot, jybot and rebot) are created and copied into another platform-specific location. On UNIX-like systems, they normally go to /usr/bin and are thus immediately available from the command line. On Windows, the operating system does not provide a similar natural place, and Python copies these scripts into [PythonInstallationDir]\Scripts.

Setting up environment

After the installation, you probably want to make Robot Framework's runner scripts easily available from the command line. On UNIX-like systems, that should be the case automatically, but for example on Windows, it is not. In environments where runners are not available, the directory containing them must be set to the PATH environment variable.

Setting the PATH environment variable on Windows:

  1. Open Start > Settings > Control Panel > System > Advanced > Environment Variables. There are User variables and System variables, and the difference between them is that User variables affect only the current users, whereas System variables affect all users.
  2. To edit the existing PATH, select Edit and add ;[PythonInstallationDir]\Scripts\ at the end of the value. Note that the leading colon (;) is important, as it separates different entries. To add a new value, select New and provide both the name and the value, this time without the colon.
  3. Start a new command prompt for the changes to take effect.

Python installer on Windows does not create [PythonInstallationDir]\Scripts directory, but it is automatically created during Robot Framework installation.

Note

Environment variable PYTHONCASEOK should not be set on Windows machines. Robot Framework will not work correctly with this environment variable.

Verifying installation

To verify that the installation and environment setup were successful, type:

$ pybot --version
Robot Framework 2.5 (Python 2.6.5 on darwin)

To verify that Robot Framework works also with Jython, type:

$ jybot --version
Robot Framework 2.5 (Jython 2.5.1 on java1.6.0_07)

In both cases, the exact version and platform information can, of course, differ from these. On Jython, you may also get some notifications from Jython package manager upon the first execution.

1.3.4   Uninstallation

If Robot Framework has been installed using a source distribution, it can be uninstalled with command:

python install.py uninstall

If Robot Framework is installed from a binary distribution, it can be uninstalled via the mechanism offered by the operating system. For example, in Windows you simply go to Control Panel > Add/Remove Programs, where Robot Framework is listed under Python.

If uninstallation fails somehow or you have used Easy Install, Robot Framework can be uninstalled by removing the framework code and runner scripts manually.

1.3.5   Upgrading

The procedure when upgrading or downgrading Robot Framework depends on the versions used:

  • If you are upgrading from one minor Robot Framework version to another (for example, from 2.5 to 2.5.1), it is safe to install the new version over the old one, unless stated otherwise.
  • If you are upgrading from one major Robot Framework version to another (for example, from 2.1.3 to 2.5), then it is highly recommended to uninstall the old version before the new installation.
  • If you are downgrading, the rules are the same as for upgrading.

With source distributions, you first need to get the new package, and after that run the following command, which automatically takes care of the uninstallation:

python install.py reinstall

If you are using Easy Install, it is enough to run:

easy_install robotframework==<new-version>

Regardless on the version or installation method, you do not need to reinstall preconditions or set the PATH environment variable again.

1.4   Demonstrations

Robot Framework Quick Start Guide acts also as a standalone demo. It is part of the source distribution (under doc/quickstart/ directory), and also available as a separate download from project web pages.

Additionally, both external SeleniumLibrary and SwingLibrary have easily executable demos available. The former contains a simple standalone HTTP server and an application that is used as a system under test, and the latter has a small Swing application. The actual test case files and scripts for running demos on different systems are also provided.

2   Creating test data

2.1   Test data syntax

This section covers Robot Framework's overall test data syntax. The following sections will explain how to actually create test cases, test suites and so on.

2.1.1   Files and directories

The hierarchical structure for arranging test cases is built as follows:

  • Test cases are created in test case files.
  • A test case file automatically creates a test suite containing the test cases in that file.
  • A directory containing test case files forms a higher-level test suite. Such a test suite directory has suites created from test case files as its sub test suites.
  • A test suite directory can also contain other test suite directories, and this hierarchical structure can be as deeply nested as needed.
  • Test suite directories can have a special initialization file.

In addition to this, there are:

2.1.2   Supported file formats

Robot Framework test data is defined in tabular format, using either the hypertext markup language (HTML), tab-separated values (TSV), plain text, or reStructuredText (reST) formats. Robot Framework selects a parser for the test data based on the file extension. The extension is case-insensitive, and the recognized extensions are .html, .htm and .xhtml for HTML, .tsv for TSV, .txt for plain text, and .rst or .rest for reStructuredText.

Different test data templates are available for HTML and TSV formats to make it easier to get started writing tests.

HTML format

In HTML files, the test data is defined in separate tables (see the example below). Robot Framework recognizes these test data tables based on the text in their first cell. Everything outside recognized tables is ignored.

Using the HTML format
Setting Value Value Value
Library OperatingSystem    
     
Variable Value Value Value
${MESSAGE} Hello, world!    
     
Test Case Action Argument Argument
My Test [Documentation] Example test  
Log ${MESSAGE}  
My Keyword /tmp  
     
Another Test Should Be Equal ${MESSAGE} Hello, world!
Keyword Action Argument Argument
My Keyword [Arguments] ${path}  
Directory Should Exist ${path}  
Editing test data

Test data in HTML files can be edited with whichever editor you prefer, but a graphic editor, where you can actually see the tables, is recommended. There is also a tool called RIDE available that is designed for editing the test data.

Encoding and entity references

HTML entity references (for example, &auml;) are supported. Additionally, any encoding can be used, assuming that it is specified in the data file. Normal HTML files must use the META element as in the example below:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

XHTML files should use the XML preamble as in this example:

<?xml version="1.0" encoding="Big5"?>

If no encoding is specified, Robot Framework uses ISO-8859-1 by default.

TSV format

The TSV format can be used in Robot Framework's test data for all the same purposes as HTML. In a TSV file, all the data is in one large table. Test data tables are recognized from one or more asterisks (*), followed by a normal table name and an optional closing asterisks. Everything before the first recognized table is ignored similarly as data outside tables in HTML data.

Using the TSV format
*Setting* *Value* *Value* *Value*
Library OperatingSystem    
     
     
*Variable* *Value* *Value* *Value*
${MESSAGE} Hello, world!    
     
     
*Test Case* *Action* *Argument* *Argument*
My Test [Documentation] Example test  
Log ${MESSAGE}  
My Keyword /tmp  
     
Another Test Should Be Equal ${MESSAGE} Hello, world!
     
     
*Keyword* *Action* *Argument* *Argument*
My Keyword [Arguments] ${path}  
Directory Should Exist ${path}  
Editing test data

You can create and edit TSV files in any spreadsheet program, such as Microsoft Excel. Select the tab-separated format when you save the file and remember to set the file extension to .tsv. It is also a good idea to turn all automatic corrections off and configure the tool to treat all values in the file as plain text.

TSV files are relatively easy to edit with any text editor, especially if the editor supports visually separating tabs from spaces. The TSV format is also supported by RIDE.

Robot Framework parses TSV data by first splitting all the content into rows and then rows into cells on the basis of the tabular characters. Spreadsheet programs sometimes surround cells with quotes (for example, "my value") and Robot Framework removes them. Possible quotes inside the data are doubled (for example, "my ""quoted"" value") and also this is handled correctly. If you are using a spreadsheet program to create TSV data, you should not need to pay attention to this, but if you create data programmatically, you have to follow the same quoting conventions as spreadsheets.

Encoding

TSV files are always expected to use UTF-8 encoding. Because ASCII is a subset of UTF-8, plain ASCII is naturally supported too.

Plain text format

The plain text format is technically otherwise similar to the TSV format but the separator between the cells is different. The TSV format uses tabs, but in the plain text format you can use either two or more spaces or a pipe character surrounded with spaces ( | ).

The test data tables must have one or more asterisk before their names similarly as in the TSV format. Otherwise asterisks and possible spaces in the table header are ignored so, for example, *** Settings *** and *Settings work the same way. Also similarly as in the TSV format, everything before the first table is ignored.

In plain text files tabs are automatically converted to two spaces. This allows using a single tab as a separator similarly as in the TSV format. Notice, however, that in the plain text format multiple tabs are considered to be a single separator whereas in the TSV format every tab would be a separator.

Space separated format

The number of spaces used as separator can vary, as long as there are at least two spaces, and it is thus possible to align the data nicely. This is a clear benefit over editing the TSV format in a text editor because with TSV the alignment cannot be controlled.

*** Settings ***
Library     OperatingSystem

*** Variables ***
${MESSAGE}  Hello, world!

*** Test Cases ***
My Test  [Documentation]  Example test
    Log         ${MESSAGE}
    My Keyword  /tmp

Another Test
    Should Be Equal  ${MESSAGE}  Hello, world!

*** Keywords ***
My Keyword  [Arguments]  ${path}
    Directory Should Exist  ${path}

Because space is used as separator, all empty cells must be escaped with ${EMPTY} variable or a single backslash. Otherwise handling whitespace is not different than in other test data because leading, trailing, and consecutive spaces must always be escaped.

Pipe and space separated format

The biggest problem of the space delimited format is that visually separating keywords form arguments can be tricky. This is a problem especially if keywords take a lot of arguments and/or arguments contain spaces. In such cases the pipe and space delimited variant can work better because it makes the cell boundary more visible.

| *Setting*  |     *Value*     |
| Library    | OperatingSystem |

| *Variable* |     *Value*     |
| ${MESSAGE} | Hello, world!   |

| *Test Case*  | *Action*        | *Argument*   |
| My Test      | [Documentation] | Example test |
|              | Log             | ${MESSAGE}   |
|              | My Keyword      | /tmp         |
| Another Test | Should Be Equal | ${MESSAGE}   | Hello, world!

| *Keyword*  |
| My Keyword | [Arguments] | ${path}
|            | Directory Should Exist | ${path}

A plain text file can contain test data in both space-only and space-and-pipe separated formats, but a single line must always use the same separator. Pipe and space separated lines are recognized by the mandatory leading pipe, but the pipe at the end of the line is optional. There must always be at least one space on both sides of the pipe (except at the beginning and end) but there is no need to align the pipes other than if it makes the data more clear.

There is no need to escape empty cells (other than the trailing empty cells) when using the pipe and space separated format. The only thing to take into account is that possible pipes surrounded by spaces in the actual test data must be escaped with a backslash:

| ${file count} = | Execute Command | ls -1 *.txt \| wc -l |
| Should Be Equal | ${file count}   | 42                   |
Editing and encoding

One of the biggest benefit of the plain text format over HTML and TSV is that editing it using normal text editors is very easy. For Emacs there is even a special robot-mode.el that provides syntax highlighting and keyword completion. The plain text format is also supported by RIDE, although it only supports the space separated variant.

Similarly as with the TSV test data, plain text files are always expected to use UTF-8 encoding. As a consequence also ASCII files are supported.

reStructuredText format

reStructuredText (reST) is a easy-to-read plain text markup syntax that is commonly used for documentation of Python projects (including Python itself, as well as this user guide). Using reST with Robot Framework allows you to mix richly formatted documents and tables that specify test data in a concise text format that is easy to work with using simple text editors, diff tools, and source control systems.

Tools to process reStructuredText are freely available as part of the docutils project, and there is a quick reference guide that shows the most common formatting constructs including the tables used by Robot Framework. Notice that Robot Framework converts test data in reST format internally to HTML before starting to actually parse it. The data must thus follow reST syntax strictly or otherwise processing it will not succeed.

Note

Using reST files with Robot Framework requires the Python docutils module to be installed.

In reST files, test data is defined in tables within the document, similar to the HTML format. Robot Framework identifies test data tables based on the text in the first cell and all content outside of the recognized table types is ignored.

An example of each of the four test data tables is shown below using the reST Simple Tables syntax. Note that \ or .. must be used to indicate an empty cell in the first column of the table:

============  ================  =======  =======
  Setting          Value         Value    Value
============  ================  =======  =======
Library       OperatingSystem
============  ================  =======  =======


============  ================  =======  =======
  Variable         Value         Value    Value
============  ================  =======  =======
${MESSAGE}    Hello, world!
============  ================  =======  =======


============  ===================  ============  =============
 Test Case          Action           Argument      Argument
============  ===================  ============  =============
My Test       [Documentation]      Example test
\             Log                  ${MESSAGE}
\             My Keyword           /tmp
\
Another Test  Should Be Equal      ${MESSAGE}    Hello, world!
============  ===================  ============  =============


============  ======================  ============  ==========
 Keyword            Action             Argument     Argument
============  ======================  ============  ==========
My Keyword    [Arguments]             ${path}
\             Directory Should Exist  ${path}
============  ======================  ============  ==========
Editing test data

Test data in reST files can be edited with any text editor. It is recommended that the editor be configured to use a monospace font to aid with alignment of table elements.

Note that RIDE does not support direct editing of test data in reST source files.

Temporary files when using reST

Unlike HTML or TSV formats, Robot Framework does not parse reST files directly. Instead, docutils is used to automatically transform reST source files into temporary HTML files that are subsequently read by Robot. These temporary files are removed immediately after being read. This HTML file generation and cleanup is handled internally by Robot Framework, it does not require the user to directly invoke docutils tools.

Syntax errors in reST source files

If reST file is not syntactically correct (a malformed table for example), the reST-to-HTML conversion will not take place and no test cases will be read from that file. When this occurs, Robot Framework will show the docutils error message in its console output showing the filename, line number, source context, and type of error.

2.1.3   Test data tables

Test data is structured in four types of tables listed below. These test data tables are identified by the first cell of the table, and the last column in the table below lists different aliases that can be used as a table name.

Different test data tables
Table name Used for Aliases
Setting table
2) Defining metadata for test suites and test cases
Setting, Settings, Metadata
Variable table Defining variables that can be used elsewhere in the test data Variable, Variables
Test case table Creating test cases from available keywords Test Case, Test Cases
Keyword table Creating user keywords from existing lower-level keywords Keyword, Keywords, User Keyword, User Keywords

2.1.4   Rules for parsing the data

Ignored data

When Robot Framework parses the test data, it ignores:

  • All tables that do not start with a recognized table name in the first cell.
  • Everything else on the first row of a table apart from the first cell.
  • Data outside tables in HTML/reST and data before the first table in TSV.
  • All empty rows, which means these kinds of rows can be used to make the tables more readable.
  • All empty cells at the end of rows; you must add a backslash (\) to prevent such cells from being ignored.
  • All single backslashes (\); they are used as an escape character.
  • All characters following a hash mark (#), if it is the first character of a cell; this means that hash marks can be used to enter comments in the test data.
  • All formatting in the HTML/reST test data.

When Robot Framework ignores some data, this data is not available in any resulting reports and, additionally, most tools used with Robot Framework also ignore them. To add information that is visible in Robot Framework outputs, or available to, for example, RIDE, place it to the documentation or other metadata of test cases or suites, or log with the Log or Comment keywords available from the BuiltIn library.

Escaping

The escape character for the Robot Framework parser is the backslash (\). The escape character can be used as follows:

  • To escape special characters so that their literal values are used:
    • \${notvar} means a literal string ${notvar} that looks like a variable
    • \\ means a single backslash (for example, C:\\Temp)
    • \# means a literal hash (#) mark, even at the beginning of a cell
  • To affect the parsing of whitespaces.
  • To prevent ignoring empty cells at the end of a row (this requires \ to be in the appropriate cell). Another possibility is using built-in variable ${EMPTY}.
  • To escape indented cells in for loops when using the plain text format.

Note

These escaping rules are applied only to arguments to keywords and values to settings. They are not used, for example, with keyword and test case names.

Handling whitespace

Robot Framework handles whitespace, such as spaces, newlines and tabs, the same way as they are handled in HTML. This means that Robot Framework:

  • Removes leading and trailing whitespace in all cells.
  • Changes multiple consecutive spaces into single spaces.
  • Converts all newlines and tabs into spaces.

To prevent Robot Framework from parsing data according to these rules, a backslash can be used:

  • Before leading spaces, for example \ some text.
  • Between consecutive spaces, for example text \ \ more text.
  • After trailing spaces, for example some text \ \.
  • As \n to create a newline, for example first line\n2nd line.
  • As \t to create a tab character, for example text\tmore text.
  • As \r to create a carriage return, for example text\rmore text.

Another, and often clearer, possibility for representing leading, trailing, or consecutive spaces is using built-in variable ${SPACE}. The extended variable syntax even allows syntax like ${SPACE * 8} which makes handling consecutive spaces very simple.

Note

Possible un-escaped whitespace character after the \n is ignored to allow wrapping long lines containing newlines. This means that two lines\nhere and two lines\n here are equivalent. An exception to this rule is that the whitespace character is not ignored inside the extended variable syntax.

Dividing test data to several rows

If there is more data than readily fits a row, it possible to use ellipsis (...) to continue the previous line. In test case and user keyword tables, the ellipsis must be preceded by at least one empty cell. In settings and variable tables, it can be placed directly under the setting or variable name.

In all tables, all empty cells before the ellipsis are ignored.

Additionally, values of settings that take only one value (mainly documentations) can be split to several columns. These values will be then catenated together with spaces when the test data is parsed.

All these syntaxes are illustrated in the following examples. In the first three tables test data has not been split, and the following three illustrate how fewer columns are needed after splitting the data to several rows.

Test data that has not been split
Setting Value Value Value Value Value Value
Default Tags tag-1 tag-2 tag-3 tag-4 tag-5 tag-6
Variable Value Value Value Value Value Value
@{LIST} this list has quite many items
Test Case Action Argument Arg Arg Arg Arg Arg Arg
Example [Documentation] Documentation for this test case. This can get quite long...            
  [Tags] t-1 t-2 t-3 t-4 t-5    
  Do X one two three four five six  
  ${var} = Get X 1 2 3 4 5 6
Test data split to several rows
Setting Value Value Value
Default Tags tag-1 tag-2 tag-3
... tag-4 tag-5 tag-6
Variable Value Value Value
@{LIST} this list has
... quite many items
Test Case Action Argument Argument Argument
Example [Documentation] Documentation for this test case.
... This can get quite long...
[Tags] t-1 t-2 t-3
... t-4 t-5  
Do X one two three
... four five six
${var} = Get X 1 2
... 3 4 5
... ... 6  

Note

Empty cells before ellipsis are allowed generally only in Robot Framework 2.5.2 and newer. In earlier versions a single leading empty cell is allowed inside for loops but not otherwise.

Splitting test data in reST tables

In the plain text markup for reST tables, there are two types of table syntax that can be used to create test data. When using the Simple Tables syntax, a \ or .. is required in the first cell of a continued row in addition to the ... required by Robot Framework.

Here is an example using reST Simple Table format:

===========  ================  ==============  ==========  ==========
 Test Case       Action           Argument      Argument    Argument
===========  ================  ==============  ==========  ==========
Example      [Documentation]   Documentation   for this    test case.
\            ...               This can get    quite       long...
\            [Tags]            t-1             t-2         t-3
\            ...               t-4             t-5
\            Do X              one             two         three
\            ...               four            five        six
\            ${var} =          Get X           1           2
\            ...               3               4           5
\            ...               6
===========  ================  ==============  ==========  ==========

For Grid Table syntax, the first cell in a continued row may be blank, and the second cell should contain ... as with HTML tables:

+-----------+-------------------+---------------+------------+------------+
| Test Case |      Action       |   Argument    |  Argument  |  Argument  |
+===========+===================+===============+============+============+
| Example   | [Documentation]   | Documentation | for this   | test case. |
+-----------+-------------------+---------------+------------+------------+
|           | ...               | This can get  | quite      | long...    |
+-----------+-------------------+---------------+------------+------------+
|           | [Tags]            | t-1           | t-2        | t-3        |
+-----------+-------------------+---------------+------------+------------+
|           | ...               | t-4           | t-5        |            |
+-----------+-------------------+---------------+------------+------------+
|           | Do X              | one           | two        | three      |
+-----------+-------------------+---------------+------------+------------+
|           | ...               | four          | five       | six        |
+-----------+-------------------+---------------+------------+------------+
|           | ${var} =          | Get X         | 1          | 2          |
+-----------+-------------------+---------------+------------+------------+
|           | ...               | 3             | 4          | 5          |
+-----------+-------------------+---------------+------------+------------+
|           | ...               | 6             |            |            |
+-----------+-------------------+---------------+------------+------------+

2.2   Creating test cases

This section describes the overall test case syntax. Organizing test cases into test suites using test case files and test suite directories is discussed in the next section.

2.2.1   Test case syntax

Basic syntax

Test cases are constructed in test case tables from the available keywords. Keywords can be imported from test libraries or resource files, or created in the keyword table of the test case file itself.

The first column in the test case table contains test case names. A test case starts from the row with something in this column and continues to the next test case name or to the end of the table. It is an error to have something between the table headers and the first test.

The second column normally has keyword names. An exception to this rule is setting variables from keyword return values, when the second and possibly also the subsequent columns contain variable names and a keyword name is located after them. In either case, columns after the keyword name contain possible arguments to the specified keyword.

Example test cases
Test Case Action Argument Argument
Valid Login Open Login Page    
Input Name demo  
Input Password mode  
Submit Credentials    
Welcome Page Should Be Open    
     
Setting Variables Do Something first argument second argument
${value} = Get Some Value
Should Be Equal ${value} Expected value

Settings in the Test Case table

Test cases can also have their own settings. Setting names are always in the second column, where keywords normally are, and their values are in the subsequent columns. Setting names have square brackets around them to distinguish them from keywords. The available settings are listed below and explained later in this section.

[Documentation]
Used for specifying a test case documentation.
[Tags]
Used for tagging test cases.
[Setup], [Teardown]
Specify test setup and teardown. Have also synonyms [Precondition] and [Postcondition], respectively.
[Template]
Specifies the template keyword to use. The test itself will contain only data to use as arguments to that keyword.
[Timeout]
Used for setting a test case timeout. Timeouts are discussed in their own section.
Example test case with settings
Test Case Action Argument Argument
Test With Settings [Documentation] Another dummy test  
[Tags] dummy owner-johndoe
Log Hello, world!  

2.2.2   Using arguments

The earlier examples have already demonstrated keywords taking different arguments, and this section discusses this important functionality more thoroughly. How to actually implement user keywords and library keywords with different arguments is discussed in separate sections.

Keywords can accept zero or more arguments, and some arguments may have default values. What arguments a keyword accepts depends on its implementation, and typically the best place to search this information is keyword's documentation. In the examples in this section the documentation is expected to be generated using the libdoc.py tool, but the same information is available on documentation generated by generic documentation tools such as javadoc.

Required arguments

Most keywords have a certain number of arguments that must always be given. In the keyword documentation this is denoted by specifying the argument names separated with a comma like first, second, third. The argument names actually do not matter in this case, except that they should explain what the argument does, but it is important to have exactly the same number of arguments as specified in the documentation. Using too few or too many arguments will result in an error.

The test below uses keywords Create Directory and Copy File from the OperatingSystem library. Their arguments are specified as path and source, destination which means that they take one and two arguments, respectively. The last keyword, No Operation from BuiltIn, takes no arguments.

Keywords with positional arguments
Test Case Action Argument Argument
Example Create Directory ${TEMPDIR}/stuff  
Copy File ${CURDIR}/file.txt ${TEMPDIR}/stuff
No Operation    

Default values

Arguments often have default values which can either be given or not. In the documentation the default value is typically separated from the argument name with an equal sign like name=default value, but with keywords implemented using Java there may be multiple implementations of the same keyword with different arguments instead. It is possible that all the arguments have default values, but there cannot be any positional arguments after arguments with default values.

Using default values is illustrated by the example below that uses Create File keyword which has arguments path, content=, encoding=UTF-8. Trying to use it without any arguments or more than three arguments would not work.

Keywords with arguments having default values
Test Case Action Argument Argument Argument
Example Create File ${TEMPDIR}/empty.txt    
Create File ${TEMPDIR}/utf-8.txt Hyvä esimerkki  
Create File ${TEMPDIR}/iso-8859-1.txt Hyvä esimerkki ISO-8859-1

Variable number of arguments

It is also possible to create keywords that accept any number of arguments. These arguments can be combined with mandatory arguments and arguments with default values, but the so called varargs are always the last ones. In the documentation they typically have an asterisk before the argument name like *varargs , but there are again differences with Java libraries.

Remove Files and Join Paths keywords used in the example below have arguments *paths and base, *parts, respectively. The former can be used with any number of arguments, but the latter requires at least one argument.

Keywords with variable number of arguments
Test Case Action Argument Argument Argument
Example Remove Files ${TEMPDIR}/f1.txt ${TEMPDIR}/f2.txt ${TEMPDIR}/f3.txt
@{paths} = Join Paths ${TEMPDIR} f1.txt
... f2.txt f3.txt f4.txt

Named arguments

When a keyword accepts more than one argument with a default value, overriding only the last one using positional argument is not possible. For example, if a keyword having arguments arg1=a, arg2=b, arg3=c is used as in the test below, its arguments arg1 and arg2 both get an empty string as value instead of their default values.

Overriding default values with positional arguments
Test Case Action Argument Argument Argument
Positional Arguments [Documentation] 1st and 2nd argument get empty strings
Example Keyword     value

To make giving only some of the arguments that expect default values easier, new named arguments syntax was added in Robot Framework 2.5. With this syntax the arguments that need to override their default values are given immediately after the required arguments in format argname=value. The arguments that should use defaults can be simply be left out. How this works in practice is illustrated by the example test below that uses the same keyword as the above example. In this example the arguments that are not specified will get their default values.

Keywords with named arguments
Test Case Action Argument Argument Argument
Named Arguments [Documentation] Not specified arguments get default values
Example Keyword arg3=value    
Example Keyword arg2=xxx arg3=yyy  

The named argument syntax can naturally be used with arguments accepting default values also when no arguments are left away. This can make argument meanings more clear than when only the value is shown. Naming the required arguments this way is not possible, though. Additionally, it is not possible to give first named arguments and then varargs.

The biggest limitation of the name arguments functionality is that it currently works only with user keywords and with library keywords implemented with Python that use either the static library API or the hybrid library API. It is possible that support for Java libraries and for the dynamic library API is added in the future. Until that it is possible to create user keywords that wrap the incompatible keywords.

Note

When the named argument syntax is used with user keywords, the argument names are given without the ${} decoration. For example, user keyword with arguments ${arg1}=default, ${arg2}=second must be used like arg2=override.

The named argument syntax is used only when the part of the argument before the equal sign matches the name of an argument with a default value. This matching is started from the end of the given argument list and stopped when there is no match. In those rare cases when there are accidental matches, it is possible to use \ to escape this syntax like nomatch\=here.

Note

The named argument syntax is both case and space sensitive. The former means that if you have an argument arg, you must use it like arg=<value>, and Arg=<value> or ARG=<value> do not work. The latter means that spaces are not allowed before the = sign, and possible spaces after it are considered part of the default value itself.

The following example demonstrates using named arguments in different scenarios, including in test library imports.

Named argument example
Setting Value Value Value
Library Telnet prompt=$  
Test Case Action Argument Argument Argument
Example Open connection 10.0.0.42 port=${25}  
List files options=-lh    
List files path=/tmp options=-l  
Keyword Action Argument Argument Argument
List files [Arguments] ${path}=. ${options}=  
Execute command ls ${options} ${path}    

Arguments embedded to keyword names

A totally different approach to specify arguments is embedding them into keyword names. This syntax is, at least currently, only supported by user keywords.

2.2.3   Test case name and documentation

The test case name comes directly from the Test Case table: it is exactly what is entered into the test case column. Test cases in one test suite should have unique names. Pertaining to this, you can also use the automatic variable ${TEST_NAME} within the test itself to refer to the test name. It is available whenever a test is being executed, including all user keywords, as well as the test setup and the test teardown.

The [Documentation] setting allows you to set a free documentation for a test case. That text is shown in the command line output, as well as the resulting test logs and test reports. If the documentation is long, it can be split into several cells that are catenated together with spaces. It is possible to use simple HTML formatting and variables can be used to make the documentation dynamic. Possible non-existing variables in documentation are just left unchanged starting from Robot Framework 2.1 version.

Test case documentation examples
Test Case Action Argument Argument
Simple [Documentation] Simple documentation  
  No Operation    
Splitting [Documentation] This documentation is a bit longer and it has been split into several columns.
  No Operation    
Formatting [Documentation] *This is bold*, _this italic_ and here is a link: http://robotframework.org
  No Operation    
Variables [Documentation] Executed at ${HOST} by ${USER}  
  No Operation    

It is important that test cases have clear and descriptive names, and in that case they normally do not need any documentation. If the logic of the test case needs documenting, it is often a sign that keywords in the test case need better names and they are to be enhanced, instead of adding extra documentation. Finally, metadata, such as the environment and user information in the last example above, is often better specified using tags.

2.2.4   Tagging test cases

Using tags in Robot Framework is a simple, yet powerful mechanism for classifying test cases. Tags are free text and they can be used at least for the following purposes:

  • Tags are shown in test reports, logs and, of course, in the test data, so they provide metadata to test cases.
  • Statistics about test cases (total, passed, failed are automatically collected based on tags).
  • With tags, you can include or exclude test cases to be executed.
  • With tags, you can specify which test cases are considered critical.

In this section it is only explained how to set tags for test cases, and different ways to do it are listed below. These approaches can naturally be used together.

Force Tags in the Setting table
All test cases in a test case file with this setting always get specified tags. If it is used in the test suite initialization file, all test cases in sub test suites get these tags.
Default Tags in the Setting table
Test cases that do not have a [Tags] setting of their own get these tags. Starting from Robot Framework version 2.5 default tags are no longer supported in test suite initialization files.
[Tags] in the Test Case table
A test case always gets these tags. Additionally, it does not get the possible tags specified with Default Tags, so it is possible to override the Default Tags by using empty value. Starting from Robot Framework 2.5.6, is also possible to use value NONE to override default tags.
--settag command line option
All executed test cases get tags set with this option in addition to tags they got elsewhere.
Set Tags and Remove Tags keywords
These BuiltIn keywords can be used to modify tags during the test execution.

Tags are free text, but they are normalized so that they are converted to lowercase and all spaces are removed. If a test case gets the same tag several times, other occurrences than the first one are removed. Tags can be created using variables, assuming that those variables exist.

Tagging example
Setting Value Value Value
Force Tags req-42    
Default Tags owner-john smoke  
Variable Value Value Value
${HOST} 10.0.1.42    
Test Case Action Argument Argument
No own tags [Documentation] This test has tags owner-john, smoke, req-42
  No Operation    
       
With own tags [Documentation] This test has tags not_ready, owner-mrx, req-42
  [Tags] owner-mrx not_ready
  No Operation    
       
Own tags with variables [Documentation] This test has tags host-10.0.1.42, req-42
  [Tags] host-${HOST}  
  No Operation    
       
Empty own tags [Documentation] This test has tags req-42
  [Tags]    
  No Operation    
       
Set Tags and Remove Tags Keywords [Documentation] This test has tags mytag, owner-john
  Set Tags mytag  
  Remove Tags smoke req-*

2.2.5   Test setup and teardown

Robot Framework has similar test setup and teardown functionality as many other test automation frameworks. In short, a test setup is something that is executed before a test case, and a test teardown is executed after a test case. In Robot Framework setups and teardowns are just normal keywords with possible arguments.

Setup and teardown are always a single keyword. If they need to take care of multiple separate tasks, it is possible to create higher-level user keywords for that purpose. An alternative solution is executing multiple keywords using the BuiltIn keyword Run Keywords that was added in Robot Framework 2.5.

The test teardown is special in two ways. First of all, it is executed also when a test case fails, so it can be used for clean-up activities that must be done regardless of the test case status. Starting from Robot Framework 2.5, all the keywords in the teardown are also executed even if one of them fails. This continue on failure functionality can be used also with normal keywords, but inside teardowns it is on by default.

The easiest way to specify a setup or a teardown for test cases in a test case file is using the Test Setup and Test Teardown settings in the Setting table. Individual test cases can also have their own setup or teardown. They are defined with the [Setup] or [Teardown] settings in the test case table and they override possible Test Setup and Test Teardown settings. Having no keyword after a [Setup] or [Teardown] setting means having no setup or teardown. Starting from Robot Framework 2.5.6, it is also possible to use value NONE to indicate that a test has no setup/teardown.

Test setup and teardown examples
Setting Value Value Value
Test Setup Open Application App A  
Test Teardown Close Application    
Test Case Action Argument Argument
Default values [Documentation] Setup and teardown from setting table
Do Something    
     
Overridden setup [Documentation] Own setup, teardown from setting table
[Setup] Open Application App B
Do Something    
     
No teardown [Documentation] Default setup, no teardown at all
Do Something    
[Teardown]    
     
No teardown 2 [Documentation] Using special NONE, works with 2.5.6
Do Something    
[Teardown] NONE  
     
Using variables [Documentation] Setup and teardown given as variables
[Setup] ${SETUP}  
Do Something    
[Teardown] ${TEARDOWN}  

Often when creating use-case-like test cases, the terms precondition and postcondition are preferred over the terms setup and teardown. Robot Framework supports also this terminology, so that a precondition is a synonym to a setup and a postcondition to a teardown.

Setup and teardown synonyms
Test Setup Test Precondition
Test Teardown Test Postcondition
[Setup] [Precondition]
[Teardown] [Postcondition]

The name of the keyword to be executed as a setup or a teardown can be a variable. This facilitates having different setups or teardowns in different environments by giving the keyword name as a variable from the command line.

Note

Test suites can have a setup and teardown of their own. A suite setup is executed before any test cases or sub test suites in that test suite, and similarly a suite teardown is executed after them.

2.2.6   Test templates

Test templates convert the normal keyword-driven test cases into data-driven tests. Whereas the body of the normal test case is constructed from keywords and their possible arguments, test cases with template define only the arguments for the template keyword. This is illustrated by the following example test cases that are functionally fully identical.

Using test template
Test Case Action Argument Argument
Normal test case Example keyword first argument second argument
     
Templated test case [Template] Example keyword  
first argument second argument  

As the example above illustrates, it is possible to specify the template for an individual test case using the [Template] setting. An alternative approach is using the Test Template setting in the Setting table, in which case the template is applied for all test cases in that test case file. The [Template] setting overrides the possible template set in the Setting table, and an empty value for [Template] means that the test has no template even when Test Template is used. Starting from Robot Framework 2.5.6, it is also possible to use value NONE to indicate that a test has no template.

If a templated test case has multiple data rows in its body, like in the example below, the template is applied for all the rows. This means that the same keyword is executed multiple times, once with data on each row. Templated tests are also special so that all the rounds are executed even if there are failures. It is possible to use this kind of continue on failure mode with normal tests too, but with the templated tests the mode is on automatically.

Using test template with multiple data rows
Test Case Action Argument Argument
Templated test case [Template] Example keyword  
first round 1 first round 2  
second round 1 second round 2  
third round 1 third round 2  

If templates are used with for loops, the template is applied for all the steps inside the loop. The continue on failure mode is in use also in this case, which means that all the steps are executed with all the looped elements even if there are failures.

Using test template with for loops
Test Case Action Argument Argument Argument
Template and for [Template] Example keyword    
:FOR ${item} IN @{ITEMS}
  ${item} 2nd arg  
:FOR ${index} IN RANGE 42
  1st arg ${index}  

The main use case for test templates is reducing duplication with data-driven tests. Instead of repeating the same keyword with all the tests in a file, it is possible to use it only once in the Setting table. This usage is illustrated more thoroughly in the next section.

Note

Test templates is a new feature in Robot Framework 2.5.

Note

It is currently not possibly to specify the template keyword using variables. This limitation may be lifted in the future versions.

2.2.7   Different test case styles

There are several different ways in which test cases may be written. Test cases that describe some kind of workflow may be written either in keyword-driven or behavior-driven style. Data-driven style can be used to test the same workflow with varying input data.

Keyword-driven style

Workflow tests, such as the Valid Login test described earlier, are constructed from several keywords and their possible arguments. Their normal structure is that first the system is taken into the initial state (Open Login Page in the Valid Login example), then something is done to the system (Input Name, Input Password, Submit Credentials), and finally it is verified that the system behaved as expected (Welcome Page Should Be Open).

Data-driven style

Another style to write test cases is the data-driven approach where test cases use only one higher-level keyword, normally created as a user keyword, that hides the actual test workflow. These tests are very useful when there is a need to test the same scenario with different input and/or output data. It would be possible to repeat the same keyword with every test, but the test template functionality allows specifying the keyword to use only once.

Data-driven testing example
Setting Value Value Value
Test Template Login with invalid credentials should fail    
Test Case User Name Password  
Invalid User Name invalid ${VALID PASSWORD}  
Invalid Password ${VALID USER} invalid  
Invalid User Name And Password invalid whatever  
Empty User Name ${EMPTY} ${VALID PASSWORD}  
Empty Password ${VALID USER} ${EMPTY}  
Empty User Name And Password ${EMPTY} ${EMPTY}  

The above example has six separate tests, one for each invalid user/password combination, and the example below illustrates how to have only one test with all the combinations. When using test templates, all the rounds in a test are executed even if there are failures, so there is no real functional difference between these two styles. In the above example separate combinations are named so it is easier to see what they test, but having potentially large number of these tests may mess-up statistics. Which style to use depends on the context and personal preferences.

Data-driven test with multiple data variations
Test Case User Name Password  
Invalid Password [Template] Login with invalid credentials should fail  
  invalid ${VALID PASSWORD}  
  ${VALID USER} invalid  
  invalid whatever  
  ${EMPTY} ${VALID PASSWORD}  
  ${VALID USER} ${EMPTY}  
  ${EMPTY} ${EMPTY}  

Tip

In both of the above examples, column headers have been changed to match the data. This is possible because on the first row other cells except the first one are ignored.

Behavior-driven style

It is also possible to write test cases as requirements that also non-technical project stakeholders must understand. These Executable Requirements are a corner stone of a process commonly called Acceptance Test Driven Development (ATDD).

One way to write these requirements/tests is Given-When-Then style popularized by Behavior Driven Development (BDD). When writing test cases in this style, the initial state is usually expressed with a keyword starting with word Given, the actions are described with keyword starting with When and the expectations with a keyword starting with Then. Keyword starting with And may be used if a step has more than one action.

Example test cases using behavior-driven style
Test Case Step
Valid Login Given login page is open
When valid username and password are inserted
and credentials are submitted
Then welcome page should be open
Ignoring Given/When/Then/And prefixes

Prefixes Given, When, Then and And are dropped when matching keywords are searched, if no match with the full name is found. This works for both user keywords and library keywords. For example, Given login page is open in the above example can be implemented as user keyword either with or without the word Given. Ignoring prefixes also allows using the same keyword with different prefixes. For example Welcome page should be open could also used as And welcome page should be open.

Embedding data to keywords

When writing concrete examples it is useful to be able pass actual data to keyword implementations. User keywords support this by allowing embedding arguments into keyword name.

2.3   Creating test suites

Robot Framework test cases are created in test case files, which can be organized into directories. These files and directories create a hierarchical test suite structure.

2.3.1   Test case files

Robot Framework test cases are created using test case tables in test case files. Such a file automatically creates a test suite from all the test cases it contains. There is no upper limit for how many test cases there can be, but it is recommended to have less than ten, unless the data-driven approach is used, where one test case consists of only one high-level keyword.

The following settings in the Setting table can be used to customize the test suite:

Documentation
Used for specifying a test suite documentation
Metadata
Used for setting free test suite metadata as name-value pairs.
Suite Setup, Suite Teardown
Specify suite setup and teardown. Have also synonyms Suite Precondition and Suite Postcondition, respectively.

Note

All setting names can optionally include a colon at the end, for example Documentation:. This can make reading the settings easier especially when using the plain text format. This is a new feature in Robot Framework 2.5.5.

2.3.2   Test suite directories

Test case files can be organized into directories, and these directories create higher-level test suites. A test suite created from a directory cannot have any test cases directly, but it contains other test suites with test cases, instead. These directories can then be placed into other directories creating an even higher-level suite. There are no limits for the structure, so test cases can be organized as needed.

When a test directory is executed, the files and directories it contains are processed recursively as follows:

  • Files and directories with names starting with a dot (.) or an underscore (_) are ignored.
  • Directories with the name CVS are ignored (case-sensitive).
  • Files not having one of the recognized extensions (.html, .xhtml, .htm, .tsv, .txt, .rst, or .rest) are ignored (case-insensitive).
  • Other files and directories are processed.

If a file or directory that is processed does not contain any test cases, it is silently ignored (a message is written to the syslog) and the processing continues.

Warning on invalid files

Normally files that do not have a valid test case table are silently ignored with a message written to the syslog. As of Robot Framework 2.5.5 it is possible to use a command line option --warnonskippedfiles, which turns the message into a warning shown in test execution errors.

Initialization files

A test suite created from a directory can have similar settings as a suite created from a test case file. Because a directory alone cannot have that kind of information, it must be placed into a special test suite initialization file. Initialization files have the same structure and syntax as test case files, except that they cannot have test case tables and not all settings are supported.

An initialization file name must always be of the format __init__.ext, where the extension must match one of the supported file formats (for example, __init__.html or __init__.txt). The name format is borrowed from Python, where files named in this manner denote that a directory is a module.

The main usage for initialization files is specifying test suite related settings similarly as in test case files, but setting some test case related settings is also possible. Variables and keywords created or imported in initialization files are not available in the lower level test suites, but resource files can be used if there is a need to share them.

How to use different settings in the initialization files:

Documentation, Metadata, Suite Setup, Suite Teardown
These test suite specific settings work the same way as in test case files.
Force Tags
Specified tags are unconditionally set to all test cases in all test case files this directory contains directly or recursively.
Test Setup, Test Teardown
Set the default value for test setup/teardown to all test cases this directory contains. Can be overridden on lower level.
Default Tags, Test Template, Test Timeout
Not supported in initialization files starting from Robot Framework 2.5.
An example test suite initialization file
Setting Value Value
Documentation Example suite  
Suite Setup Do Something ${MESSAGE}
Force Tags example  
Library SomeLibrary  
Variable Value Value
${MESSAGE} Hello, world!  
Keyword Action Argument Argument
Do Something [Arguments] ${arg}  
Some Keyword ${arg}  
Another Keyword    

2.3.3   Test suite name and documentation

The test suite name is constructed from the file or directory name. The name is created so that the extension is ignored, possible underscores are replaced with spaces, and names fully in lower case are title cased. For example, some_tests.html becomes Some Tests and My_test_directory becomes My test directory.

Note

The rules for creating test suite names changed slightly in Robot Framework 2.5.

The file or directory name can contain a prefix to control the execution order of the suites. The prefix is separated from the base name by two underscores and, when constructing the actual test suite name, both the prefix and underscores are removed. For example files 01__some_tests.txt and 02__more_tests.txt create test suites Some Tests and More Tests, respectively, and the former is executed before the latter.

The documentation for a test suite is set using the Documentation setting in the Setting table. It can be used in test case files or, with higher-level suites, in test suite initialization files. Test suite documentation has exactly the same characteristics regarding to where it is shown and how it can be created as test case documentation.

Test suite documentation example
Setting Value Value Value
Documentation An example test suite documentation with *some* _formatting_.
... See test documentation for more documentation examples.

Both the name and documentation of the top-level test suite can be overridden in test execution. This can be done with the command line options --name and --doc, respectively, as explained in section Setting metadata.

2.3.4   Free test suite metadata

Test suites can also have other metadata than the documentation. This metadata is defined in the Setting table using the Metadata setting. Metadata set in this manner is shown in test reports and logs.

The name and value for the metadata are located in the columns following Metadata. The value is handled similarly as documentations, which means that it can be split into several cells (joined together with spaces), simple HTML formatting works and even variables can be used.

Metadata examples
Setting Value Value Value Value
Metadata Version 2.0    
Metadata More Info For more information about *Robot Framework* see http://robotframework.org
Metadata Executed At ${HOST}    

For top-level test suites, it is possible to set metadata also with the --metadata command line option. This is discussed in more detail in section Setting metadata.

Prior to Robot Framework 2.5 the free metadata was specified with syntax like Meta: <name>, where <name> was the metadata name and the value was defined in subsequent column. Robot Framework 2.5 still supports this old format but it will be deprecated in the future.

2.3.5   Suite setup and teardown

Not only test cases but also test suites can have a setup and a teardown. A suite setup is executed before running any of the suite's test cases or child test suites, and a test teardown is executed after them. All test suites can have a setup and a teardown; with suites created from a directory they must be specified in a test suite initialization file.

Similarly as with test cases, a suite setup and teardown are keywords that may take arguments. They are defined in the Setting table with Suite Setup and Suite Teardown settings, respectively. They also have similar synonyms, Suite Precondition and Suite Postcondition, as a test case setup and teardown have. Keyword names and possible arguments are located in the columns after the setting name.

If a suite setup fails, all test cases in it and its child test suites are immediately assigned a fail status and they are not actually executed. This makes suite setups ideal for checking preconditions that must be met before running test cases is possible.

A suite teardown is normally used for cleaning up after all the test cases have been executed. It is executed even if the setup of the same suite fails. If the suite teardown fails, all test cases in the suite are marked failed, regardless of their original execution status. Starting from Robot Framework 2.5, all the keywords in suite teardowns are executed even if one of them fails.

The name of the keyword to be executed as a setup or a teardown can be a variable. This facilitates having different setups or teardowns in different environments by giving the keyword name as a variable from the command line.

2.4   Using test libraries

Test libraries contain those lowest-level keywords, often called library keywords, which actually interact with the system under test. All test cases always use keywords from some library, often through higher-level user keywords. This section explains how to take test libraries into use and how to use the keywords they provide. Creating test libraries is described in a separate section.

2.4.1   Taking test libraries into use

Instructions for taking test libraries into use are given in the subsections below.

Using Library setting

Test libraries are normally imported using the Library setting in the Setting table and having the library name in the subsequent column. The library name is case-sensitive (it is the name of the module or class implementing the library and must be exactly correct), but any spaces in it are ignored. With Python libraries in modules or Java libraries in packages, the full name including the module or package name must be used.

In those cases where the library needs arguments, they are listed in the columns after the library name. It is possible to use default values, variable number of arguments, and named arguments in test library imports similarly as with arguments to keywords. Both the library name and arguments can be set using variables.

Importing test libraries
Setting Value Value Value
Library OperatingSystem
Library com.company.TestLib
Library MyLibrary arg1 arg2
Library ${LIBRARY}

It is possible to import test libraries in test case files, resource files and test suite initialization files. In all these cases, all the keywords in the imported library are available in that file. With resource files, those keywords are also available in other files using them.

Using Import Library keyword

Another possibility to take a test library into use is using the keyword Import Library from the BuiltIn library. This keyword takes the library name and possible arguments similarly as the Library setting. Keywords from the imported library are available in the test suite where the Import Library keyword was used. This approach is useful in cases where the library is not available when the test execution starts and only some other keywords make it available.

Using Import Library keyword
Test Case Action Argument Argument Argument
Example Do Something
Import Library MyLibrary arg1 arg2
KW From Mylibrary

Library search path

The most common way to specify a test library to import is using its name, like it has been done in all the examples in this section. In these cases Robot Framework tries to find the class or module implementing the library from the library search path. Basically, this means that the library code and all its possible dependencies must be in PYTHONPATH or, when running tests on Jython, in a CLASSPATH. Setting the library search path is explained in a section of its own. Libraries can also set the search path automatically or have special instructions on how to do it. All standard libraries, for example, are in the library search path automatically.

The biggest benefit of this approach is that when the library search path has been configured, often using a custom start-up script, normal users do not need to think where libraries actually are installed. The drawback is that getting your own, possible very simple, libraries into the search path may require some additional configuration.

Using physical path to library

Another mechanism for specifying the library to import is using a path to it in the file system. This path is considered relative to the directory where current test data file is situated similarly as paths to resource and variable files. The main benefit of this approach is that there is no need to configure the library search path.

If the library is a file, the path to it must contain extension. For Python libraries the extension is naturally .py and for Java libraries it can either be .class or .java, but the class file must always be available. If Python library is implemented as a directory, the path to it must have a trailing forward slash (/). Following examples demonstrate these different usages.

Importing test libraries using physical paths to them
Setting Value Value Value
Library PythonLib.py
Library /absolute/path/JavaLib.java
Library relative/path/PythonDirLib/ possible arguments
Library ${RESOURCES}/Example.class

A limitation of this approach is that libraries implemented as Python classes must be in a module with the same name as the class. Additionally, importing libraries distributed in JAR or ZIP packages is not possible with this mechanism.

2.4.2   Setting custom name to test library

The library name is shown in test logs before keyword names, and if multiple keywords have the same name, they must be used so that the keyword name is prefixed with the library name. The library name is got normally from the module or class name implementing it, but there are some situations where changing it is desirable:

  • There is a need to import the same library several times with different arguments. This is not possible otherwise.
  • The library name is inconveniently long. This can happen, for example, if a Java library has a long package name.
  • You want to use variables to import different libraries in different environments, but refer to them with the same name.
  • The library name is misleading or otherwise poor. In this case, changing the actual name is, of course, a better solution.

The basic syntax for specifying the new name is having the text WITH NAME (case-insensitive) after the library name and then having the new name in the next cell. The specified name is shown in logs and must be used in the test data when using keywords' full name (LibraryName.Keyword Name).

Importing libraries with custom names
Setting Value Value Value
Library com.company.TestLib WITH NAME TestLib
Library ${LIBRARY} WITH NAME MyName

Possible arguments to the library are placed into cells between the original library name and the WITH NAME text. The following example illustrates how the same library can be imported several times with different arguments:

Importing the same library several times with a different name
Setting Value Value Value Value Value
Library SomeLibrary localhost 1234 WITH NAME LocalLib
Library SomeLibrary server.domain 8080 WITH NAME RemoteLib
Test Case Action Argument Argument
My Test LocalLib.Some Keyword some arg second arg
RemoteLib.Some Keyword another arg whatever
LocalLib.Another Keyword

Setting a custom name to a test library works both when importing a library in the Setting table and when using the Import Library keyword.

2.4.3   Standard libraries

Some test libraries are distributed with Robot Framework and these libraries are called standard libraries. These are the available standard libraries:

The BuiltIn library is special, because it is taken into use automatically and thus its keywords are always available. Other standard libraries need to be imported in the same way as any other libraries, but there is no need to install them. Additionally, they work when running tests both with Python and Jython (with the Screenshot library as an exception).

New standard libraries can, and will, be added in the future. If you have an idea for a new standard library, or even have one that could be incorporated immediately, please contact Robot Framework developers. In general, a library is a good candidate to be added into standard libraries if it is generic, works on both Python and Jython without any external dependencies, and is adequately tested and documented.

BuiltIn library

The BuiltIn library provides a set of generic keywords needed often. It is imported automatically and thus always available. The provided keywords can be used, for example, for verifications (e.g. Should Be Equal, Should Contain), conversions (e.g. Convert To Integer) and for various other purposes (e.g. Log, Sleep, Run Keyword If, Set Global Variable).

The names of the keywords in the BuiltIn library have been renamed in Robot Framework version 1.8. All the old keywords still work, but the long names (the names visible in log files) of the keywords that are deprecated begin with DeprecatedBuiltIn. (for example, DeprecatedBuiltIn.Equals). It is highly recommended to use the new names of the keywords as the old versions will be removed altogether in the future.

For more information, see the BuiltIn library documentation.

OperatingSystem library

The OperatingSystem library enables various operating system related tasks to be performed in the system where Robot Framework is running. It can, among other things, execute commands (e.g. Run), create and remove files and directories (e.g. Create File, Remove Directory), check whether files or directories exists or contain something (e.g. File Should Exist, Directory Should Be Empty) and manipulate environment variables (e.g. Set Environment Variable).

The names of the keywords in the OperatingSystem library have been renamed in Robot Framework 1.8 similarly as the names of the BuiltIn keywords.

For more information, see the OperatingSystem library documentation.

Telnet library

The Telnet library makes it possible to connect to Telnet servers and execute commands on the opened connections.

For more information, see the Telnet library documentation.

Collections library

The Collections library provides a set of keywords for handling Python lists and dictionaries. This library has keywords, for example, for modifying and getting values from lists and dictionaries (e.g. Append To List, Get From Dictionary) and for verifying their contents (e.g. Lists Should Be Equal, Dictionary Should Contain Value).

For more information, see the Collections library documentation.

String library

The String library enables manipulating strings (e.g. Replace String With Regexp, Split To Lines) and verifying their contents (e.g. Should Be String).

For more information, see the String library documentation. This library is new in Robot Framework 2.1.

Dialogs library

The Dialogs library provides means for pausing the test execution and getting input from users. The dialogs are slightly different depending on are tests run on Python or Jython but they provide the same functionality.

For more information, see the Dialogs library documentation. This library is new in Robot Framework 2.1.

Screenshot library

The Screenshot library has keywords to capture and store screenshots of the whole desktop. This library is implemented with Java AWT APIs, so it can be used only when running Robot Framework on Jython.

For more information, see the Screenshot library documentation.

Remote library

The Remote library is totally different than the other standard libraries. It does not have any keywords of its own but it works as a proxy between Robot Framework and actual test library implementations. These libraries can be running on other machines than the core framework and can even be implemented using languages not supported by Robot Framework natively.

See separate Remote library interface section for more information about the concept. This library is new in Robot Framework 2.1.

2.4.4   External libraries

Any test library that is not one of the standard libraries is, by definition, an external library. Robot Framework developers provide some generic libraries, such as SeleniumLibrary and SwingLibrary, which are not packaged with the framework itself, because they require external dependencies. Generic libraries can also be provided by other parties, and most teams have also some custom libraries only for themselves.

Different external libraries can have a totally different mechanism for installing and introducing them. Quite often they also require some other dependencies to be installed separately. All libraries should have clear instructions on this and preferably automate the installation.

See Creating test libraries section for more information about how to create new test libraries for your own or generic usage.

2.5   Variables

2.5.1   Introduction

Variables are an integral feature of Robot Framework, and they can be used in most places in test data. Most commonly, they are used in arguments for keywords in test case tables and keyword tables, but also all settings allow variables in their values. A normal keyword name cannot be specified with a variable, but the BuiltIn keyword Run Keyword can be used to get the same effect.

Robot Framework itself has two kinds of variables, scalars and lists, and they have the syntaxes ${SCALAR} and @{LIST}, respectively. In addition to this, environment variables can be used directly with the syntax %{VARIABLE}.

Warning

Using scalar variables and list variables with the same base name, for example ${VAR} and @{VAR}, has been deprecated in Robot Framework 2.5. For more information, see issue 484 in the issue tracker.

The use of variables is recommended in the following cases:

  • When strings change often in the test data. With variables you only need to make these changes in one place.
  • When creating system-independent and operating-system-independent test data. Using variables instead of hard-coded strings eases that considerably (for example, ${RESOURCES} instead of c:\resources, or ${HOST} instead of 10.0.0.1:8080). Because variables can be set from the command line when tests are started, changing system-specific variables is easy (for example, --variable HOST:10.0.0.2:1234 --variable RESOURCES:/opt/resources). This also facilitates localization testing, which often involves running the same tests with different strings.
  • When there is a need to have objects other than strings as arguments for keywords.
  • When different keywords, even in different test libraries, need to communicate. You can assign a return value from one keyword to a variable and give that as an argument to another.
  • When values in the test data are long or otherwise complicated. For example, ${URL} is shorter than http://long.domain.name:8080/path/to/service?foo=1&bar=2&zap=42.

If a nonexistent variable is used in the test data, the keyword using it fails. If the same syntax that is used for variables is needed as a literal string, it must be escaped with a backslash as in \${NAME}.

2.5.2   Variable types

Different variable types are briefly described in this section. The creation and usage of variables is described in more detail in the following subsections.

Robot Framework variables, similarly as keywords, are case-insensitive, and also spaces and underscores are ignored. However, it is recommended to use all capital letters with global variables (for example, ${PATH} or ${TWO_WORDS}) and small letters with variables that are only available in certain test cases or user keywords (for example, ${my_var} or ${myVar}). Much more importantly, though, cases should be used consistently.

Unlike in some programming languages where similar variable syntax is used, curly braces ({ and }) are mandatory in Robot Framework test data. Basically, variable names can have any characters between the curly braces. However, using only alphabetic characters from a to z, numbers, underscore and space is recommended, and it is even a requirement for using the extended variable syntax.

Scalar variables

When scalar variables are used in the test data, they are replaced with the value they are assigned to. While scalar variables are most commonly used for simple strings, you can assign any objects, including lists, to them. The scalar variable syntax, for example ${NAME}, should be familiar to most users, as it is also used, for example, in shell scripts and Perl programming language.

The example below illustrates the usage of scalar variables. Assuming that the variables ${GREET} and ${NAME} are available and assigned to strings Hello and world, respectively, both the example test cases are equivalent.

Scalar variables with string values
Test Case Action Argument Argument
Strings Log Hello  
Log Hello, world!!  
Variables Log ${GREET}  
Log ${GREET}, ${NAME}!!  

When a scalar variable is used as the only value in a test data cell, the scalar variable is replaced with the value it has. The value may be any object. When a scalar variable is used in a test data cell with anything else (constant strings or other variables), its value is first converted into a Unicode string and then catenated to whatever is in that cell. Converting the value into a string means that the object's method __unicode__ (in Python, with __str__ as a fallback) or toString (in Java) is called.

Note

Variable values are used as-is without conversions also when passing arguments to keywords using the named arguments syntax like argname=${var}.

The example below demonstrates the difference between having a variable in a cell alone or with other content. First, let us assume that we have a variable ${STR} set to a string Hello, world! and ${OBJ} set to an instance of the following Java object:

public class MyObj {

    public String toString() {
        return "Hi, tellus!";
    }
}

With these two variables set, we then have the following test data:

Scalar variables with objects as values
Test Case Action Argument Argument
Objects KW 1 ${STR}  
KW 2 ${OBJ}  
KW 3 I said "${STR}"  
KW 4 You said "${OBJ}"  

Finally, when this test data is executed, different keywords receive the arguments as explained below:

  • KW 1 gets a string Hello, world!
  • KW 2 gets an object stored to variable ${OBJ}
  • KW 3 gets a string I said "Hello, world!"
  • KW 4 gets a string You said "Hi, tellus!"

Note

Converting variables to Unicode obviously fails if the variable cannot be represented as Unicode. This can happen, for example, if you try to use byte sequences as arguments to keywords so that you catenate the values together like ${byte1}${byte2}. A workaround is creating a variable that contains the whole value and using it alone in the cell (e.g. ${bytes}) because then the value is used as-is.

List variables

List variables are compound variables that can have several values assigned to them. In short, they are always lists and can contain an unlimited number of entries (also empty lists are possible). The main benefit of list variables is that they allow you to assign a name for a larger data set. While list variables normally contain only strings, other content is also possible.

When you use a list variable in test data, then the elements of the list are inserted as new cells in the test data. Thus, if the list variable contains two elements, the cell containing the list variable is turned into two cells with the content of the list variable. Note that cells with list variables should not contain other content. The list variable syntax, @{NAME}, is borrowed from Perl.

Assuming that the list variable @{USER} is set to the value ['robot','secret'], the following two test cases are equivalent.

Using list variables
Test Case Action User Name Password
Strings Login robot secret
List Variable Login @{USER}  
Accessing individual list variable items

It is also possible to access a certain value from the list variable with the syntax @{NAME}[i], where i is the index of the selected value. Indexes start from zero, and trying to access a value with too large an index causes an error. List items accessed in this manner can be used similarly as scalar variables:

Accessing list variable items
Test Case Action Argument Argument
Strings Login robot secret
Title Should Be Welcome robot!  
List Variable Login @{USER}  
Title Should Be Welcome @{USER}[0]!  
Using list variables as scalar variables

It is possible to use list variables as scalar variables containing lists simply by replacing @ with $. This makes it possible to use list variables with list related keywords, for example, from BuiltIn and Collections libraries. This feature works only if there is no scalar variable with same base name as the list variable has. In these cases the scalar variable has precedence and its value is used instead.

Using list variables as scalars
Test Case Action Argument Argument Argument
Example @{items} = Create List first second
Length Should Be ${items} 2  
Append To List ${items} third  
Length Should Be ${items} 3  
Remove From List ${items} 1  
Length Should Be ${items} 2  
Log Many @{items}    
Using list variables with settings

List variables can be used only with some of the settings. They can be used in arguments to imported libraries and variable files, but library and variable file names themselves cannot be list variables. Also with setups and teardowns list variable can not be used as the name of the keyword, but can be used in arguments. With tag related settings they can be used freely. Using scalar variables is possible in those places where list variables are not supported.

Using list variables with settings
Settings Value Value Comment
Library ExampleLibrary @{LIB ARGS} # This works
Library ${LIBRARY} @{LIB ARGS} # This works
Library @{NAME AND ARGS}   # This does not work
Suite Setup Some Keyword @{KW ARGS} # This works
Suite Setup ${KEYWORD} @{KW ARGS} # This works
Suite Setup @{KEYWORD}   # This does not work
Default Tags @{TAGS}   # This works

Environment variables

Robot Framework allows using environment variables in the test data using the syntax %{ENV_VAR_NAME}. They are limited to string values.

Environment variables set in the operating system before the test execution are available during it, and it is possible to create new ones with the keyword Set Environment Variable or delete existing ones with the keyword Delete Environment Variable, both available in the OperatingSystem library. Because environment variables are global, environment variables set in one test case can be used in other test cases executed after it. However, changes to environment variables are not effective after the test execution.

Using environment variables
Test Case Action Argument Argument
Env Variables Log Current user: %{USER}  
Run %{JAVA_HOME}${/}javac  

Java system properties

When running tests with Jython, it is possible to access Java system properties using same syntax as environment variables. If an environment variable and a system property with same name exist, the environment variable will be used. Support for accessing Java system properties was added in Robot Framework 2.6.

Using Java system properties
Test Case Action Argument Argument
System Properties Log %{user.name} running tests on %{os.name}  

2.5.3   Creating variables

Variables can spring into existence from different sources as described in the subsections below.

Variable table

The most common source for variables are Variable tables in test case files and resource files. Variable tables are convenient, because they allow creating variables in the same place as the rest of the test data, and the needed syntax is very simple. Their main disadvantage is that they only enable assigning variables into strings or a list of strings. If other value types are needed, variable files are probably a better option.

Creating scalar variables

The simplest possible variable assignment is setting a string into a scalar variable. This is done by giving the variable name (including ${}) in the first column of the Variable table and the value in the second one. If the second column is empty, an empty string is set as a value. Also an already defined variable can be used in the value.

Creating scalar variables
Variable Value Value
${NAME} Robot Framework  
${VERSION} 2.0  
${ROBOT} ${NAME} ${VERSION}  

It is also possible, but not obligatory, to use the equals sign = after the variable name to make assigning variables slightly more explicit.

Creating scalar variables using the equals sign
Variable Value Value
${NAME} = Robot Framework  
${VERSION} = 2.0  
Creating list variables

Creating list variables is as easy as creating scalar variables. Again, the variable name is in the first column of the Variable table and values in the subsequent columns. A list variable can have any number of values, starting from zero, and if many values are needed, they can be split into several rows.

Creating list variables
Variable Value Value Value
@{NAMES} Matti Teppo  
@{NAMES2} @{NAMES} Seppo  
@{NOTHING}      
@{MANY} one two three
... four five six
... seven    

Variable file

Variable files are the most powerful mechanism for creating different kind of variables. It is possible to assign variables to any object using them, and they also enable creating variables dynamically. The variable file syntax and taking variable files into use is explained in section Resource and variable files.

Setting variables in command line

Variables can be set from the command line either individually with the --variable (-v) option or using a variable file with the --variablefile (-V) option. Variables set from the command line are globally available for all executed test data files, and they also override possible variables with the same names in the Variable table and in variable files imported in the test data.

The syntax for setting individual variables is --variable name:value, where name is the name of the variable without ${} and value is its value. Several variables can be set by using this option several times. Only scalar variables can be set using this syntax and they can only get string values. Many special characters are difficult to represent in the command line, but they can be escaped with the --escape option.

--variable EXAMPLE:value
--variable HOST:localhost:7272 --variable USER:robot
--variable ESCAPED:Qquotes_and_spacesQ --escape quot:Q --escape space:_

In the examples above, variables are set so that

  • ${EXAMPLE} gets the value value
  • ${HOST} and ${USER} get the values localhost:7272 and robot
  • ${ESCAPED} gets the value "quotes and spaces"

The basic syntax for taking variable files into use from the command line is --variablefile path/to/variables.py, and Taking variable files into use section has more details. What variables actually are created depends on what variables there are in the referenced variable file.

If both variable files and individual variables are given from the command line, the latter have higher priority.

Return values from keywords

Return values from keywords can also be set into variables. This allows communication between different keywords even in different test libraries. The syntax for a simple case is illustrated in the example below:

Assigning values from keywords to variables
Test Case Action Argument Argument
Returning ${x} = Get X an argument
Log We got ${x}!  

In the example above, the value returned by the Get X keyword is first set into the variable ${x} and then used by the Log keyword. This syntax works in all cases where a keywords returns something, and the variable is set to whatever value returned by the keyword. Having the equals sign = after the variable name is not obligatory, but recommended, because it makes the assignment more explicit.

If a keyword returns a list, it is also possible to assign the return value into several scalar variables and/or one list variable. Starting from Robot Framework 2.5 this works with all list-like objects, but prior to it only Python lists and tuples and Java arrays were supported.

Assigning multiple values at once
Test Case Action Argument Argument Argument
Return Multiple ${scalar} = Get 3    
${a} ${b} ${c} = Get 3
${first} @{rest} = Get 3  
@{list} = Get 3    

Assuming that the keyword Get 3 returns a list [1, 2, 3], the following variables are created:

  • ${scalar} with the value [1, 2, 3]
  • ${a}, ${b} and ${c} with the values 1, 2, and 3, respectively
  • ${first} with the value 1, and @{rest} with the value [2, 3]
  • @{list} with the value [1, 2, 3]

Variables set in this manner are otherwise similar to any other variables, but they are available only within the scope of the test case or keyword where they are created. Thus it is not possible, for example, to set a variable in one test case and use it in another. This is because, in general, automated test cases should not depend on each other, and accidentally setting a variable that is used elsewhere could cause hard-to-debug errors. If there is a genuine need for setting a variable in one test case and using it in another, it is possible to use built-in keywords as explained in the next section.

Using built-in Set Test/Suite/Global Variable keywords

The BuiltIn library has keywords Set Test Variable, Set Suite Variable and Set Global Variable which can be used for setting variables dynamically during the test execution. If a variable already exists within the new scope, its value will be overwritten, and otherwise a new variable is created.

Variables set with Set Test Variable keyword are available everywhere within the scope of the currently executed test case. For example, if you set a variable in a user keyword, it is available both in the test case level and also in all other user keywords used in the current test. Other test cases will not see variables set with this keyword.

Variables set with Set Suite Variable keyword are available everywhere within the scope of the currently executed test suite. Setting variables with this keyword thus has the same effect as creating them using the Variable table in the test data file or importing them from variable files. Other test suites, including possible child test suites, will not see variables set with this keyword.

Variables set with Set Global Variable keyword are globally available in all test cases and suites executed after setting them. Setting variables with this keyword thus has the same effect as creating from the command line using the options --variable or --variablefile. Because this keyword can change variables everywhere, it should be used with care.

2.5.4   Built-in variables

Robot Framework provides some built-in variables that are available automatically.

Operating-system variables

Built-in variables related to the operating system ease making the test data operating-system-agnostic.

Available operating-system-related built-in variables
Variable Explanation
${CURDIR} An absolute path to the directory where the test data file is located. This variable is case-sensitive.
${TEMPDIR} An absolute path to the system temporary directory. In UNIX-like systems this is typically /tmp, and in Windows c:\Documents and Settings\<user>\Local Settings\Temp.
${EXECDIR} An absolute path to the directory where test execution was started from. New in Robot Framework 2.1.
${/} The system directory path separator. / in UNIX-like systems, \ in Windows.
${:} The system path element separator. : in UNIX-like systems and ; in Windows.
Using operating-system-related built-in variables
Test Case Action Argument Argument
Example Create File ${CURDIR}${/}input.data Some text here
Set Environment Variable CLASSPATH ${TEMPDIR}${:}${TEMPDIR}${/}foo.jar

Number variables

The variable syntax can be used for creating both integers and floating point numbers, as illustrated in the example below. This is useful when a keyword expects to get an actual number, and not a string that just looks like a number, as an argument.

Using number variables
Test Case Action Argument Argument Comment
Example 1A Connect example.com 80 # Connect gets two strings as arguments
Example 1B Connect example.com ${80} # Connect gets a string and an integer
Example 2 Do X ${3.14} ${-1e-4} # Do X gets floating point numbers 3.14 and -0.0001

Starting from Robot Framework 2.6, it is possible to create integers also from binary, octal, and hexadecimal values using 0b, 0o and 0x prefixes, respectively. The syntax is case insetive.

Using integer variables with base
Test Case Action Argument Argument
Example Should Be Equal ${0b1011} ${11}
Should Be Equal ${0o10} ${8}
Should Be Equal ${0xff} ${255}
Should Be Equal ${0B1010} ${0XA}

Boolean and None/null variables

Also Boolean values and Python None and Java null can be created using the variable syntax similarly as numbers.

Using Boolean and None/null variables
Test Case Action Argument Argument Comment
Boolean Set Status ${true}   # Set Status gets Boolean true as an argument
Create Y something ${false} # Create Y gets a string and Boolean false
None Do XYZ ${None}   # Do XYZ gets Python None as an argument
Null ${ret} = Get Value arg # Checking that Get Value returns Java null
Should Be Equal ${ret} ${null}  

These variables are case-insensitive, so for example ${True} and ${true} are equivalent. Additionally, ${None} and ${null} are synonyms, because when running tests on the Jython interpreter, Jython automatically converts None and null to the correct format when necessary.

Space and empty variables

It is possible to create spaces and empty strings using variables ${SPACE} and ${EMPTY}, respectively. These variables are useful, for example, when there would otherwise be a need to escape spaces or empty cells with a backslash. If more than one space is needed, it is possible to use the extended variable syntax like ${SPACE * 5}. In the following example, Should Be Equal keyword gets identical arguments but those using variables are easier to understand than those using backslashes.

Using ${SPACE} and ${EMPTY}
Test Case Action Argument Argument
One Space Should Be Equal ${SPACE} \ \
Four Spaces Should Be Equal ${SPACE * 4} \ \ \ \ \
Ten Spaces Should Be Equal ${SPACE * 10} \ \ \ \ \ \ \ \ \ \ \
Quoted Space Should Be Equal "${SPACE}" " "
Quoted Spaces Should Be Equal "${SPACE * 2}" " \ "
Empty Should Be Equal ${EMPTY} \

Automatic variables

Some automatic variables can also be used in the test data. These variables can have different values during the test execution and some of them are not even available all the time.

Available automatic variables
Variable Explanation Available
${TEST NAME} The name of the current test case. Test case
@{TEST TAGS} Contains the tags of the current test case in alphabetical order. Test case
${TEST STATUS} The status of the current test case, either PASS or FAIL. Test teardown
${TEST MESSAGE} The possible error message of the current test case. Test teardown
${PREV TEST NAME} The name of the previous test case, or an empty string if no tests have been executed yet. Everywhere
${PREV TEST STATUS} The status of the previous test case: either PASS, FAIL or an empty string when no tests have been executed. Everywhere
${PREV TEST MESSAGE} The possible error message of the previous test case. Everywhere
${SUITE NAME} The full name of the current test suite. Everywhere
${SUITE SOURCE} An absolute path to the suite file or directory. New in Robot Framework 2.5. Everywhere
${SUITE STATUS} The status of the current test case, either PASS or FAIL. Suite teardown
${SUITE MESSAGE} The full message of the current test suite, including statistics. Suite teardown
${OUTPUT FILE} An absolute path to the output file. Everywhere
${LOG FILE} An absolute path to the log file or string NONE when no log file is created. Everywhere
${REPORT FILE} An absolute path to the report file or string NONE when no report is created. Everywhere
${SUMMARY FILE} Summary files were removed in Robot Framework 2.6 and this variable always has value NONE. It will be removed altogether in version 2.7. Everywhere
${DEBUG FILE} An absolute path to the debug file or string NONE when no debug file is created. Everywhere
${OUTPUT DIR} An absolute path to the output directory. Everywhere

2.5.5   Variable priorities and scopes

Variables coming from different sources have different priorities and are available in different scopes.

Variable priorities

Variables from the command line

Variables set in the command line have the highest priority of all variables that can be set before the actual test execution starts. They override possible variables created in Variable tables in test case files, as well as in resource and variable files imported in the test data.

Individually set variables (--variable option) override the variables set using variable files (--variablefile option). If you specify same individual variable multiple times, the one specified last will override earlier ones. This allows setting default values for variables in a start-up script and overriding them from the command line. Notice, though, that if multiple variable files have same variables, the ones in the file specified first have the highest priority.

Variable table in a test case file

Variables created using the Variable table in a test case file are available for all the test cases in that file. These variables override possible variables with same names in imported resource and variable files.

Variables created in the variable tables are available in all other tables in the file where they are created. This means that they can be used also in the Setting table, for example, for importing more variables from resource and variable files.

Imported resource and variable files

Variables imported from the resource and variable files have the lowest priority of all variables created in the test data. Variables from resource files and variable files have the same priority. If several resource and/or variable file have same variables, the ones in the file imported first are taken into use.

If a resource file imports resource files or variable files, variables in its own Variable table have a higher priority than variables it imports. All these variables are available for files that import this resource file.

Note that variables imported from resource and variable files are not available in the Variable table of the file that imports them. This is due to the Variable table being processed before the Setting table where the resource files and variable files are imported.

Variables set during test execution

Variables set during the test execution either using return values from keywords or built-in keywords Set Test/Suite/Global Variable always override possible existing variables in the scope where they are set. In a sense they thus have the highest priority, but on the other hand they do not affect variables outside the scope they are defined.

Built-in variables

Built-in variables like ${TEMPDIR} and ${TEST_NAME} have the highest priority of all variables. They cannot be overridden using Variable table or from command line, but even they can be reset during the test execution. An exception to this rule are number variables, which are resolved dynamically if no variable is found otherwise. They can thus be overridden, but that is generally a bad idea. Additionally ${CURDIR} is special because it is replaced already during the test data processing time.

Variable scopes

Depending on where and how they are created, variables can have a global, test suite, test case or user keyword scope.

Global scope

Global variables are available everywhere in the test data. These variables are normally set from the command line with the --variable and --variablefile options, but it is also possible to create new global variables or change the existing ones with the BuiltIn keyword Set Global Variable anywhere in the test data. Additionally also built-in variables are global.

It is recommended to use capital letters with all global variables.

Test suite scope

Variables with the test suite scope are available anywhere in the test suite where they are defined or imported. They can be created in Variable tables, imported from resource and variable files, or set during the test execution using the BuiltIn keyword Set Suite Variable.

The test suite scope is not recursive, which means that variables available in a higher-level test suite are not available in lower-level suites. If necessary, resource and variable files can be used for sharing variables.

Since these variables can be considered global in the test suite where they are used, it is recommended to use capital letters also with them.

Test case scope

Variables created in test cases from the return values of keywords have a test case scope and they are available only in that test case. Another possibility to create them is using the BuiltIn keyword Set Test Variable anywhere in that particular test case. Test case variables are local and should use lower-case letters.

User keyword scope

User keywords get their own variables from arguments passed to them and return values from the keywords they use. Also these variables are local and should use lower-case letters.

2.5.6   Advanced variable features

Extended variable syntax

Extended variable syntax can be used with objects set into scalar variables. It allows accessing the attributes of the object (for example, ${obj.name} or ${obj.some_attr}), and even calling its methods (for example, ${obj.get_name()} or ${obj.getSomething('arg')}).

Extended variable syntax is a powerful feature, but it should be used with care. Accessing attributes is normally not a problem, on the contrary, as one variable with an object having several attributes is often better than having several variables. On the other hand, calling methods, especially when they are used with arguments, can make the test data complicated. If that happens, it is recommended to move the code into a test library.

The most common usages of extended variable syntax are illustrated in the example below. First assume that we have the following variable file and test case:

class MyObject:

    def __init__(self, name):
        self.name = name

    def greet(self, who):
        return '%s says hello to %s' % (self.name, who)

    def __str__(self):
        return self.name

OBJECT = MyObject('Robot')
DICTIONARY = { 1: 'one', 2: 'two', 3: 'three'}
Test Case Action Argument Argument
Example KW 1 ${OBJECT.name}  
KW 2 ${OBJECT.greet('Fit')}  
KW 3 ${DICTIONARY[2]}  

When this test data is executed, the keywords get the arguments as explained below:

  • KW 1 gets string Robot
  • KW 2 gets string Robot says hello to Fit
  • KW 3 gets string two

The extended variable syntax is evaluated in the following order:

  1. The variable is searched using the full variable name. The extended variable syntax is evaluated only if no matching variable is found.
  2. The real name of the base variable is created. The body of the name consists of all the characters after ${ until the first occurrence of a non-alphanumeric character or a space (for example, OBJECT in ${OBJECT.name} and DICTIONARY in ${DICTIONARY[2]}).
  3. A variable matching the body is searched. If there is no match, an exception is raised and the test case fails.
  4. The expression inside the curly brackets is evaluated as a Python expression, so that the base variable name is replaced with its value. If the evaluation fails because of an invalid syntax or that the queried attribute does not exist, an exception is raised and the test fails.
  5. The whole extended variable is replaced with the value returned from the evaluation.

If the object that is used is implemented with Java, the extended variable syntax allows you to access attributes using so-called bean properties. In essence, this means that if you have an object with the getName method set into a variable ${OBJ}, then the syntax ${OBJ.name} is equivalent to, but clearer than ${OBJ.getName()}. Thus the Python object used in the previous example could be replaced with the following Java implementation:

public class MyObject:

    private String name;

    public MyObject(String name) {
        name = name;
    }

    public String getName() {
        return name;
    }

    public String greet(String who) {
        return name + " says hello to " + who;
    }

    public String toString() {
        return name;
    }
}

Many standard Python objects, including strings and numbers, have methods that can be used with the extended variable syntax either explicitly or implicitly. Sometimes this can be really useful and reduce the need for setting temporary variables, but it is also easy to overuse it and create really cryptic test data. Following examples show few pretty good usages.

Using methods of strings and numbers
Test Case Action Argument Argument
String ${string} = Set Variable abc
Log ${string.upper()} # Logs 'ABC'
Log ${string * 2} # Logs 'abcabc'
Number ${number} = Set Variable ${-2}
Log ${number * 10} # Logs -20
Log ${number.__abs__()} # Logs 2

Note that even though abs(number) is recommended over number.__abs__() in normal Python code, using ${abs(number)} does not work. This is because the variable name must be in the beginning of the extended syntax. Using __xxx__ methods in the test data like this is already a bit questionable, and it is normally better to move this kind of logic into test libraries.

Variables inside variables

Variables are allowed also inside variables, and when this syntax is used, variables are resolved from the inside out. For example, if you have a variable ${var${x}}, then ${x} is resolved first. If it has the value name, the final value is then the value of the variable ${varname}. There can be several nested variables, but resolving the outermost fails, if any of them does not exist.

In the example below, Do X gets the value ${JOHN HOME} or ${JANE HOME}, depending on if Get Name returns john or jane. If it returns something else, resolving ${${name} HOME} fails.

Using a variable inside another variable
Variable Value Value Value
${JOHN HOME} /home/john    
${JANE HOME} /home/jane    
Test Case Action Argument Argument
Example ${name} = Get Name  
Do X ${${name} HOME}  

2.6   Creating user keywords

Keyword tables are used to create new higher-level keywords by combining existing keywords together. These keywords are called user keywords to differentiate them from lowest level library keywords that are implemented in test libraries. The syntax for creating user keywords is very close to the syntax for creating test cases, which makes it easy to learn.

2.6.1   User keyword syntax

Basic syntax

In many ways, the overall user keyword syntax is identical to the test case syntax. User keywords are created in keyword tables which differ from test case tables only by the name that is used to identify them. User keyword names are in the first column similarly as test cases names. Also user keywords are created from keywords, either from keywords in test libraries or other user keywords. Keyword names are normally in the second column, but when setting variables from keyword return values, they are in the subsequent columns.

User keyword examples
Keyword Action Argument Argument
Open Login Page Open Browser http://host/login.html  
Title Should Be Login Page  
     
Title Should Start With [Arguments] ${expected}  
${title} = Get Title  
Should Start With ${title} ${expected}

Most user keywords take some arguments. This important feature is used already in the second example above, and it is explained in detail later in this section, similarly as user keyword return values.

User keywords can be created in test case files, resource files, and test suite initialization files. Keywords created in resource files are available for files using them, whereas other keywords are only available in the files where they are created.

Settings in the Keyword table

User keywords can have similar settings as test cases, and they have the same square bracket syntax separating them from keyword names. All available settings are listed below and explained later in this section.

[Documentation]
Used for setting a user keyword documentation.
[Arguments]
Specifies user keyword arguments.
[Return]
Specifies user keyword return values.
[Teardown]
Specify keyword teardown. Available from Robot Framework 2.6 onwards.
[Timeout]
Sets the possible user keyword timeout. Timeouts are discussed in a section of their own.

2.6.2   User keyword name and documentation

The user keyword name is defined in the first column of the user keyword table. Of course, the name should be descriptive, and it is acceptable to have quite long keyword names. Actually, when creating use-case-like test cases, the highest-level keywords are often formulated as sentences or even paragraphs.

User keywords can have a documentation that is set with the [Documentation] setting, exactly as test case documentation. This setting documents the user keyword in the test data. It is also shown in a more formal keyword documentation, which the libdoc.py tool can create from resource files. Finally, the first line of the documentation, everything until the first \n sequence, is shown as a keyword documentation in test logs.

Sometimes keywords need to be removed, replaced with new ones, or deprecated for other reasons. User keywords can be marked deprecated by starting the documentation with *DEPRECATED*, which will cause a warning when the keyoword is used. For more information, see Deprecating keywords section.

2.6.3   User keyword arguments

Most user keywords need to take some arguments. The syntax for specifying them is probably the most complicated feature normally needed with Robot Framework, but even that is relatively easy, particularly in most common cases. Arguments are normally specified with the [Arguments] setting, and argument names use the same syntax as variables, for example ${arg}.

Positional arguments

The simplest way to specify arguments (apart from not having them at all) is using only positional arguments. In most cases, this is all that is needed.

The syntax is such that first the [Arguments] setting is given and then argument names are defined in the subsequent cells. Each argument is in its own cell, using the same syntax as with variables. The keyword must be used with as many arguments as there are argument names in its signature. The actual argument names do not matter to the framework, but from users' perspective they should should be as descriptive as possible. It is recommended to use lower-case letters in variable names, either as ${my_arg}, ${my arg} or ${myArg}.

User keyword taking different number of arguments
Keyword Action Argument Argument Argument
One Argument [Arguments] ${arg_name}    
Log Got argument ${arg_name}    
       
Three Arguments [Arguments] ${arg1} ${arg2} ${arg3}
Log 1st argument: ${arg1}    
Log 2nd argument: ${arg2}    
Log 3rd argument: ${arg3}    

Default values

Positional arguments are probably sufficient in most situations. However, sometimes it is useful to be able to have a keyword that takes a different number of arguments and has default values for those that are not given. User keywords also allow this, and the needed new syntax does not add very much to the already discussed basic syntax. In short, default values are added to arguments, so that first there is the equals sign (=) and then the value, for example ${arg}=default. There can be many arguments with defaults, but they all must be given after the normal positional arguments.

Note

The syntax for default values is space sensitive. Spaces before the = sign are not allowed, and possible spaces after it are considered part of the default value itself.

User keyword with default values for arguments
Keyword Action Argument Argument
One Argument With Default Value [Arguments] ${arg}=default value  
[Documentation] This keyword takes 0-1 arguments
Log Got argument ${arg}  
     
Two Arguments With Defaults [Arguments] ${arg1}=default 1 ${arg2}=default 2
[Documentation] This keyword takes 0-2 arguments
Log 1st argument ${arg1}  
Log 2nd argument ${arg2}  
     
One Required And One With Default [Arguments] ${required} ${optional}=default
[Documentation] This keyword takes 1-2 arguments
Log Required: ${required}  
Log Optional: ${optional}  

When a keyword accepts several arguments with default values and only some of them needs to be overridden, it is often handy to use the named arguments syntax. When this syntax is used with user keywords, the arguments are specified without the ${} decoration. For example, the second keyword above could be used like below and ${arg1} would still get its default value.

User keyword and named arguments syntax
Test Case Action Argument Argument
Example Two Arguments With Defaults arg2=new value  

As all Pythonistas must have already noticed, the syntax for specifying default arguments is heavily inspired by Python syntax for function default values.

Variable number of arguments

Sometimes even default values are not enough and there is a need for a keyword accepting any number of arguments. User keywords support also this. All that is needed is having list variable such as @{varargs} as the last argument in the keyword signature. This syntax can be combined with the previously described positional arguments and default values, and at the end the list variable gets all the leftover arguments that do not match other arguments. The list variable can thus have any number of items, even zero.

User keywords accepting variable number of arguments
Keyword Action Argument Argument Argument
Any Number Of Arguments [Arguments] @{varargs}    
Log Many @{varargs}    
       
One Or More Arguments [Arguments] ${required} @{rest}  
Log Many ${required} @{rest}  
       
Required, Default, Varargs [Arguments] ${req} ${opt}=42 @{others}
Log Required: ${req}    
Log Optional: ${opt}    
Log Others:    
: FOR ${item} IN @{others}
  Log ${item}  

Notice that if the last keyword above is used with more than one argument, the second argument ${opt} always gets the given value instead of the default value. This happens even if the given value is empty. The last example also illustrates how a variable number of arguments accepted by a user keyword can be used in a for loop. This combination of two rather advanced functions can sometimes be very useful.

Again, Pythonistas probably notice that the variable number of arguments syntax is very close to the one in Python.

2.6.4   Embedding arguments into keyword name

Robot Framework has also another approach to pass arguments to user keywords than specifying them in cells after the keyword name as explained in the previous section. This method is based on embedding the arguments directly into the keyword name, and its main benefit is making it easier to use real and clear sentences as keywords.

Basic syntax

It has always been possible to use keywords like Select dog from list and Selects cat from list, but all such keywords must have been implemented separately. The idea of embedding arguments into the keyword name is that all you need is a keyword with name like Select ${animal} from list.

An example keyword with arguments embedded into its name
Keyword Action Argument Argument
Select ${animal} from list Open Page Pet Selection  
Select Item From List animal_list ${animal}

Keywords using embedded arguments cannot take any "normal" arguments (specified with [Arguments] setting) but otherwise they are created just like other user keywords. The arguments used in the name will naturally be available inside the keyword and they have different value depending on how the keyword is called. For example, ${animal} in the previous has value dog if the keyword is used like Select dog from list. Obviously it is not mandatory to use all these arguments inside the keyword, and they can thus be used as wildcards.

These kind of keywords are also used the same way as other keywords except that spaces and underscores are not ignored in their names. They are, however, case-insensitive like other keywords. For example, the keyword in the example above could be used like select x from list, but not like Select x fromlist.

Embedded arguments do not support default values or variable number of arguments like normal arguments do. Using variables when calling these keywords is possible but that can reduce readability. Notice also that embedded arguments only work with user keywords.

Embedded arguments matching too much

One tricky part in using embedded arguments is making sure that the values used when calling the keyword match the correct arguments. This is a problem especially if there are multiple arguments and characters separating them may also appear in the given values. For example, keyword Select ${city} ${team} does not work correctly if used with city containing too parts like Select Los Angeles Lakers.

An easy solution to this problem is quoting the arguments (e.g. Select "${city}" "${team}") and using the keyword in quoted format (e.g. Select "Los Angeles" "Lakers"). This approach is not enough to resolve all this kind of conflicts, though, but it is still highly recommended because it makes arguments stand out from rest of the keyword. A more powerful but also more complicated solution, using custom regular expressions when defining variables, is explained in the next section. Finally, if things get complicated, it might be a better idea to use normal positional arguments instead.

The problem of arguments matching too much occurs often when creating keywords that ignore given/when/then/and prefixes . For example, ${name} goes home matches Given Janne goes home so that ${name} gets value Given Janne. Quotes around the argument, like in "${name}" goes home, resolve this problem easily.

Using custom regular expressions

When keywords with embedded arguments are called, the values are matched internally using regular expressions (regexps for short). The default logic goes so that every argument in the name is replaced with a pattern .*? that basically matches any string. This logic works fairly well normally, but as just discussed above, sometimes keywords match more than intended. Quoting or otherwise separating arguments from the other text can help but, for example, the test below fails because keyword I execute "ls" with "-lh" matches both of the defined keywords.

Embedded arguments match too much
Test Case Step
Example I execute "ls"
I execute "ls" with "-lh"
Keyword Action Argument Argument
I execute "${cmd}" Run ${cmd}  
I execute "${cmd}" with "${opts}" Run ${cmd} ${opts}  

A solution to this problem is using a custom regular expression that makes sure that the keyword matches only what it should in that particular context. To be able to use this feature, and to fully understand the examples in this section, you need to understand at least the basics of the regular expression syntax.

A custom embedded argument regular expression is defined after the base name of the argument so that the argument and the regexp are separated with a colon. For example, an argument that should match only numbers can be defined like ${arg:\d+}. Using custom regular expressions is illustrated by the examples below.

Using custom regular expressions with embedded arguments
Test Case Step
Example I execute "ls"
I execute "ls" with "-lh"
I type 1 + 2
I type 53 - 11
Today is 2011-06-27
Keyword Action Argument Argument Argument
I execute "${cmd:[^"]+}" Run ${cmd}    
I execute "${cmd}" with "${opts}" Run ${cmd} ${opts}    
I type ${a:\d+} ${operator:[+-]} ${b:\d+} Calculate ${a} ${operator} ${b}
Today is ${date:\d{4\}-\d{2\}-\d{2\}} Log ${date}    

In the above example keyword I execute "ls" with "-lh" matches only I execute "${cmd}" with "${opts}". That is guaranteed because the custom regular expression [^"]+ in I execute "${cmd:[^"]}" means that a matching argument cannot contain any quotes. In this case there is no need to add custom regexps to the other I execute variant.

Tip

If you quote arguments, using regular expression [^"]+ guarantees that the argument matches only until the first closing quote.

Supported regular expression syntax

Being implemented with Python, Robot Framework naturally uses Python's re module that has pretty standard regular expressions syntax. This syntax is otherwise fully supported with embedded arguments, but regexp extensions in format (?...) cannot be used. Notice also that matching embedded arguments is done case-insensitively. If the regular expression syntax is invalid, creating the keyword fails with an error visible in test execution errors.

Escaping special characters

There are some special characters that need to be escaped when used in the custom embedded arguments regexp. First of all, possible closing curly braces (}) in the pattern need to be escaped with a single backslash (\}) because otherwise the argument would end already there. Escaping closing burly braces is illustrated in the previous example with keyword Today is ${date:\d{4\}-\d{2\}-\d{2\}}.

Backslash (\) is a special character in Python regular expression syntax and thus needs to be escaped if you want to have a literal backslash character. The safest escape sequence in this case is four backslashes (\\\\) but, depending on the next character, also two backslashes may be enough.

Notice also that keyword names and possible embedded arguments in them should not be escaped using the normal test data escaping rules. This means that, for example, backslashes in expressions like ${name:\w+} should not be escaped.

Using variables with custom embedded argument regular expressions

Whenever custom embedded argument regular expressions are used, Robot Framework automatically enhances the specified regexps so that they match variables in addition to the text matching the pattern. This means that it is always possible to use variables with keywords having embedded arguments. For example, the following test case would pass using the keywords from the earlier example.

Using variables with custom regular expressions
Variable Value
${DATE} 2011-06-27
Test Case Step
Example I type ${1} + ${2}
Today is ${DATE}

A drawback of variables automatically matching custom regular expressions is that it is possible that the value the keyword gets does not actually match the specified regexp. For example, variable ${DATE} in the above example could contain any value and Today is ${DATE} would still match the same keyword.

Behavior-driven development example

The biggest benefit of having arguments as part of the keyword name is that it makes it easier to use higher-level sentence-like keywords when writing test cases in behavior-driven style. The example below illustrates this. Notice also that prefixes Given, When and Then are left out of the keyword definitions.

Embedded arguments used by BDD style tests
Test Case Step
Add two numbers Given I have Calculator open
When I add 2 and 40
Then result should be 42
 
Add negative numbers Given I have Calculator open
When I add 1 and -2
Then result should be -1
Keyword Action Argument Argument
I have ${program} open Start Program ${program}  
     
I add ${number 1} and ${number 2} Input Number ${number 1}  
Push Button +  
Input Number ${number 2}  
Push Button =  
     
Result should be ${expected} ${result} = Get Result  
Should Be Equal ${result} ${expected}

Note

Embedded arguments feature in Robot Framework is inspired by how step definitions are created in a popular BDD tool called Cucumber.

2.6.5   User keyword return values

Similarly as library keywords, also user keywords can return values. Return values are defined with the [Return] setting. The values can then be assigned to variables in test cases or other user keywords.

In a typical case, a user keyword returns one value and it can be set to a scalar variable. This is done by having the return value in the next cell after the [Return] setting. User keywords can also return several values, which can then be assigned into several scalar variables at once, to a list variable, or to scalar variables and a list variable. Several values can be returned simply by specifying those values in different cells after the [Return] setting.

User keywords returning values
Test Case Action Argument Argument Argument
One Return Value ${ret} = Return One Value argument  
Some Keyword ${ret}    
       
Multiple Values ${a} ${b} ${c} = Return Three Values
@{list} = Return Three Values    
${scalar} @{rest} = Return Three Values  
Keyword Action Argument Argument Argument
Return One Value [Arguments] ${arg}    
Do Something ${arg}    
${value} = Get Some Value    
[Return] ${value}    
       
Return Three Values [Return] foo bar zap

2.6.6   Keyword teardown

Starting from Robot Framework 2.6, also user keywords may have a teardown. It is defined using [Teardown] setting.

Keyword teardown works much in the same way as a test case teardown. Most importantly, the teardown is always a single keyword, although it can be another user keyword, and it gets executed also when the user keyword fails. In addition, all steps of the teardown are executed even if one of them fails. However, a failure in keyword teardown will fail the test case and subsequent steps in the test are not run. The name of the keyword to be executed as a teardown can also be a variable.

User Keyword Action Argument Argument
With Teardown Do Something    
[Teardown] Log keyword teardown
     
Using variables [Documentation] Teardown given as variable
Do Something    
[Teardown] ${TEARDOWN}  

2.7   Resource and variable files

User keywords and variables in test case files and test suite initialization files can only be used in files where they are created, but resource files provide a mechanism for sharing them. Since the resource file structure is very close to test case files, it is easy to create them.

Variable files provide a powerful mechanism for creating and sharing variables. For example, they allow values other than strings and enable creating variables dynamically. Their flexibility comes from the fact that they are created using Python code, which also makes them somewhat more complicated than Variable tables.

2.7.1   Resource files

Taking resource files into use

Resource files are imported using the Resource setting in the Settings table. The path to the resource file is given in the cell after the setting name.

If the path is given in an absolute format, it is used directly. In other cases, the resource file is first searched relatively to the directory where the importing file is located. If the file is not found there, it is then searched from the directories in PYTHONPATH. The path can contain variables, and it is recommended to use them to make paths system-independent (for example, ${RESOURCES}/login_resources.html or ${RESOURCE_PATH}). Additionally, slashes ("/") in the path are automatically changed to backslashes ("\") on Windows.

Importing resource files
Setting Value Value
Resource myresources.html  
Resource ../data/resources.html  
Resource ${RESOURCES}/common.tsv  

The user keywords and variables defined in a resource file are available in the file that takes that resource file into use. Similarly available are also all keywords and variables from the libraries, resource files and variable files imported by the said resource file.

Resource file structure

The higher-level structure of resource files is the same as that of test case files otherwise, but, of course, they cannot contain Test Case tables. Additionally, the Setting table in resource files can contain only import settings (Library, Resource, Variables) and Documentation. The Variable table and Keyword table are used exactly the same way as in test case files.

If several resource files have a user keyword with the same name, they must be used so that the keyword name is prefixed with the resource file name without the extension (for example, myresources.Some Keyword and common.Some Keyword). Moreover, if several resource files contain the same variable, the one that is imported first is taken into use.

Documenting resource files

Keywords created in a resource file can be documented using [Documentation] setting. Starting from Robot Framework 2.1 also the resource file itself can have Documentation in the Setting table similarly as test suites.

Both libdoc.py and RIDE use these documentations, and they are naturally available for anyone opening resource files. The first line of the documentation of a keyword is logged when it is run, but otherwise resource file documentations are ignored during the test execution.

Example resource file

Setting Value Value Value
Documentation An example resource file    
Library SeleniumLibrary    
Resource ${RESOURCES}/common.html    
Variable Value Value Value
${HOST} localhost:7272    
${LOGIN_URL} http://${HOST}/    
${WELCOME_URL} http://${HOST}/welcome.html    
${BROWSER} Firefox    
Keyword Action Argument Argument Argument
Open Login Page [Documentation] Opens browser to login page  
Open Browser ${LOGIN_URL} ${BROWSER}  
Title Should Be Login Page    
       
Input Name [Arguments] ${name}    
Input Text username_field ${name}  
       
Input Password [Arguments] ${password}    
Input Text password_field ${password}  

2.7.2   Variable files

Variable files contain variables that can be used in test data. Variables can also be created using variable tables or set from the command line, but variable files allow creating them dynamically and their variables can contain any objects.

Variable files are created using the Python code, and technically they are Python modules. There are two different possibilities for creating variables:

Creating variables directly
Variables are specified as module attributes. In simple cases, the syntax is so simple that no real programming is needed. For example, MY_VAR = 'my value' creates a variable ${MY_VAR} with the specified text as the value.
Getting variables from a special function
Alternatively, variable files can have a special get_variables (or getVariables) method that returns variables as either a Python dictionary or a Java Map. This method can even take arguments, which makes this approach quite flexible.

Taking variable files into use

Setting table

All test data files can import variables using the Variables setting in the Setting table, in the same way as resource files are imported using the Resource setting. Similarly to resource files, the path to the imported variable file is considered relative to the directory where the importing file is, and if not found, it is searched from the directories in PYTHONPATH. The path can also contain variables, and slashes are converted to backslashes on Windows. If an argument file takes arguments, they are specified in the cells after the path and also they can contain variables.

Importing a variable file
Setting Value Value Value
Variables myvariables.py    
Variables ../data/variables.py    
Variables ${RESOURCES}/common.py    
Variables taking_arguments.py arg1 ${ARG2}

All variables from a variable file are available in the test data file that imports it. If several variable files are imported and they contain a variable with the same name, the one in the earliest imported file is taken into use. Additionally, variables created in Variable tables and set from the command line override variables from variable files.

Command line

Another way to take variable files into use is using the command line option --variablefile. Variable files are referenced using a path to them, and possible arguments are joined to the path with a colon (:):

--variablefile myvariables.py
--variablefile path/variables.py
--variablefile /absolute/path/common.py
--variablefile taking_arguments.py:arg1:arg2

Variables in these files are globally available in all test data files, similarly as individual variables set with the --variable option. If both --variablefile and --variable options are used and there are variables with same names, those that are set individually with --variable option take precedence.

Creating variables directly

Basic syntax

When variable files are taken into use, they are imported as Python modules and all their global attributes that do not start with an underscore (_) are considered to be variables. Because variable names are case-insensitive, both lower- and upper-case names are possible, but in general, capital letters are recommended for global variables and attributes.

VARIABLE = "An example string"
ANOTHER_VARIABLE = "This is pretty easy!"
INTEGER = 42
STRINGS = ["one", "two", "kolme", "four"]
NUMBERS = [1, INTEGER, 3.14]

In the example above, variables ${VARIABLE}, ${ANOTHER_VARIABLE}, and so on, are created. The first two variables are strings, the third one is an integer and the last two are lists. All these variables are scalar variables, even the ones containing lists as values. To create list variables, the variable name must be prefixed with LIST__ (note the two underscores).

LIST__STRINGS = ["list", "of", "strings"]
LIST__MIXED = ["first value", -1.1, None, True]

The variables in both the examples above could be created also using the Variable table below.

Variable Value Value Value Value
${VARIABLE} An example string      
${ANOTHER_VARIABLE} This is pretty easy!      
${INTEGER} ${42}      
${STRINGS} one two kolme four
${NUMBERS} ${1} ${INTEGER} ${3.14}  
@{STRINGS} list of strings  
@{MIXED} first value ${-1.1} ${None} ${True}
Using objects as values

Variables in variable files are not limited to having only strings or other base types as values like variable tables. Instead, their variables can contain any objects. In the example below, the variable ${MAPPING} contains a Java hashtable with two values (this example works only when running tests on Jython).

from java.util import Hashtable

MAPPING = Hashtable()
MAPPING.put("one", 1)
MAPPING.put("two", 2)

The second example creates ${MAPPING} as a Python dictionary and also has two variables created from a custom object implemented in the same file.

MAPPING = {'one': 1, 'two': 2}

class MyObject:
    def __init__(self, name):
        self.name = name

OBJ1 = MyObject('John')
OBJ2 = MyObject('Jane')
Creating variables dynamically

Because variable files are created using a real programming language, they can have dynamic logic for setting variables.

import os
import random
import time

USER = os.getlogin()                # current login name
RANDOM_INT = random.randint(0, 10)  # random integer in range [0,10]
CURRENT_TIME = time.asctime()       # timestamp like 'Thu Apr  6 12:45:21 2006'
if time.localtime()[3] > 12:
    AFTERNOON = True
else:
    AFTERNOON = False

The example above uses standard Python libraries to set different variables, but you can use your own code to construct the values. The example below illustrates the concept, but similarly, your code could read the data from a database, from an external file or even ask it from the user.

import math

def get_area(diameter):
    radius = diameter / 2
    area = math.pi * radius * radius
    return area

AREA1 = get_area(1)
AREA2 = get_area(2)
Selecting which variables to include

When Robot Framework processes variable files, all their attributes that do not start with an underscore are expected to be variables. This means that even functions or classes created in the variable file or imported from elsewhere are considered variables. For example, the last example would contain the variables ${math} and ${get_area} in addition to ${AREA1} and ${AREA2}.

Normally the extra variables do not cause problems, but they could override some other variables and cause hard-to-debug errors. One possibility to ignore other attributes is prefixing them with an underscore:

import math as _math

def _get_area(diameter):
    radius = diameter / 2.0
    area = _math.pi * radius * radius
    return area

AREA1 = _get_area(1)
AREA2 = _get_area(2)

If there is a large number of other attributes, instead of prefixing them all, it is often easier to use a special attribute __all__ and give it a list of attribute names to be processed as variables.

import math

__all__ = ['AREA1', 'AREA2']

def get_area(diameter):
    radius = diameter / 2.0
    area = math.pi * radius * radius
    return area

AREA1 = get_area(1)
AREA2 = get_area(2)

Note

The __all__ attribute is also, and originally, used by Python to decide which attributes to import when using the syntax from modulename import *.

Getting variables from a special function

An alternative syntax for getting variables is having a special get_variables function (also camelCase syntax getVariables is possible) in the variable file. In this case, Robot Framework calls that function and it returns variables as a Python dictionary or its subclass or a Java Map, with variable names as keys and variable values as values. (Note: Prior to Robot Framework 2.5 only Python dictionaries were supported.) Variables are considered to be scalars, unless prefixed with LIST__, and values can contain anything. The example below is identical to the first examples of creating variables directly.

def get_variables():
    variables = { "VARIABLE ": "An example string",
                  "ANOTHER_VARIABLE": "This is pretty easy!",
                  "INTEGER": 42,
                  "STRINGS": ["one", "two", "kolme", "four"],
                  "NUMBERS": [1, 42, 3.14],
                  "LIST__STRINGS": ["list", "of", "strings"],
                  "LIST__MIXED": ["first value", -1.1, None, True] }
    return variables

get_variables can also take arguments, which facilitates changing what variables actually are created. Arguments to the function are set just as any other arguments for a Python function. When taking variable files into use in the test data, arguments are specified in cells after the path to the variable file, and in the command line they are separated from the path with a colon.

The dummy example below shows how to use arguments with variable files. In a more realistic example, the argument could be a path to an external text file or database where to read variables from.

variables1 = { 'scalar': 'Scalar variable',
               'LIST__list': ['List','variable'] }
variables2 = { 'scalar' : 'Some other value',
               'LIST__list': ['Some','other','value'],
               'extra': 'variables1 does not have this at all' }

def get_variables(arg):
    if arg == 'one':
        return variables1
    else:
        return variables2

The most notable benefit of using get_variables instead of defining variables directly as global attributes of the variable file is the ability to use arguments. On the other hand, the main drawback is that this approach always requires some actual programming.

2.8   Advanced features

2.8.1   Handling keywords with same names

Keywords that are used with Robot Framework are either library keywords or user keywords. The former come from standard libraries or external libraries, and the latter are either created in the same file where they are used or then imported from resource files. When many keywords are in use, it is quite common that some of them have the same name, and this section describes how to handle possible conflicts in these situations.

Keyword scopes

When only a keyword name is used and there are several keywords with that name, Robot Framework attempts to determine which keyword has the highest priority based on its scope. The keyword's scope is determined on the basis of how the keyword in question is created:

  1. Created as a user keyword in the same file where it is used. These keywords have the highest priority and they are always used, even if there are other keywords with the same name elsewhere.
  2. Created in a resource file and imported either directly or indirectly from another resource file. This is the second-highest priority.
  3. Created in an external test library. These keywords are used, if there are no user keywords with the same name. However, if there is a keyword with the same name in the standard library, a warning is displayed.
  4. Created in a standard library. These keywords have the lowest priority.

Specifying a keyword explicitly

Scopes alone are not a sufficient solution, because there can be keywords with the same name in several libraries or resources, and thus, they provide a mechanism to use only the keyword of the highest priority. In such cases, it is possible to use the full name of the keyword, where the keyword name is prefixed with the name of the resource or library and a dot is a delimiter.

With library keywords, the long format means only using the format LibraryName.Keyword Name. For example, the keyword Run from the OperatingSystem library could be used as OperatingSystem.Run, even if there was another Run keyword somewhere else. If the library is in a module or package, the full module or package name must be used (for example, com.company.Library.Some Keyword). If a custom name is given to a library using the WITH NAME syntax, the specified name must be used also in the full keyword name.

Resource files are specified in the full keyword name, similarly as library names. The name of the resource is derived from the basename of the resource file without the file extension. For example, the keyword Example in a resource file myresources.html can be used as myresources.Example. Note that this syntax does not work, if several resource files have the same basename. In such cases, either the files or the keywords must be renamed. The full name of the keyword is case-, space- and underscore-insensitive, similarly as normal keyword names.

Specifying explicit priority between libraries and resources

If there are multiple conflicts between keywords, specifying all the keywords in the long format can be quite a lot work. Using the long format also makes it impossible to create dynamic test cases or user keywords that work differently depending on which libraries or resources are available. A solution to both of these problems is specifying the keyword priorities explicitly using the keyword Set Library Search Order from the BuiltIn library.

Note

Although the keyword has the word library in its name, it works also with resource files starting from Robot Framework 2.6.2. As discussed above, keywords in resources always have higher priority than keywords in libraries, though.

The Set Library Search Order accepts an ordered list or libraries and resources as arguments. When a keyword name in the test data matches multiple keywords, the first library or resource containing the keyword is selected and that keyword implementation used. If the keyword is not found from any of the specified libraries or resources, execution fails for conflict the same way as when the search order is not set.

For more information and examples, see the documentation of the keyword.

2.8.2   Timeouts

Keywords may be problematic in situations where they take exceptionally long to execute or just hang endlessly. Robot Framework allows you to set timeouts both for test cases and user keywords, and if a test or keyword is not finished within the specified time, the keyword that is currently being executed is forcefully stopped. Stopping keywords in this manner may leave the library or system under test to an unstable state, and timeouts are recommended only when there is no safer option available. In general, libraries should be implemented so that keywords cannot hang or that they have their own timeout mechanism, if necessary.

Test case timeout

The test case timeout can be set either by using the Test Timeout setting in the Setting table or the [Timeout] setting in the Test Case table. Test Timeout in the Setting table defines a default test timeout value for all the test cases in the test suite, whereas [Timeout] in the Test Case table applies a timeout to an individual test case and overrides the possible default value.

Using an empty [Timeout] means that the test has no timeout even when Test Timeout is used. Starting from Robot Framework 2.5.6, it is also possible to use value NONE for this purpose.

Regardless of where the test timeout is defined, the first cell after the setting name contains the duration of the timeout. The duration must be given in Robot Framework's time format, that is, either directly in seconds or in a format like 1 minute 30 seconds. It must be noted that there is always some overhead by the framework, and timeouts shorter than one second are thus not recommended.

The default error message displayed when a test timeout occurs is Test timeout <time> exceeded. It is also possible to use custom error messages, and these messages are written into the cells after the timeout duration. The message can be split into multiple cells, similarly as documentations. Both the timeout value and the error message may contain variables.

If there is a timeout, the keyword running is stopped at the expiration of the timeout and the test case fails. However, keywords executed as test teardown are not interrupted if a test timeout occurs, because they are normally engaged in important clean-up activities. If necessary, it is possible to interrupt also these keywords with user keyword timeouts.

Test timeout examples
Setting Value Value Value
Test Timeout 2 minutes    
Test Case Action Argument Argument Argument
Default Timeout [Documentation] Timeout from the Setting table is used    
Some Keyword argument    
       
Override [Documentation] Override default, use 10 seconds timeout    
[Timeout] 10    
Some Keyword argument    
       
Custom Message [Documentation] Override default and use custom message    
[Timeout] 1min 10s This is my custom error. It continues here.
Some Keyword argument    
       
Variables [Documentation] It is possible to use variables too    
[Timeout] ${TIMEOUT}    
Some Keyword argument    
       
No Timeout [Documentation] Empty timeout means no timeout even when Test Timeout has been used  
[Timeout]      
Some Keyword argument    
       
No Timeout 2 [Documentation] Empty timeout using NONE, works with 2.5.6  
[Timeout] NONE    
Some Keyword argument    

User keyword timeout

A timeout can be set for a user keyword using the [Timeout] setting in the Keyword table. The syntax for setting it, including how timeout values and possible custom messages are given, is identical to the syntax used with test case timeouts. If no custom message is provided, the default error message Keyword timeout <time> exceeded is used if a timeout occurs.

User keyword timeout examples
Keyword Action Argument Argument
Timed Keyword [Documentation] Set only the timeout value and not the custom message.
[Timeout] 1 minute 42 seconds  
Do Something    
Do Something Else    
     
Timed-out Wrapper [Arguments] @{args}  
[Documentation] This keyword is a wrapper that adds a timeout to another keyword.
[Timeout] 2 minutes Original Keyword didn't finish in 2 minutes
Original Keyword @{args}  

A user keyword timeout is applicable during the execution of that user keyword. If the total time of the whole keyword is longer than the timeout value, the currently executed keyword is stopped. User keyword timeouts are applicable also during a test case teardown, whereas test timeouts are not.

If both the test case and some of its keywords (or several nested keywords) have a timeout, the active timeout is the one with the least time left.

Warning

Using timeouts might cause test to be executed slower if the Python interpreter is used. The slowing down is caused by Python's threading implementation. For more information see issue 497.

2.8.3   For loops

Repeating same actions several times is quite a common need in test automation. With Robot Framework, test libraries can have any kind of loop constructs, and most of the time loops should be implemented in them. Robot Framework also has its own For loop syntax, which is useful, for example, when there is a need to repeat keywords from different libraries.

For loops can be used with both test cases and user keywords. Except for really simple cases, user keywords are better, because they hide the complexity introduced by for loops. The basic for loop syntax, FOR item IN sequence, is derived from Python, but similar syntax is possible also in shell scripts or Perl.

Normal for loop

In a normal For loop, one variable is assigned from a list of values, one value per iteration. The syntax starts with :FOR, where colon is required to separate the syntax from normal keywords. The next cell contains the loop variable, the subsequent cell must have IN, and the final cells contain values over which to iterate.

The keywords used in the For loop are on the next rows and they must be indented one cell to the right. The For loop ends when the indentation returns back to normal or the table ends. Having nested For loops directly is not supported, but it is possible to use a user keyword inside a For loop and have another For loop there.

Simple for loops
Test Case Action Argument Argument Argument Arguments
Example 1 :FOR ${animal} IN cat dog
  Log ${animal}    
  Log 2nd keyword    
Log Outside loop      
         
Example 2 :FOR ${var} IN one two
... three four five six
... seven      
  Log ${var}    

The For loop in Example 1 above is executed twice, so that first the loop variable ${animal} has the value cat and then dog. The loop consists of two Log keywords. In the second example, loop values are split into several rows and the loop is run altogether seven times.

Tip

If you use for loops in the plain text format, remember to escape the indented cell using a backslash:

*** Test Case ***
Example 1
    :FOR    ${animal}    IN    cat    dog
    \    Log    ${animal}
    \    Log    2nd keyword
    Log    Outside loop

For loops are most useful and also clearest when they are used with list variables. This is illustrated by the example below, where @{ELEMENTS} contains an arbitrarily long list of element names and keyword Start Element is used with all of them.

For loop with a list variable
Test Case Action Argument Argument Argument Arguments
Example :FOR ${element} IN @{ELEMENTS}  
  Start Element ${element}    

Using several loop variables

It is also possible to use several loop variables. The syntax is the same as with the normal For loop, but all loop variables are listed in the cells between :FOR and IN. There can be any number of loop variables, but the number of values must be evenly dividable by the number of variables.

This syntax naturally works both with and without list variables. In the former case, it is often possible to organize loop values below loop variables, as in the first part of the example below:

Using multiple loop variables
Test Case Action Argument Argument Argument Arguments
Example :FOR ${index} ${english} ${finnish} IN
... 1 cat kissa  
... 2 dog koira  
... 3 horse hevonen  
  Do X ${english}    
  Y Should Be ${finnish} ${index}  
:FOR ${name} ${id} IN @{EMPLOYERS}
  Create ${name} ${id}  

For in range

Earlier For loops always iterated over a sequence, and this is also the most common use case. Sometimes it is still convenient to have a For loop that is executed a certain number of times, and Robot Framework has a special FOR index IN RANGE limit syntax for this purpose. This syntax is derived from the similar Python idiom.

Similarly as other For loops, the For in range loop starts with :FOR and the loop variable is in the next cell. In this format there can be only one loop variable and it contains the current loop index. The next cell must contain IN RANGE and the subsequent cells loop limits.

In the simplest case, only the upper limit of the loop is specified. In this case, loop indexes start from zero and increase by one until, but excluding, the limit. It is also possible to give both the start and end limits. Then indexes start from the start limit, but increase similarly as in the simple case. Finally, it is possible to give also the step value that specifies the increment to use. If the step is negative, it is used as decrement.

Starting from Robot Framework 2.5.5, it is possible to use simple arithmetics such as addition and subtraction with the range limits. This is especially useful when the limits are specified with variables.

For in range examples
Test Case Action Argument Argument Arg Arg Arg
Only upper limit [Documentation] Loops over values from 0 to 9  
:FOR ${index} IN RANGE 10    
  Log ${index}      
           
Start and end [Documentation] Loops over values from 1 to 10  
:FOR ${index} IN RANGE 1 11  
  Log ${index}      
           
Also step given [Documentation] Loops over values 5, 15, and 25  
:FOR ${index} IN RANGE 5 26 10
  Log ${index}      
           
Negative step [Documentation] Loops over values 13, 3, and -7  
:FOR ${index} IN RANGE 13 -13 -10
  Log ${index}      
           
Arithmetics [Documentation] Arithmetics with variable    
:FOR ${index} IN RANGE ${var}+1    
  Log ${index}      

Exiting for loop

Normally for loop is executed until all the elements of the loop have been looped through or an error occurs and the test case or keyword fails. However sometimes execution of a for loop needs to be stopped before all elements of the loop have been gone through. BuiltIn keyword Exit For Loop can be used to exit the enclosing for loop.

Exit For Loop keyword can be used directly in a for loop or in a keyword that the for loop uses. In both cases the test execution continues after the for loop. If executed outside of a for loop, the test fails.

Exit for loop example
Test Case Action Argument Argument Argument
Exit Example :FOR ${var} IN @{SOME LIST}
  Run Keyword If '${var}' == 'EXIT' Exit For Loop
  Do Something ${var}  

Exiting a for loop can also be initiated from a keyword in a test library by raising an exception with ROBOT_EXIT_FOR_LOOP attribute. Please see Stopping test execution for examples how to do this in Python and Java libraries.

Note

Exit for loop functionality is new in Robot Framework 2.5.2.

Repeating single keyword

For loops can be excessive in situations where there is only a need to repeat a single keyword. In these cases it is often easier to use BuiltIn keyword Repeat Keyword. This keyword takes a keyword and how many times to repeat it as arguments. The times to repeat the keyword can have an optional postfix times or x to make the syntax easier to read.

Repeat Keyword examples
Test Case Action Argument Argument Argument Argument
Example Repeat Keyword 5 Some Keyword arg1 arg2
Repeat Keyword 42 times My Keyword    
Repeat Keyword ${var} Another KW argument  

Robot Framework also had a special syntax for repeating a single keyword. This syntax was deprecated in the 2.0.4 version in favor of Repeat Keyword and it was removed in the 2.5 version.

2.8.4   Conditional execution

In general, it is not recommended to have conditional logic in test cases, or even in user keywords, because it can make them hard to understand and maintain. Instead, this kind of logic should be in test libraries, where it can be implemented using natural programming language constructs. However, some conditional logic can be useful at times, and even though Robot Framework does not have an actual if/else construct, there are several ways to get the same effect.

  • The name of the keyword used as a setup or a teardown of both test cases and test suites can be specified using a variable. This facilitates changing them, for example, from the command line.
  • The BuiltIn keyword Run Keyword takes a keyword to actually execute as an argument, and it can thus be a variable. The value of the variable can, for example, be got dynamically from an earlier keyword or given from the command line.
  • The BuiltIn keywords Run Keyword If and Run Keyword Unless execute a named keyword only if a certain expression is true or false, respectively. They are ideally suited to creating simple if/else constructs. For an example, see the documentation of the former.
  • Another BuiltIn keyword, Set Variable If, can be used to set variables dynamically based on a given expression.
  • There are several BuiltIn keywords that allow executing a named keyword only if a test case or test suite has failed or passed.

2.8.5   Parallel execution of keywords

Prior to the 2.5 version Robot Framework a had special syntax for executing keywords in parallel. This functionality was removed because it was rarely used and it never worked fully.

When parallel execution is needed, it must be implemented in test library level so that the library executes the code on background. Typically this means that the library needs a keyword like Start Something that starts the execution and returns immediately, and another keyword like Get Results From Something that waits until the result is available and returns it. See OperatingSystem library keywords Start Process and Read Process Output for an example.

3   Executing test cases

3.1   Basic usage

Robot Framework test cases are executed from the command line, and the end result is, by default, an output file in XML format and an HTML report and log. After the execution, output files can be combined and otherwise post-processed with the rebot tool.

3.1.1   Starting test execution

Synopsis

pybot [options] datasources
jybot [options] datasources
interpreter /path/to/robot/runner.py [options] datasources
java -jar robotframework-<version>.jar [options] datasources

Different runner scripts

Test execution is normally started with the pybot or jybot commands. These commands are otherwise identical, but the former executes tests using the Python interpreter and the latter uses Jython. Which one to use depends on the needed test libraries. Some libraries use modules or syntax available only on Python, others use Java-based tools that require Jython, and some work on both. If you can use either pybot or jybot, the former is recommended, as Python is somewhat faster than Jython.

Starting from Robot Framework 2.5.2, it is also possible to get Robot Framework as a single jar file. In this case, Jython is bundled inside the jar, and the above discussion about Jython applies. Normal arguments to Robot Framework are given after the jar file name.

Another possibility for starting the test execution is running the runner.py script under the installed robot module directly. This method allows selecting the interpreter and setting command line options to it freely. The most common use case is altering the options controlling JVM maximum memory consumption.

Regardless of the runner script, the path (or paths) to the test data to be executed is given as an argument. Additionally, different command line options can be used to alter the test execution or generated outputs in some way.

Specifying test data to be executed

Robot Framework test cases are created in files and directories, and they are executed by giving the path to the file or directory in question to the selected runner script. The path can be absolute or, more commonly, relative to the directory where tests are executed from. The given file or directory creates the top-level test suite, which gets its name, unless overridden with the --name option, from the file or directory name. Different execution possibilities are illustrated in the examples below. Note that in these examples, as well as in other examples in this section, only the pybot command is used, but jybot or a custom runner script could be used similarly.

pybot test_cases.html
pybot path/to/my_tests/
pybot c:\robot\tests.txt

It is also possible to give paths to several test case files or directories at once, separated with spaces. In this case, Robot Framework creates the top-level test suite automatically, and the specified files and directories become its child test suites. The name of the created test suite is got from child suite names by catenating them together with an ampersand (&) and spaces. For example, the name of the top-level suite in the first example below is My Tests & Your Tests. These automatically created names are often quite long and complicated. In most cases, it is thus better to use the --name option for overriding it, as in the second example below:

pybot my_tests.html your_tests.html
pybot --name Example path/to/tests/pattern_*.html

3.1.2   Using command line options

Robot Framework provides a number of command line options that can be used to control how test cases are executed and what outputs are generated. This section explains the option syntax, and what options actually exist. How they can be used is discussed elsewhere in this chapter.

Using options

When options are used, they must always be given between the runner script and the data sources. For example:

pybot -L debug my_tests.txt
jybot --include smoke --variable HOST:10.0.0.42 path/to/tests/

Short and long options

Options always have a long name, such as --name, and the most frequently needed options also have a short name, such as -N. In addition to that, long options can be shortened as long as they are unique. For example, --logle DEBUG works, while --lo log.html does not, because the former matches only --loglevel, but the latter matches several options. Short and shortened options are practical when executing test cases manually, but long options are recommended in start-up scripts, because they are easier to understand.

The long option format is case-insensitive, which facilitates writing option names in an easy-to-read format. For example, --SuiteStatLevel is equivalent to, but easier to read than --suitestatlevel.

Setting option values

Most of the options require a value, which is given after the option name. Both short and long options accept the value separated from the option name with a space, as in --include tag or -i tag. With long options, the separator can also be the equals sign, for example --include=tag, and with short options the separator can be omitted, as in -itag.

Some options can be specified several times. For example, --variable VAR1:value --variable VAR2:another sets two variables. If the options that take only one value are used several times, the value given last is effective.

Option value as simple pattern

Many of the options take arguments as simple patterns. This means that * and ? can be used as special characters, so that the former matches any string (even an empty string) and the latter matches any single character. For example, --include prefix-* matches all tags starting with prefix-, and --include a??? matches any tag that is four characters long and starts with a character a.

3.1.3   Test results

Command line output

The most visible output from test execution is the output displayed in the command line. All executed test suites and test cases, as well as their statuses, are shown there in real time. The example below shows the output from executing a simple test suite with only two test cases:

==============================================================================
Example test suite
==============================================================================
First test :: Possible test documentation                             | PASS |
------------------------------------------------------------------------------
Second test                                                           | FAIL |
Error message is displayed here
==============================================================================
Example test suite                                                    | FAIL |
2 critical tests, 1 passed, 1 failed
2 tests total, 1 passed, 1 failed
==============================================================================
Output:  /path/to/output.xml
Report:  /path/to/report.html
Log:     /path/to/log.html

Generated output files

The command line output is very limited, and separate output files are normally needed for investigating the test results. As the example above shows, three output files are generated by default. The first one is in XML format and contains all the information about test execution. The second is a higher-level report and the third is a more detailed log file. These files and other possible output files are discussed in more detail in the section Different output files.

Return codes

Runner scripts communicate the overall test execution status to the system running them using return codes. When the execution starts successfully and no critical test fail, the return code is zero. All possible return codes are explained in the table below.

Possible return codes
RC Explanation
0 All critical tests passed.
1-249 Returned number of critical tests failed.
250 250 or more critical failures.
251 Help or version information printed.
252 Invalid test data or command line options.
253 Test execution stopped by user.
255 Unexpected internal error.

Return codes should always be easily available after the execution, which makes it easy to automatically determine the overall execution status. For example, in bash shell the return code is in special variable $?, and in Windows it is in %ERRORLEVEL% variable. If you use some external tool for running tests, consult its documentation for how to get the return code.

Starting from Robot Framework 2.5.7, the return code can be set to 0 even if there are critical failures using the --NoStatusRC command line option. This might be useful, for example, in continuous integration servers where post-processing of results is needed before the overall status of test execution can be determined.

Errors and warnings during execution

During the test execution there can be unexpected problems like failing to import a library or a resource file or a keyword being deprecated. Depending on the severity such problems are categorized as errors or warnings and they are written into the console (using the standard error stream), shown on a separate Test Execution Errors section in log files, and also written into Robot Framework's own system log. Normally these errors are generated by Robot Framework core, but libraries can use log level WARN to write warnings. Example below illustrates how errors and warnings look like in the log file.

20090322 19:58:42.528 ERROR Error in file '/home/robot/tests.html' in table 'Setting' in element on row 2: Resource file 'resource.html' does not exist
20090322 19:58:43.931 WARN Keyword 'SomeLibrary.Example Keyword' is deprecated. Use keyword `Other Keyword` instead.

3.1.4   Escaping complicated characters

Because spaces are used for separating options from each other, it is problematic to use them in option values. Some options, such as --name, automatically convert underscores to spaces, but with others spaces must be escaped. Additionally, many special characters are complicated to use on the command line. Because escaping complicated characters with a backslash or quoting the values does not always work too well, Robot Framework has its own generic escaping mechanism. Another possibility is using argument files where options can be specified in the plain text format. Both of these mechanisms work when executing tests and when post-processing outputs, and also some of the external supporting tools have the same or similar capabilities.

In Robot Framework's command line escaping mechanism, problematic characters are escaped with freely selected text. The command line option to use is --escape (short version -E), which takes an argument in the format what:with, where what is the name of the character to escape and with is the string to escape it with. Characters that can be escaped are listed in the table below:

Available escapes
Character Name to use Character Name to use
& amp ( paren1
' apos ) paren2
@ at % percent
\ blash | pipe
: colon ? quest
, comma " quot
{ curly1 ; semic
} curly2 / slash
$ dollar space
! exclam [ square1
> gt ] square2
# hash * star
< lt

The following examples make the syntax more clear. In the first example, the metadata X gets the value Value with spaces, and in the second example variable ${VAR} is assigned to "Hello, world!":

--escape space:_ --metadata X:Value_with_spaces
-E space:SP -E quot:QU -E comma:CO -E exclam:EX -v VAR:QUHelloCOSPworldEXQU

Note that all the given command line arguments, including paths to test data, are escaped. Escape character sequences thus need to be selected carefully.

3.1.5   Argument files

Problematic characters can often be handled easily using argument files. These files can contain both command line options and paths to the test data, one per line. They are taken into use with --argumentfile option (short option -A) along with possible other command line options. Argument files can contain any characters without escaping, but spaces in the beginning and end of lines are ignored. Additionally, empty lines and lines starting with a hash mark (#) are ignored:

--doc This is an example (where "special characters" are ok!)
--metadata X:Value with spaces
--variable VAR:Hello, world!
# This is a comment
path/to/my/tests

Note

Starting from Robot Framework 2.5 it is possible to have also non-ASCII characters in argument files. For this to work, the argument file must be saved using UTF-8 encoding.

Another important usage for argument files is specifying input files or directories in certain order. This can be very useful if the alphabetical default execution order is not suitable:

--name My Example Tests
tests/some_tests.html
tests/second.html
tests/more/tests.html
tests/more/another.html
tests/even_more_tests.html

When an argument file is used on the command line, its contents are placed to the original list of arguments to the same place where the argument file option was. Argument files can be used either alone so that they contain all the options and paths to the test data, or along with other options and paths. It is possible to use --argumentfile option multiple times or even recursively:

pybot --argumentfile all_arguments.txt
pybot --name example --argumentfile other_options_and_paths.txt
pybot --argumentfile default_options.txt --name example my_tests.html
pybot -A first.txt -A second.txt -A third.txt some_tests.tsv

Special value STDIN can be used to read arguments from the standard input stream instead of a file. This can be useful when generating arguments with a script:

generate_arguments.sh | pybot --argumentfile STDIN
generate_arguments.sh | pybot --name Example --argumentfile STDIN mytest.txt

Reading arguments from the standard input is a new feature in Robot Framework 2.5.6.

3.1.6   Getting help and version information

Both when executing test cases with pybot or jybot and when post-processing reports with rebot, it is possible to get command line help with the option --help and its short version -h. These help texts have a short general overview and briefly explain the available command line options.

All runner scripts also support getting the version information with the option --version. This information also contains Python or Jython version and the platform type:

$ pybot --version
Robot Framework 2.0.3 (Python 2.5.1 on cygwin)

C:\>jybot --version
Robot Framework 2.0.3 (Jython 2.2 on java1.5.0_16)

C:\>rebot --version
Rebot 2.0.3 (Python 2.5.2 on win32)

3.1.7   Creating start-up scripts

Test cases are often executed automatically by a continuous integration system or some other mechanism. In such cases, there is a need to have a script for starting the test execution, and possibly also for post-processing outputs somehow. Similar scripts are also useful when running tests manually, especially if a large number of command line options are needed or setting up the test environment is complicated.

In UNIX-like environments, shell scripts provide a simple but powerful mechanism for creating custom start-up scripts. Windows batch files can also be used, but they are more limited and often also more complicated. A platform-independent alternative is using Python or some other high-level programming language. Regardless of the language, it is recommended that long option names are used, because they are easier to understand than the short names.

In the first examples, the same web tests are executed with different browsers and the results combined afterwards. This is easy with shell scripts, as practically you just list the needed commands one after another:

#!/bin/bash
pybot --variable BROWSER:Firefox --name Firefox --log none --report none --output out/fx.xml login
pybot --variable BROWSER:IE --name IE --log none --report none --output out/ie.xml login
rebot --name Login --outputdir out --output login.xml out/fx.xml out/ie.xml

Implementing the above example with Windows batch files is not very complicated, either. The most important thing to remember is that because pybot and rebot are implemented as batch files, call must be used when running them from another batch file. Otherwise execution would end when the first batch file is finished.

@echo off
call pybot --variable BROWSER:Firefox --name Firefox --log none --report none --output out\fx.xml login
call pybot --variable BROWSER:IE --name IE --log none --report none --output out\ie.xml login
call rebot --name Login --outputdir out --output login.xml out\fx.xml out\ie.xml

In the next examples, JAR files under the lib directory are put into CLASSPATH before starting the test execution. In these examples, start-up scripts require that paths to the executed test data are given as arguments. It is also possible to use command line options freely, even though some options have already been set in the script. All this is relatively straight-forward using bash:

#!/bin/bash

cp=.
for jar in lib/*.jar; do
    cp=$cp:$jar
done
export CLASSPATH=$cp

jybot --ouputdir /tmp/logs --suitestatlevel 2 $*

Implementing this using Windows batch files is slightly more complicated. The difficult part is setting the variable containing the needed JARs inside a For loop, because, for some reason, that is not possible without a helper function.

@echo off

set CP=.
for %%jar in (lib\*.jar) do (
    call :set_cp %%jar
)
set CLASSPATH=%CP%

jybot --ouputdir c:\temp\logs --suitestatlevel 2 %*

goto :eof

:: Helper for setting variables inside a for loop
:set_cp
    set CP=%CP%;%1
goto :eof

Modifying Java startup parameters

Sometimes there is need to alter the Java startup parameters. The most common use case is increasing the JVM maximum memory size as the default value may not be enough for creating reports and logs when outputs are very big. How to give the parameters to Java depends on the Jython version.

With Jython 2.2 you need to modify the Jython start-up script (jython shell script or jython.bat batch file) by adding the needed options (e.g. -Xmx1024m which sets the maximum memory to 1024 megabytes) to the java command. On Windows the final command could look like this:

"C:\Java\jre1.6.0\bin\java.exe" -Xmx1024m -Dpython.home="C:\Jython22" -classpath "C:\Jython22\jython.jar;%CLASSPATH%" org.python.util.jython %ARGS%

With Jython 2.5 it is also possible, and easier, to give the Java parameters with -J option to the Jython interpreter. This means that you can modify the jybot start-up script instead of Jython scripts. The last line of the jybot script can, again in Windows, be edited like below:

%jython% -J-Xmx1024m %runner% %*

3.1.8   Debugging problems

A test case can fail because the system under test does not work correctly, in which case the test has found a bug, or because the test itself is buggy. The error message explaining the failure is shown on the command line output and in the report file, and sometimes the error message alone is enough to pinpoint the problem. More often that not, however, log files are needed because they have also other log messages and they show which keyword actually failed.

When a failure is caused by the tested application, the error message and log messages ought to be enough to understand what caused it. If that is not the case, the test library does not provide enough information and needs to be enhanced. In this situation running the same test manually, if possible, may also reveal more information about the issue.

Failures caused by test cases themselves or by keywords they use can sometimes be hard to debug. If the error message, for example, tells that a keyword is used with wrong number of arguments fixing the problem is obviously easy, but if a keyword is missing or fails in unexpected way finding the root cause can be harder. The first place to look for more information is the execution errors section in the log file. For example, an error about a failed test library import may well explain why a test has failed due to a missing keyword.

If the log file does not provide enough information by default, it is possible to execute tests with a lower log level. For example tracebacks showing where in the code the failure occurred are logged using the DEBUG level, and this information is invaluable when the problem is in an individual keyword.

If the log file still does not have enough information, it is a good idea to enable the syslog and see what information it provides. It is also possible to add some keywords to the test cases to see what is going on. Especially BuiltIn keywords Log and Log Variables are useful. If nothing else works, it is always possible to search help from mailing lists or elsewhere.

3.2   Test execution

This section describes how the test suite structure created from the parsed test data is executed, how to continue executing a test case after failures, and how to stop the whole test execution gracefully.

3.2.1   Execution flow

Executed suites and tests

Test cases are always executed within a test suite. A test suite created from a test case file has tests directly, whereas suites created from directories have child test suites which either have tests or their own child suites. By default all the tests in an executed suite are run, but it is possible to select tests using options --test, --suite, --include and --exclude. Suites containing no tests are ignored.

The execution starts from the top-level test suite. If the suite has tests they are executed one-by-one, and if it has suites they are executed recursively in depth-first order. When an individual test case is executed, the keywords it contains are run in a sequence. Normally the execution of the current test ends if any of the keywords fails, but it is also possible to continue after failures. The exact execution order and how possible setups and teardowns affect the execution are discussed in the following sections.

Setups and teardowns

Setups and teardowns can be defined on test case and test suite level.

Suite setup

If a test suite has a setup, it is executed before its tests and child suites. If the suite setup passes, test execution continues normally. If it fails, all the test cases the suite and its child suites are marked failed with a message Setup of the parent suite failed.. The tests and possible suite setups and teardowns in the child test suites are not executed.

Suite setups are often used for setting up the test environment. Because tests are not run if the suite setup fails, it is easy to use suite setups for verifying that the environment is in state in which the tests can be executed.

Suite teardown

If a test suite has a teardown, it is executed after all its test cases and child suites. Suite teardowns are executed regardless of the test status and even if the matching suite setup fails. If the suite teardown fails, all tests in the suite are marked failed afterwards in reports and logs.

Suite teardowns are mostly used for cleaning up the test environment after the execution. To ensure that all these tasks are done, all the keywords used in the teardown are executed even if some of them fail.

Test setup

Possible test setup is executed before the keywords of the test case. If the setup fails, the keywords are not executed. The main use for test setups is setting up the environment for that particular test case.

Test teardown

Possible test teardown is executed after the test case has been executed. It is executed regardless of the test status and also if the setup of the test has failed.

Similarly as suite teardown, test teardowns are used mainly for cleanup activities. Also they are executed fully even if some of their keywords fail.

Execution order

Test cases in a test suite are executed in the same order as they are defined in the test case file. Test suites inside a higher level test suite are executed in case-insensitive alphabetical order based on the file or directory name. If multiple files and/or directories are given from the command line, they are executed in the order they are given.

If there is a need to use certain test suite execution order inside a directory, it is possible to add prefixes like 01 and 02 into file and directory names. Such prefixes are not included in the generated test suite name if they are separated from the base name of the suite with two underscores:

01__my_suite.html -> My Suite
02__another_suite.html -> Another Suite

If the alphabetical ordering of test suites inside suites is problematic, a good workaround is giving them separately in the required order. This easily leads to overly long start-up commands, but argument files allow listing files nicely one file per line.

It is also possible to randomize the execution order using the --runmode option.

3.2.2   Continue on failure

Normally test cases are stopped immediately when any of their keywords fail. This behavior shortens test execution time and prevents subsequent keywords hanging or otherwise causing problems if the system under test is in unstable state. This has the drawback that often subsequent keywords would give more information about the state of the system.

Before Robot Framework 2.5 the only way to handle failures so that test execution is not terminated immediately was using BuiltIn keywords Run Keyword And Ignore Error and Run Keyword And Expect Error. Using these keywords for this purpose often added extra complexity to test cases, and in Robot Framework 2.5 the following features were added to make continuing after failures easier.

Special failures from keywords

Library keywords report failures using exceptions, and it is possible to use special exceptions to tell the core framework that execution can continue regardless the failure. How these exceptions can be created is explained in the test library API chapter.

When a test ends and there has been one or more continuable failure, the test will be marked failed. If there are more than one failure, all of them will be enumerated in the final error message:

Several failures occurred:

1) First error message.

2) Second error message ...

Test execution ends also if a normal failure occurs after continuable failures. Also in that case all the failures will be listed in the final error message.

The return value from failed keywords, possibly assigned to a variable, is always the Python None.

Run Keyword And Continue On Failure keyword

BuiltIn keyword Run Keyword And Continue On Failure allows converting any failure into a continuable failure. These failures are handled by the framework exactly the same way as continuable failures originating from library keywords.

Execution continues on teardowns automatically

To make it sure that all the cleanup activities are taken care of, the continue on failure mode is automatically on in test and suite teardowns. In practice this means that in teardowns all the keywords in all levels are always executed.

All top-level keywords are executed when tests have templates

When using test templates, all the data rows are always executed to make it sure that all the different combinations are tested. In this usage continuing is limited to the top-level keywords, and inside them the execution ends normally if there are non-continuable failures.

3.2.3   Stopping test execution gracefully

Sometimes there is a need to stop the test execution before all the tests have finished, but so that logs and reports are created. Different ways how to accomplish this are explained below. In all these cases the remaining test cases are marked failed.

Note

Most of these features are new in Robot Framework 2.5. Only the ExitOnFailure mode is supported in earlier versions.

Pressing Ctrl-C

The execution is stopped when Ctrl-C is pressed in the console where the tests are running. When running the tests on Python, the execution is stopped immediately, but with Jython it ends only after the currently executing keyword ends.

If Ctrl-C is pressed again, the execution ends immediately and reports and logs are not created.

Using signals

On Unix-like machines it is possible to terminate test execution using signals INT and TERM. These signals can be sent from the command line using kill command, and sending signals can also be easily automated.

Signals have the same limitation on Jython as pressing Ctrl-C. Similarly also the second signal stops the execution forcefully.

Using keywords

The execution can be stopped also by the executed keywords. There is a separate Fatal Error BuiltIn keyword for this purpose, and custom keywords can use fatal exceptions when they fail.

ExitOnFailure mode

If option --runmode is used with value ExitOnFailure (case-insensitive), the execution of tests stops immediately if a critical test fails and the remaining tests are marked as failed.

Handling teardowns

By default teardowns for tests and suites that have been started are executed even if test execution is stopped using one of the methods above. This allows clean-up activities to be run regardless how execution ends.

Starting from Robot Framework 2.5.2, teardowns are skipped when the execution is stopped if the --runmode SkipTeardownOnExit command line option is used. This can be useful if clean-up takes a lot of time.

3.3   Post-processing outputs

XML output files that are generated during the test execution can be post-processed afterwards by the rebot tool, which is an integral part of Robot Framework. It is used automatically when test reports and logs are generated during the test execution, but there are also good grounds for using it separately after the execution.

3.3.1   Using rebot tool

The basic syntax for using rebot is exactly the same as when starting test execution, return codes are the same, and also most of the command line options are identical. The main difference is that arguments to rebot are XML output files instead of test data files or directories.

3.3.2   Creating different reports and logs

You can use rebot for creating the same reports and logs that are created automatically during the test execution. Of course, it is not sensible to create the exactly same files, but, for example, having one report with all test cases and another with only some subset of tests can be useful. Another common usage is creating only the output file when running tests (log and report generation can be disabled with options --log NONE and --report NONE) and generating logs and reports later. Tests can, for example, be executed on different environments, output files collected to a central place, and reports and logs created there. If generating reports and logs takes a lot of time when running tests on Jython, it is a good idea to try if using rebot, which always runs on Python, is any faster.

rebot output.xml
rebot path/to/output_file.xml
rebot --include smoke --name Smoke_Tests c:\results\output.xml

When using Robot Framework jar distribution, rebot is started with command:

java -jar robotframework-<version>.jar rebot

All normal command line options can be used when executing rebot from jar.

Note

When running tests with Jython, the default JVM maximum memory size may not be enough for creating reports and logs if output files are very large. If that happens, you can either increase the JVM's maximum memory, or disable creating reports and logs when tests are executed and use rebot to generate them afterwards.

3.3.3   Combining outputs

The most important feature of rebot is its ability to combine outputs from different test execution rounds. This capability allows, for example, running the same test cases on different environments and generating an overall report from all outputs. Combining outputs is extremely easy, all that needs to be done is giving several output files as arguments:

rebot output1.xml output2.xml
rebot outputs/*.xml

When outputs are combined, a new top-level test suite is created so that test suites in the given output files are its child suites. This works the same way when multiple test data files or directories are executed, and also in this case the name of the top-level test suite is created by joining child suite names with an ampersand (&) and spaces. These automatically generated names are not that good, and it is often a good idea to use --name to give a more meaningful name:

rebot --name Browser_Compatibility firefox.xml opera.xml safari.xml ie.xml
rebot --include smoke --name Smoke_Tests c:\results\*.xml

3.4   Configuring execution

This section explains different command line options that can be used for configuring the test execution or post-processing outputs. Options related to generated output files are discussed in the next section.

3.4.1   Selecting test cases

Robot Framework offers several command line options for selecting which test cases to execute. The same options also work when post-processing outputs with the rebot tool.

By test suite and test case names

Test suites and test cases can be selected by their names with the command line options --suite (-s) and --test (-t), respectively. Both of these options can be used several times to select several test suites or cases. Arguments to these options are case- and space-insensitive, and there can also be simple patterns matching multiple names. If both the --suite and --test options are used, only test cases in matching suites with matching names are selected.

--test Example
--test mytest --test yourtest
--test example*
--test mysuite.mytest
--test *.suite.mytest
--suite example-??
--suite mysuite --test mytest --test your*

Note

Selecting test cases using long name (e.g. mysuite.mytest) works with Robot Framework 2.5.6 and newer.

Using the --suite option is more or less the same as executing only the appropriate test case file or directory. One major benefit is the possibility to select the suite based on its parent suite. The syntax for this is specifying both the parent and child suite names separated with a dot. In this case, the possible setup and teardown of the parent suite are executed.

--suite parent.child
--suite myhouse.myhousemusic --test jack*

Selecting individual test cases with the --test option is very practical when creating test cases, but quite limited when running tests automatically. The --suite option can be useful in that case, but in general, selecting test cases by tag names is more flexible.

By tag names

It is possible to include and exclude test cases by tag names with the --include (-i) and --exclude (-e) options, respectively. When the former is used, only test cases having a matching tag are selected, and with the latter, test cases having a matching tag are not. If both are used, only tests with a tag matching the former option, and not with a tag matching the latter, are selected.

--include example
--exclude not_ready
--include regression --exclude long_lasting

Both --include and --exclude can be used several times to match multiple tags, and their arguments can be simple patterns. In these cases, the rules for selecting test cases apply, so that test cases with a tag matching any include patterns are selected, and tests with a tag matching exclude patterns are not. It is also possible to select only test cases that have two or more specified tags by separating the tags either with & or AND (case-sensitive). Starting from Robot Framework 2.1.3, only tests with a certain tag, but without any others, can be selected by separating these tags with NOT (case-sensitive). If any of the patterns between multiple NOT is matching, the test case is not selected.

--include req-*
--include regressionANDiter-42
--include tag1&tag2&tag3&tag4
--exclude regressionNOTowner-*
--include tag1NOTtag2NOTtag3&tag4  (includes tests which have `tag1`, but not tests which additionally have `tag2` or both tags `tag3` and `tag4`)

Selecting test cases by tags is a very flexible mechanism and allows many interesting possibilities:

  • A subset of tests to be executed before other tests can be tagged with smoke and executed with --include smoke.
  • Unfinished test can be committed to version control with the tag not_ready and excluded from the test execution with --exclude not_ready.
  • Tests can be tagged with iter-<num>, where <num> specifies the number of the current iteration, and after executing all test cases, a separate report containing only the tests for a certain iteration can be generated (for example, rebot --include iter-42 output.xml).

When no tests match selection

By default when no tests match the selection criteria the execution fails with an error like:

[ ERROR ] Suite 'Example' with includes 'xxx' contains no test cases.

Because no outputs are generated, this behavior can be problematic if tests are executed and results processed automatically. Luckily a command line option --RunEmptySuite can be used to force the suite to be executed also in this case. As a result normal outputs are created but show zero executed tests.

The same option can be used also to alter the behavior when an empty directory or a test case file containing no tests is executed.

Note

This is a new option in Robot Framework 2.6.

3.4.2   Setting criticality

The final result of test execution is determined on the basis of critical tests. If a single critical test fails, the whole test run is considered failed. On the other hand, non-critical test cases can fail and the overall status is still passed.

By default, all test cases are critical, but this can be changed with the --critical (-c) and --noncritical (-n) options. These options specify which test cases are consider critical based on tags, similarly as --include and --exclude are used to select test cases by tag names. If only --critical is used, test cases with a matching tag are critical. If only --noncritical is used, tests without a matching tag are critical. Finally, if both are used, only test with a critical tag but without a non-critical tag are considered critical. Both of these options accept simple patterns and can be given several times:

--critical regression
--noncritical not_ready
--critical iter-* --critical req-* --noncritical req-6??

The most common use case for setting criticality is having test cases that are not ready or test features still under development in the test execution. Of course, these tests could be excluded from the test execution altogether with the --exclude option, but including them as non-critical tests enables you to see when they start to pass.

Starting from Robot Framework 2.1 criticality set when tests are executed is not stored anywhere. If you want to keep same criticality when post-processing outputs with rebot, you need to use --critical and/or --noncritical also with it:

# Use rebot to create new log and report from the output created during execution
pybot --critical regression --outputdir all my_tests.html
rebot --name Smoke --include smoke --critical regression --outputdir smoke all/output.xml

# No need to use --critical/--noncritical when no log or report is created
jybot --log NONE --report NONE my_tests.html
rebot --critical feature1 output.xml

3.4.3   Setting metadata

Setting the name

When Robot Framework parses test data, test suite names are created from file and directory names. The name of the top-level test suite can, however, be overridden with the command line option --name (-N). Underscores in the given name are converted to spaces automatically, and words in the name capitalized.

Setting the documentation

In addition to defining documentation in the test data, documentation of the top-level suite can be given from the command line with the option --doc (-D). Underscores in the given documentation are converted to spaces, and it may contain simple HTML formatting.

Setting free metadata

Free test suite metadata may also be given from the command line with the option --metadata (-M). The argument must be in the format name:value, where name the name of the metadata to set and value is its value. Underscores in the name and value are converted to spaces, and the latter may contain simple HTML formatting. This option may be used several times to set multiple metadata.

Setting tags

The command line option --settag (-G) can be used to set the given tag to all executed test cases. This option may be used several times to set multiple tags.

3.4.4   Adjusting library search path

When a test library is taken into use, Robot Framework uses the Python or Jython interpreter to import a module implementing the library from the system. The location where these modules are searched from is called PYTHONPATH, and when running tests on Jython, also Java CLASSPATH is used.

Adjusting the library search path so that libraries are found is a requirement for successful test execution. In addition to find test libraries, the search path is also used to find listeners set on the command line. There are various ways to alter PYTHONPATH and CLASSPATH, but regardless of the selected approach, it is recommended to use a custom start-up script.

Locations automatically in PYTHONPATH

Python and Jython installations put their own library directories into PYTHONPATH automatically. This means that test libraries packaged using Python's own packaging system are automatically installed into a location that is in the library search path. Robot Framework also puts the directory containing its standard libraries and the directory where tests are executed from into PYTHONPATH.

Setting PYTHONPATH

There are several ways to alter PYTHONPATH in the system, but the most common one is setting an environment variable with the same name before the test execution. Jython actually does not use PYTHONPATH environment variable normally, but Robot Framework ensures that locations listed in it are added into the library search path regardless of the interpreter.

Setting CLASSPATH

CLASSPATH is used only with Jython, and the most common way to alter it is setting an environment variable similarly as with PYTHONPATH. Note that instead of CLASSPATH, it is always possible to use PYTHONPATH with Jython, even with libraries and listeners implemented with Java.

Using --pythonpath option

Robot Framework also has a separate command line option --pythonpath (-P) for adding directories or archives into PYTHONPATH. Multiple paths can be given by separating them with a colon (:) or using this option several times. The given path can also be a glob pattern matching multiple paths, but then it normally must be escaped.

Examples:

--pythonpath libs/
--pythonpath /opt/testlibs:mylibs.zip:yourlibs
--pythonpath mylib.jar --pythonpath lib/STAR.jar --escape star:STAR

3.4.5   Setting variables

Variables can be set from the command line either individually using the --variable (-v) option or through variable files with the --variablefile (-V) option. Variables and variable files are explained in separate chapters, but the following examples illustrate how to use these options:

--variable name:value
--variable OS:Linux --variable IP:10.0.0.42
--variablefile path/to/variables.py
--variablefile myvars.py:possible:arguments:here
--variable ENVIRONMENT:Windows --variablefile c:\resources\windows.py

3.4.6   Dry run

Robot Framework supports so called dry run mode where the tests are run normally otherwise, but the keywords coming from the test libraries are not executed at all. The dry run mode can be used to validate the test data; if the dry run passes, the data should be syntactically correct. This mode is triggered using option --runmode DryRun (case-insensitive) and it is supported starting from Robot Framework 2.5.

The dry run execution may fail for following reasons:

  • Using keywords that are not found.
  • Using keywords with wrong number of arguments.
  • Using user keywords that have invalid syntax.

In addition to these failures, normal execution errors are shown, for example, when test library or resource file imports cannot be resolved.

Note

The dry run mode does not validate variables. This limitation may be lifted in the future releases.

3.4.7   Randomizing execution order

The --runmode option can also be used to randomize the test execution order. This is done using the different values explained below.

random:test
Test cases inside each test suite are executed in random order.
random:suite
All test suites are executed in a random order, but test cases inside suites are run in the order they are defined.
random:all
Both test cases and test suites are executed in a random order.

Example:

pybot --runmode random:test my_test.txt

3.4.8   Controlling console output

Console width

The width of the test execution output in the console can be set using the option --monitorwidth (-W). The default width is 78 characters.

Tip

On many UNIX-like machines you can use handy $COLUMNS variable like --monitorwidth $COLUMNS.

Console colors

The --monitorcolors (-C) option is used to control whether colors should be used in the console output. Colors should work on all other platforms except for Windows when using Jython. This option has following case-insensitive values:

auto
Colors are enabled when output is written into the console but not when it is redirected into a file. This is the default and there is rarely need to change it.
on
Colors are used also when output is redirected into a file. Does not have effect on Windows.
off
Colors are disabled.
force
Backwards compatibility with Robot Framework 2.5.5 and older. Should not be used.

Note

Support for colors on Windows and the auto mode are new features in Robot Framework 2.5.6.

3.4.9   Setting listeners

So-called listeners can be used for monitoring the test execution. They are taken into use with the command line option --listener, and the specified listeners must be in the module search path similarly as test libraries.

3.5   Created outputs

Several output files are created when tests are executed, and all of them are somehow related to test results. This section discusses what outputs are created, how to configure where they are created, and how to fine-tune their contents.

3.5.1   Different output files

This section explains what different output files can be created and how to configure where they are created. Output files are configured using command line options, which get the path to the output file in question as an argument. A special value NONE (case-insensitive) can be used to disable creating a certain output file.

Output directory

All output files can be set using an absolute path, in which case they are created to the specified place, but in other cases, the path is considered relative to the output directory. The default output directory is the directory where the execution is started from, but it can be altered with the --outputdir (-d) option. The path set with this option is, again, relative to the execution directory, but can naturally be given also as an absolute path. Regardless of how a path to an individual output file is obtained, its parent directory is created automatically, if it does not exist already.

Output file

Output files contain all the test execution results in XML format. Log and report files are generated based on output files, and output files can also be combined and otherwise post-processed after the test execution.

The command line option --output (-o) determines the path where the output file is created relative to the output directory. The default name for the output file, when tests are run, is output.xml.

When post-processing outputs, new output files are not created unless --output (-o) option is explicitly used.

Starting from Robot Framework 2.6, it is possible to disable creation of the output file also when running tests with special value NONE. In this case also other output files, except for the debug file, are disabled.

Log file

Log files contain details about the executed test cases in HTML format. They have a hierarchical structure showing test suite, test case and keyword details. Log files are needed nearly every time when test results are to be investigated in detail. Even though log files also have statistics, reports are better for getting an higher-level overview.

The command line option --log (-l) determines where log files are created. Unless the special value NONE is used, log files are always created and their default name is log.html.

src/ExecutingTestCases/log_passed.png

An example of beginning of a log file

src/ExecutingTestCases/log_failed.png

An example of a log file with keyword details visible

Report file

Report files contain an overview of the test execution results in HTML format. They have statistics based on tags and executed test suites, as well as a list of all executed test cases. When both reports and logs are generated, the report has links to the log file for easy navigation to more detailed information. It is easy to see the overall test execution status from report, because its background color is green, if all critical tests pass, and bright red otherwise.

The command line option --report (-r) determines where report files are created. Similarly as log files, reports are always created unless NONE is used as a value, and their default name is report.html.

src/ExecutingTestCases/report_passed.png

An example report file of successful test execution

src/ExecutingTestCases/report_failed.png

An example report file of failed test execution

Summary file

Summary files are not supported in Robot Framework 2.6 or newer. Their original purpose was providing a report that has small size even when the number of test cases increases. This need disappeared because reports in 2.6 and newer are orders of magnitude smaller than earlier.

XUnit compatible result file

XUnit result files contain the test run summary in XUnit compatible XML format. This file can be used as input for tools that process XUnit data. For example, Hudson continuous integration server has built-in support for this output format and can be configured to generate test history based on this file.

XUnit output files are not created unless the command line option --xunitfile (-x) is used explicitly.

Debug file

Debug files are plain text files that are written during the test execution. All messages got from test libraries are written to them, as well as information about started and ended test suites, test cases and keywords. Debug files can be used for monitoring the test execution. This can be done using, for example, a separate file viewing tool, or in UNIX-like systems, simply with the tail -f command.

Debug files are not created unless the command line option --debugfile (-b) is used explicitly.

Timestamping output files

All output files listed in this section can be automatically timestamped with the option --timestampoutputs (-T). When this option is used, a timestamp in the format YYYYMMDD-hhmmss is placed between the extension and the base name of each file. The example below would, for example, create such output files as output-20080604-163225.xml and mylog-20080604-163225.html:

pybot --timestampoutputs --log mylog.html --report NONE tests.html

Setting titles

The default titles for logs and reports are generated by prefixing the name of the top-level test suite with Test Log or Test Report. Custom titles can be given from the command line using the options --logtitle and --reporttitle, respectively. Underscores in the given titles are converted to spaces automatically.

Example:

pybot --logtitle Smoke_Test_Log --reporttitle Smoke_Test_Report --include smoke my_tests/

Setting background colors

By default the report file has a green background when all the critical tests pass and a red background otherwise. These colors can be customized by using the --reportbackground command line option, which takes two or three colors separated with a colon as an argument:

--reportbackground blue:red
--reportbackground green:yellow:red
--reportbackground #00E:#E00

If you specify two colors, the first one will be used instead of the default green color and the second instead of the default red. This allows, for example, using blue instead of green to make backgrounds easier to separate for color blind people.

If you specify three colors, the first one will be used when all the test succeed, the second when only non-critical tests have failed, and the last when there are critical failures. This feature thus allows using a separate background color, for example yellow, when non-critical tests have failed.

The specified colors are used as a value for the body element's background CSS property. The value is used as-is and can be a HTML color name (e.g. red), a hexadecimal value (e.g. #F00 or #FF0000), or an RGB value (e.g. rgb(255,0,0)). The default green and red colors are specified using hexadecimal values #9F6 and #F33, respectively.

3.5.2   Log levels

Available log levels

Messages in log files can have different log levels. Some of the messages are written by Robot Framework itself, but also executed keywords can log information using different levels. The available log levels are:

FAIL
Used when a keyword fails. Can be used only by Robot Framework itself.
WARN
Used to display warnings. They shown also in the console and in the Test Execution Errors section in log files, but they do not affect the test case status.
INFO
The default level for normal messages. By default, messages below this level are not shown in the log file.
DEBUG
Used for debugging purposes. Useful, for example, for logging what libraries are doing internally. When a keyword fails, a traceback showing where in the code the failure occurred is logged using this level automatically.
TRACE
More detailed debugging level. The keyword arguments and return values are automatically logged using this level.

Setting log level

By default, log messages below the INFO level are not logged, but this threshold can be changed from the command line using the --loglevel (-L) option. This option takes any of the available log levels as an argument, and that level becomes the new threshold level. A special value NONE can also be used to disable logging altogether.

Starting from Robot Framework 2.5.2, it is possible to use the --loglevel option also when post-processing outputs with rebot. This allows, for example, running tests initially with the TRACE level, and generating smaller log files for normal viewing later with the INFO level. By default all the messages included during execution will be included also with rebot. Messages ignored during the execution cannot be recovered.

Another possibility to change the log level is using the BuiltIn keyword Set Log Level in the test data. It takes the same arguments as the --loglevel option, and it also returns the old level so that it can be restored later, for example, in a test teardown.

3.5.3   Splitting logs

Normally the log file is just a single HTML file. When the amount of he test cases increases, the size of the file can grow so large that opening it into a browser is inconvenient or even impossible. Starting from Robot Framework 2.6, it is possible to use the --splitlog option to split parts of the log into external files that are loaded transparently into the browser when needed.

The main benefit of splitting logs is that individual log parts are so small that opening and browsing the log file is possible even if the amount of the test data is very large. A small drawback is that the overall size taken by the log file increases.

Technically the test data related to each test case is saved into a JavaScript file in the same folder as the main log file. These files have names such as log-42.js where log is the base name of the main log file and 42 is an incremented index.

Note

When copying the log files, you need to copy also all the log-*.js files or some information will be missing.

3.5.4   Splitting outputs

Splitting outputs functionality has been removed in Robot Framework 2.6. Splitting logs works much better and should be used instead.

3.5.5   Configuring statistics

There are several command line options that can be used to configure and adjust the contents of the Statistics by Tag, Statistics by Suite and Test Details by Tag tables in different output files. All these options work both when executing test cases and when post-processing outputs.

Configuring displayed suite statistics

When a deeper suite structure is executed, showing all the test suite levels in the Statistics by Suite table may make the table somewhat difficult to read. Bt default all suites are shown, but you can control this with the command line option --suitestatlevel which takes the level of suites to show as an argument:

--suitestatlevel 3

Including and excluding tag statistics

When many tags are used, the Statistics by Tag table can become quite congested. If this happens, the command line options --tagstatinclude and --tagstatexclude can be used to select which tags to display, similarly as --include and --exclude are used to select test cases:

--tagstatinclude some-tag --tagstatinclude another-tag
--tagstatexclude owner-*
--tagstatinclude prefix-* --tagstatexclude prefix-13

Generating combined tag statistics

The command line option --tagstatcombine can be used to generate aggregate tags that combine statistics from multiple tags. There are three somewhat different ways for giving arguments for this option:

One tag as a simple pattern
All tags matching the given pattern are combined together.
Two or more tags separated by AND or &
The combined statistics contain tests that have all the listed tags. Tags can be given as simple patterns.
Two or more tags separated by NOT
The combined statistics contain tests that have the first tag but not the others. Also in this case tags may be patterns.

The following examples illustrate these usages, and the figure below shows a snippet of the resulting Statistics by Tag table when the example test data is executed with these options:

--tagstatcombine owner-*
--tagstatcombine smokeANDmytag
--tagstatcombine smokeNOTowner-janne*
src/ExecutingTestCases/tagstatcombine.png

Examples of combined tag statistics

As the above example shows, the name of the added combined statistic is, by default, generated from the given pattern. In certain situations this name can look pretty cryptic and it is possible to specify a more descriptive name. This name is given after the pattern separating it with a colon (:). Example below generates combined tag so that the name shown in reports and logs is Critical Tests:

--tagstatcombine *NOTnon-critical:Critical_Tests

Adding documentation to tags

Tags can be given a documentation with the command line option --tagdoc, which takes an argument in the format tag:doc. tag is the name of the tag to assign the documentation to, and it can also be a simple pattern matching multiple tags. doc is the assigned documentation. Underscores in it the documentation are automatically converted to spaces and it can also contain HTML formatting.

The given documentation is shown with matching tags in the Test Details by Tag table, and as a tool tip for these tags in the Statistics by Tag table. If one tag gets multiple documentations, they are combined together and separated with an ampersand.

Examples:

--tagdoc mytag:My_documentation
--tagdoc regression:*See*_http://info.html
--tagdoc owner-*:Original_author

3.5.6   Additional options for post-processing outputs

These options are available only when post-processing outputs with rebot.

Setting start and end time of execution

When combining outputs, it is possible to set the start and end time of the combined test suite using the options --starttime and --endtime, respectively. This is convenient, because by default, combined suites do not have these values. When both the start and end time are given, the elapsed time is also calculated based on them. Otherwise the elapsed time is got by adding the elapsed times of the child test suites together.

Starting from Robot Framework 2.5.6, it is also possible to use the above mentioned options to set start and end times for a single suite when using rebot. Using these options with a single output always affects the elapsed time of the suite.

Times must be given as timestamps in the format YYYY-MM-DD hh:mm:ss.mil, where all separators are optional and the parts from milliseconds to hours can be omitted. For example, 2008-06-11 17:59:20.495 is equivalent both to 20080611-175920.495 and 20080611175920495, and also mere 20080611 would work.

Examples:

rebot --starttime 20080611-17:59:20.495 output1.xml output2.xml
rebot --starttime 20080611-175920 --endtime 20080611-180242 *.xml
rebot --starttime 20110302-1317 --endtime 20110302-11418 myoutput.xml

Removing keywords from outputs

Most of the content of output files comes from keywords and especially their log messages. When creating higher level reports, log files are not necessarily needed at all, and then keywords and their messages just take space unnecessarily. In these situations, the command line option --removekeywords can be used to dispose of unnecessary keywords. It has two possible values:

ALL
All keywords are unconditionally removed.
PASSED
Keywords are removed only from test cases that have passed and do not contain messages written with loglevel WARN. In most cases, log files created after this contain enough information to investigate possible failures.

Removing keywords makes output files considerably smaller and thus faster to process further. Even when keywords are removed, names, arguments and statuses of top-level keywords are preserved, so it is still possible to create log files and see the high-level structure of each test case.

3.5.7   System log

Robot Framework has its own plain-text system log where it writes information about

  • Processed and skipped test data files
  • Imported test libraries, resource files and variable files
  • Executed test suites and test cases
  • Created outputs

Normally users never need this information, but it can be useful when investigating problems with test libraries or Robot Framework itself. A system log is not created by default, but it can be enabled by setting the environment variable ROBOT_SYSLOG_FILE so that it contains a path to the selected file.

A system log has the same log levels as a normal log file, with the exception that instead of FAIL it has the ERROR level. The threshold level to use can be altered using the ROBOT_SYSLOG_LEVEL environment variable like shown in the example below. Possible unexpected errors and warnings are written into the system log in addition to the console and the normal log file.

#!/bin/bash

export ROBOT_SYSLOG_FILE=/tmp/syslog.txt
export ROBOT_SYSLOG_LEVEL=DEBUG

pybot --name Syslog_example path/to/tests

4   Extending Robot Framework

4.1   Creating test libraries

Robot Framework's actual testing capabilities are provided by test libraries. There are many existing libraries, some of which are even bundled with the core framework, but there is still often a need to create new ones. This task is not too complicated because, as this chapter illustrates, Robot Framework's library API is simple and straightforward.

4.1.1   Introduction

Supported programming languages

Robot Framework itself is written with Python and naturally test libraries extending it can be implemented using the same language. When running the framework on Jython, libraries can also be implemented using Java. Pure Python code works both on Python and Jython, assuming that it does not use syntax or modules that are not available on Jython. When using Python, it is also possible to implement libraries with C using Python C API, although it is often easier to interact with C code from Python libraries using ctypes module.

Libraries implemented using these natively supported languages can also act as wrappers to functionality implemented using other programming languages. A good example of this approach is the Remote library, and another widely used approaches is running external scripts or tools as separate processes.

Tip

Python Tutorial for Robot Framework Test Library Developers covers enough of Python language to get started writing test libraries using it. It also contains a simple example library and test cases that you can execute and otherwise investigate on your machine.

Different test library APIs

Robot Framework has three different test library APIs.

Static API

The simplest approach is having a module (in Python) or a class (in Python or Java) with methods which map directly to keyword names. Keywords also take the same arguments as the methods implementing them. Keywords report failures with exceptions, log by writing to standard output and can return values using the return statement.

Dynamic API

Dynamic libraries are classes that implement a method to get the names of the keywords they implement, and another method to execute a named keyword with given arguments. The names of the keywords to implement, as well as how they are executed, can be determined dynamically at runtime, but reporting the status, logging and returning values is done similarly as in the static API.

Hybrid API

This is a hybrid between the static and the dynamic API. Libraries are classes with a method telling what keywords they implement, but those keywords must be available directly. Everything else except discovering what keywords are implemented is similar as in the static API.

All these APIs are described in this chapter. Everything is based on how the static API works, so its functions are discussed first. How the dynamic library API and the hybrid library API differ from it is then discussed in sections of their own.

The examples in this chapter are mainly about using Python, but they should be easy to understand also for Java-only developers. In those few cases where APIs have differences, both usages are explained with adequate examples.

4.1.2   Creating test library class or module

Test libraries can be implemented as Python modules and Python or Java classes.

Test library names

The name of a test library that is used when a library is imported is the same as the name of the module or class implementing it. For example, if you have a Python module MyLibrary (that is, the file MyLibrary.py), it will create a library with a name MyLibrary. Similarly, a Java class YourLibrary, when it is not in any package, creates a library with exactly that name.

Python classes are always inside a module. If the name of a class implementing a library is the same as the name of the module, Robot Framework allows dropping the module name when importing the library. For example, the class MyLib in the MyLib.py file can be used as a library with the name MyLib. If the module name and class name are different, libraries must be taken into use using both module and class names, such as mymodule.MyLibrary.

Java classes in a non-default package must be taken into use with the full name. For example, the class MyLib in the com.mycompany.myproject package must be imported with the name com.mycompany.myproject.MyLib.

Tip

If the library name is really long, for example when the Java package name is long, it is recommended to give the library a simpler alias by using the WITH NAME syntax.

Providing arguments to test libraries

All test libraries implemented as classes can take arguments. These arguments are specified in the Setting table after the library name, and when Robot Framework creates an instance of the imported library, it passes them to its constructor. Libraries implemented as a module cannot take any arguments, so trying to use those results in an error.

The number of arguments needed by the library is the same as the number of arguments accepted by the library's constructor. The default values and variable number of arguments work similarly as with keyword arguments, with the exception that there is no variable argument support for Java libraries. Arguments passed to the library, as well as the library name itself, can be specified using variables, so it is possible to alter them, for example, from the command line.

Importing a test library with arguments
Setting Value Value Value
Library MyLibrary 10.0.0.1 8080
Library AnotherLib ${VAR}  

Example implementations, first one in Python and second in Java, for the libraries used in the above example:

from example import Connection

class MyLibrary:

    def __init__(self, host, port=80):
        self._conn = Connection(host, int(port))

    def send_message(self, message):
        self._conn.send(message)
public class AnotherLib {

    private String setting = null;

    public AnotherLib(String setting) {
        setting = setting;
    }

    public void doSomething() {
        if setting.equals("42") {
            // do something ...
        }
    }
}

Test library scope

Libraries implemented as classes can have an internal state, which can be altered by keywords and with arguments to the constructor of the library. Because the state can affect how keywords actually behave, it is important to make sure that changes in one test case do not accidentally affect other test cases. These kind of dependencies may create hard-to-debug problems, for example, when new test cases are added and they use the library inconsistently.

Robot Framework attempts to keep test cases independent from each other: by default, it creates new instances of test libraries for every test case. However, this behavior is not always desirable, because sometimes test cases should be able to share a common state. Additionally, all libraries do not have a state and creating new instances of them is simply not needed.

Test libraries can control when new libraries are created with a class attribute ROBOT_LIBRARY_SCOPE . This attribute must be a string and it can have the following three values:

TEST CASE
A new instance is created for every test case. A possible suite setup and suite teardown share yet another instance. This is the default.
TEST SUITE
A new instance is created for every test suite. The lowest-level test suites, created from test case files and containing test cases, have instances of their own, and higher-level suites all get their own instances for their possible setups and teardowns.
GLOBAL
Only one instance is created during the whole test execution and it is shared by all test cases and test suites. Libraries created from modules are always global.

When the TEST SUITE or GLOBAL scopes are used with test libraries that have a state, it is recommended that libraries have some special keyword for cleaning up the state. This keyword can then be used, for example, in a suite setup or teardown to ensure that test cases in the next test suites can start from a known state. For example, SeleniumLibrary uses the GLOBAL scope to enable using the same browser in different test cases without having to reopen it, and it also has the Close All Browsers keyword for easily closing all open browsers.

Example Python library using the TEST SUITE scope:

class ExampleLibrary:

    ROBOT_LIBRARY_SCOPE = 'TEST SUITE'

    def __init__(self):
        self._counter = 0

    def count(self):
        self._counter += 1
        print self._counter

    def clear_counter(self):
        self._counter = 0

Example Java library using the GLOBAL scope:

public class ExampleLibrary {

    public static final String ROBOT_LIBRARY_SCOPE = "GLOBAL";

    private int counter = 0;

    public void count() {
        counter += 1;
        System.out.println(counter);
    }

    public void clearCounter() {
        counter = 0;
    }
}

Specifying library version

When a test library is taken into use, Robot Framework tries to determine its version. This information is then written into the syslog to provide debugging information. Library documentation tool libdoc.py also writes this information into the keyword documentations it generates.

Version information is read from attribute ROBOT_LIBRARY_VERSION, similarly as test library scope is read from ROBOT_LIBRARY_SCOPE. If ROBOT_LIBRARY_VERSION does not exist, information is tried to be read from __version__ attribute. These attributes must be class or module attributes, depending whether the library is implemented as a class or a module. For Java libraries the version attribute must be declared as static final.

An example Python module using __version__:

__version__ = '0.1'

def keyword():
    pass

A Java class using ROBOT_LIBRARY_VERSION:

public class VersionExample {

    public static final String ROBOT_LIBRARY_VERSION = "1.0.2";

    public void keyword() {
    }
}

4.1.3   Creating static keywords

What methods are considered keywords

When the static library API is used, Robot Framework uses reflection to find out what public methods the library class or module implements. It will exclude all methods starting with an underscore, and with Java libraries also methods that are implemented only in java.lang.Object are ignored. All the methods that are not ignored are considered keywords. For example, the Python and Java libraries below implement single keyword My Keyword.

class MyLibrary:

    def my_keyword(self, arg):
        return self._helper_method(arg)

    def _helper_method(self, arg):
        return arg.upper()
public class MyLibrary {

    public String myKeyword(String arg) {
        return helperMethod(arg);
    }

    private String helperMethod(String arg) {
        return arg.toUpperCase();
    }
}

When the library is implemented as a Python module, it is also possible to limit what methods are keywords by using Python's __all__ attribute. If __all__ is used, only methods listed in it can be keywords. For example, the library below implements keywords Example Keyword and Second Example. Without __all__, it would implement also keywords Not Exposed As Keyword and Current Thread. The most important usage for __all__ is making sure imported helper methods, such as current_thread in the example below, are not accidentally exposed as keywords.

from threading import current_thread

__all__ = ['example_keyword', 'second_example']

def example_keyword():
    if current_thread().name == 'MainThread':
        print 'Running in main thread'

def second_example():
    pass

def not_exposed_as_keyword():
    pass

Note

Support for the __all__ attribute is available from Robot Framework 2.5.5 onwards.

Keyword names

Keyword names used in the test data are compared with method names to find the method implementing these keywords. Name comparison is case-insensitive, and also spaces and underscores are ignored. For example, the method hello maps to the keyword name Hello, hello or even h e l l o. Similarly both the do_nothing and doNothing methods can be used as the Do Nothing keyword in the test data.

Example Python library implemented as a module in the MyLibrary.py file:

def hello(name):
    print "Hello, %s!" % name

def do_nothing():
    pass

Example Java library implemented as a class in the MyLibrary.java file:

public class MyLibrary {

    public void hello(String name) {
        System.out.println("Hello, " + name + "!");
    }

    public void doNothing() {
    }

}

The example below illustrates how the example libraries above can be used. If you want to try this yourself, make sure that the library is in the library search path.

Using simple example library
Setting Value Value Value
Library MyLibrary    
Test Case Action Argument Argument
My Test Do Nothing    
Hello world  

Keyword arguments

With a static and hybrid API, the information on how many arguments a keyword needs is got directly from the method that implements it. Libraries using the dynamic library API have other means for sharing this information, so this section is not relevant to them.

The most common and also simplest situation is when a keyword needs an exact number of arguments. In this case, both the Python and Java methods simply take exactly those arguments. For example, a method implementing a keyword with no arguments takes no arguments either, a method implementing a keyword with one argument also takes one argument, and so on.

Example Python keywords taking different numbers of arguments:

def no_arguments():
    print "Keyword got no arguments"

def one_argument(arg):
    print "Keyword got one argument '%s'" % arg

def multiple_arguments(a1, a2, a3):
    print "Keyword got three arguments '%s', '%s' and '%s'" % (a1, a2, a3)

Default values to keywords

It is often useful that some of the arguments that a keyword uses have default values. Python and Java have different syntax for handling default values to methods, and the natural syntax of these languages can be used when creating test libraries for Robot Framework.

Default values with Python

In Python a method has always exactly one implementation and possible default values are specified in the method signature. The syntax, which is familiar to all Python programmers, is illustrated below:

def one_default(arg='default'):
    print "Argument has value '%s'" % arg

def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
    print "Got arguments %s, %s and %s" % (arg1, arg2, arg3)

The first example keyword above can be used either with zero or one arguments. If no arguments are given, arg gets the value default. If there is one argument, arg gets that value, and calling the keyword with more than one argument fails. In the second example, one argument is always required, but the second and the third one have default values, so it is possible to use the keyword with one to three arguments.

Using keywords with variable number of arguments
Test Case Action Argument Argument Argument
Defaults One Default      
One Default argument    
Multiple Defaults required arg    
Multiple Defaults required arg optional  
Multiple Defaults required arg optional 1 optional 2
Default values with Java

In Java one method can have several implementations with different signatures. Robot Framework regards all these implementations as one keyword, which can be used with different arguments. This syntax can thus be used to provide support for the default values. This is illustrated by the example below, which is functionally identical to the earlier Python example:

public void oneDefault(String arg) {
    System.out.println("Argument has value '" + arg "'");
}

public void oneDefault() {
    oneDefault("default");
}

public void multipleDefaults(String arg1, String arg2, String arg3) {
    System.out.println("Got arguments " + arg1 + ", " + arg2 + " and " + arg3);
}

public void multipleDefaults(String arg1, String arg2) {
    multipleDefaults(arg1, arg2, "default 2");
}

public void multipleDefaults(String arg1) {
    multipleDefaults(arg1, "default 1");
}

Variable number of arguments

Robot Framework supports also keywords that take any number of arguments. Similarly as with the default values, the actual syntax to use in test libraries is different in Python and Java.

Variable number of arguments with Python

Python supports methods accepting any number of arguments. The same syntax works in libraries and, as the examples below show, it can also be combined with other ways of specifying arguments:

def any_arguments(*args):
    print "Got arguments:"
    for arg in args:
        print arg

def one_required(required, *others):
    print "Required: %s\nOthers:" % required
    for arg in others:
        print arg

def also_defaults(req, def1="default 1", def2="default 2", *rest):
    print req, def1, def2, rest
Using keywords with a variable number of arguments
Test Case Action Argument Argument Argument
Varargs Any Arguments      
Any Arguments argument    
Any Arguments arg 1 arg 2 arg 2
... arg 4 arg 5  
One Required required arg    
One Required required arg another arg yet another
Also Defaults required    
Also Defaults required these two have defaults
Also Defaults 1 2 3
... 4 5 6
Variable number of arguments with Java

Robot supports Java varargs syntax for defining variable number of arguments. Robot also will translate an array as the last argument in a keyword signature as a list of variable number of arguments. In this case, all leftover arguments to the keyword are packed into the list. This also works if the keyword is used with one argument less than the actual number of arguments in the signature - in this case the array at the end will be empty.

Robot's support for variable number of arguments in Java has one limitation: it only works if the method has only one signature. Thus it is not possible to have a Java keyword that has both the default values and a variable number of arguments. Of course, having a number of required arguments is still possible, as the examples below illustrate:

public void anyNumberOfArguments(String... varargs) {
    System.out.println("Got arguments:");
    for (String arg: varargs) {
        System.out.println(arg);
    }
}

public void oneArgumentRequired(String required, String... others) {
    System.out.println("Required: " + required + "\nOthers:");
    for (String arg: others) {
        System.out.println(arg);
    }
}

public void usingAnArray(String[] args) {
    System.out.println("Got arguments:");
    for (String arg: args) {
        System.out.println(arg);
    }
}

Argument types

Normally keyword arguments come to Robot Framework as strings. If keywords require some other types, it is possible to either use variables or convert strings to required types inside keywords. With Java keywords base types are also coerced automatically.

Argument types with Python

Because arguments in Python do not have any type information, there is no possibility to automatically convert strings to other types when using Python libraries. Calling a Python method implementing a keyword with a correct number of arguments always succeeds, but the execution fails later if the arguments are incompatible. Luckily with Python it is simple to convert arguments to suitable types inside keywords:

def connect_to_host(address, port=25):
    port = int(port)
    # ...
Argument types with Java

Arguments to Java methods have types, and all the base types are handled automatically. This means that arguments that are normal strings in the test data are coerced to correct type at runtime. The types that can be coerced are:

  • integer types (byte, short, int, long)
  • floating point types (float and double)
  • the boolean type
  • object versions of the above types e.g. java.lang.Integer

The coercion is done for arguments that have the same or compatible type across all the signatures of the keyword method. In the following example, the conversion can be done for keywords doubleArgument and compatibleTypes, but not for conflictingTypes.

public void doubleArgument(double arg) {}

public void compatibleTypes(String arg1, Integer arg2) {}
public void compatibleTypes(String arg2, Integer arg2, Boolean arg3) {}

public void conflictingTypes(String arg1, int arg2) {}
public void conflictingTypes(int arg1, String arg2) {}

The coercion works with the numeric types if the test data has a string containing a number, and with the boolean type the data must contain either string true or false. Coercion is only done if the original value was a string from the test data, but it is of course still possible to use variables containing correct types with these keywords. Using variables is the only option if keywords have conflicting signatures.

Using automatic type coercion
Test Case Action Argument Argument Argument
Coercion Double Argument 3.14    
Double Argument 2e16   # scientific notation
Compatible Types Hello, world! 1234  
Compatible Types Hi again! -10 true
       
No Coercion Double Argument ${3.14}    
Conflicting Types 1 ${2} # must use variables
Conflicting Types ${1} 2  

4.1.4   Communicating with Robot Framework

After a method implementing a keyword is called, it can use any mechanism to communicate with the system under test. It can then also send messages to Robot Framework's log file, return information that can be saved to variables and, most importantly, report if the keyword passed or not.

Reporting keyword status

Reporting keyword status is done simply using exceptions. If an executed method raises an exception, the keyword status is FAIL, and if it returns normally, the status is PASS.

The error message shown in logs, reports and the console is created from the exception type and its message. With generic exceptions (for example, AssertionError, Exception, and RuntimeError), only the exception message is used, and with others, the message is created in the format ExceptionType: Actual message. In both cases, it is important for the users that the exception message is as informative as possible.

If the error message is longer than 40 lines, it will be automatically cut from the middle to prevent reports from getting too long and difficult to read. The full error message is always shown in the log message of the failed keyword.

The traceback of the exception is also logged using DEBUG log level. These messages are not visible in log files by default because they are very rarely interesting for normal users. When developing libraries, it is often a good idea to run tests using --loglevel DEBUG.

Stopping test execution

Starting from Robot Framework 2.5 it is possible to fail a test case so that the whole test execution is stopped. This is done simply by having a special ROBOT_EXIT_ON_FAILURE attribute with True value set on the exception raised from the keyword. This is illustrated in the examples below.

Python:

class MyFatalError(RuntimeError):
    ROBOT_EXIT_ON_FAILURE = True

Java:

public class MyFatalError extends RuntimeException {
    public static final boolean ROBOT_EXIT_ON_FAILURE = true;
}

Continuing test execution despite of failures

Starting from Robot Framework 2.5 it is possible to continue test execution even when there are failures. The way to signal this from test libraries is adding a special ROBOT_CONTINUE_ON_FAILURE attribute with True value to the exception used to communicate the failure. This is demonstrated by the examples below.

Python:

class MyContinuableError(RuntimeError):
    ROBOT_CONTINUE_ON_FAILURE = True

Java:

public class MyContinuableError extends RuntimeException {
    public static final boolean ROBOT_CONTINUE_ON_FAILURE = true;
}

Logging information

Exception messages are not the only way to give information to the users. In addition to them, methods can also send messages to log files simply by writing to the standard output stream (stdout) or to the standard error stream (stderr), and they can even use different log levels. Another, and often better, logging possibility is using the programmatic logging APIs.

By default, everything written by a method into the standard output is written to the log file as a single entry with the log level INFO. Messages written into the standard error are handled similarly otherwise, but they are echoed back to the original stderr after the keyword execution has finished. It is thus possible to use the stderr if you need some messages to be visible on the console where tests are executed.

Using log levels

To use other log levels than INFO, or to create several messages, specify the log level explicitly by embedding the level into the message in the format *LEVEL* Actual log message, where *LEVEL* must be in the beginning of a line and LEVEL is one of the available logging levels TRACE, DEBUG, INFO, WARN and HTML.

Warnings

Messages with WARN level are automatically written into the console and into separate Test Execution Errors section in log files. This makes warnings more visible than other messages and allows using them for reporting important but non-critical problems to users.

Logging HTML

Everything normally logged by the library will be converted into a format that can be safely represented as HTML. For example, <b>foo</b> will be displayed in the log exactly like that and not as foo. If libraries want to use formatting, links, display images and so on, they can use a special pseudo log level HTML. Robot Framework will write these messages directly into the log with the INFO level, so they can use any HTML syntax they want. Notice that this feature needs to be used with care, because one badly placed </table> tag can ruin the log file quite badly.

Timestamps

By default messages logged via the standard output or error streams get their timestamps when the executed keyword ends. This means that the timestamps are not accurate and debugging problems especially with longer running keywords can be problematic.

Starting from Robot Framework 2.6 keywords have a possibility to add an accurate timestamp to the messages they log if there is a need. The timestamp must be given as milliseconds since the Unix epoch and it must be placed after the log level separated from it with a colon:

*INFO:1308435758660* Message with timestamp
*HTML:1308435758661* <b>HTML</b> message with timestamp

As illustrated by the examples below, adding the timestamp is easy both using Python and Java. If you are using Python, it is, however, even easier to get accurate timestamps using the programmatic logging APIs. A big benefit of this mechanism is that it works also with the remote library interface.

Python:

import time

def example_keyword():
    print '*INFO:%d* Message with timestamp' % (time.time()*1000)

Java:

public void exampleKeyword() {
    System.out.println("*INFO:" + System.currentTimeMillis() + "* Message with timestamp");
}
Logging to console

If libraries need to write something to the console they have three options.

As already discussed, warnings as well as all messages written to the standard error stream are written both to the log file and to the console. Both of these options have a limitation that the messages end up to the console only after the currently executing keyword finishes. A bonus is that these approaches work both with Python and Java based libraries.

The third option, that is only available with Python, is writing messages to sys.__stdout__. Robot Framework only intercepts sys.stdout and sys.stderr and leaves sys.__stdout__ (and sys.__stderr__) alone like all well behaving Python programs should. When using sys.__stdout__ messages end up to the console immediately and are not written to the log file at all.

Logging example

In most cases, the INFO level is adequate. The levels below it, DEBUG and TRACE, are useful for writing debug information. These messages are normally not shown, but they can facilitate debugging possible problems in the library itself. The WARN level can be used to make messages more visible and HTML is useful if any kind of formatting is needed.

The following examples clarify how logging with different levels works. Java programmers should regard the code print 'message' as pseudocode meaning System.out.println("message");.

print 'Hello from a library.'
print '*WARN* Warning from a library.'
print '*INFO* Hello again!'
print 'This will be part of the previous message.'
print '*INFO* This is a new message.'
print '*INFO* This is <b>normal text</b>.'
print '*HTML* This is <b>bold</b>.'
print '*HTML* <a href="http://robotframework.org">Robot Framework</a>'
16:18:42.123 INFO Hello from a library.
16:18:42.123 WARN Warning from a library.
16:18:42.123 INFO Hello again!
This will be part of the previous message.
16:18:42.123 INFO This is a new message.
16:18:42.123 INFO This is <b>normal text</b>.
16:18:42.123 INFO This is bold.
16:18:42.123 INFO Robot Framework

Programmatic logging APIs

Programmatic APIs provide somewhat cleaner way to log information than using the standard output and error streams. Currently these interfaces are available only to Python bases test libraries.

Public logging API

Robot Framework 2.6 has a new Python based logging API for writing messages to the log file and to the console. Test libraries can use this API like logger.info('My message') instead of logging through the standard output like print '*INFO* My message'. In addition to a programmatic interface being a lot cleaner to use, this API has a benefit that the log messages have accurate timestamps. An obvious limitation is that test libraries using this logging API have a dependency to Robot Framework.

The public logging API is documented as part of the API documentation but here is a simple usage example:

from robot.api import logger

def my_keyword(arg):
    logger.debug('Got argument %s' % arg)
    do_something()
    logger.info('<i>This</i> is a boring example', html=True)
    logger.console('Hello, console!')
Using Python's standard logging module

In addition to the new public logging API, Robot Framework 2.6 also added a built-in support to Python's standard logging module. This works so that all messages that are received by the root logger of the module are automatically propagated to Robot Framework's log file. Also this API produces log messages with accurate timestamps, but logging HTML messages or writing messages to the console are not supported. A big benefit, illustrated also by the simple example below, is that using this logging API creates no dependency to Robot Framework.

import logging

def my_keyword(arg):
    logging.debug('Got argument %s' % arg)
    do_something()
    logging.info('This is a boring example')

The logging module has slightly different log levels than Robot Framework. Its levels DEBUG and INFO are mapped directly to the matching Robot Framework log levels and WARNING and everything above is mapped to WARN. Custom levels below DEBUG are mapped to DEBUG and everything between DEBUG and WARNING is mapped to INFO.

Logging during library initialization

Libraries can also log during the test library import and initialization. These messages do not appear in the log file like the normal log messages, but are instead written to the syslog. This allows logging any kind of useful debug information about the library initialization. Messages logged using the WARN level are also visible in the test execution errors section in the log file.

Logging during the import and initialization is possible both using the standard output and error streams and the programmatic logging APIs. Both of these are demonstrated below.

Java library logging via stdout during initialization:

public class LoggingDuringInitialization {

    public LoggingDuringInitialization() {
        System.out.println("*INFO* Initializing library");
    }

    public void keyword() {
        // ...
    }
}

Python library logging using the logging API during import:

from robot.api import logger

logger.debug("Importing library")

def keyword():
    # ...

Note

If you log something during initialization, i.e. in Python __init__ or in Java constructor, the messages may be logged multiple times depending on the test library scope.

Note

The support for writing log messages to the syslog during the library initialization is a new feature in Robot Framework 2.6.

Returning values

The final way for keywords to communicate back to the core framework is returning information retrieved from the system under test or generated by some other means. The returned values can be assigned to variables in the test data and then used as inputs for other keywords, even from different test libraries.

Values are returned using the return statement both from the Python and Java methods. Normally, one value is assigned into one scalar variable, as illustrated in the example below. This example also illustrates that it is possible to return any objects and to use extended variable syntax to access object attributes.

from mymodule import MyObject

def return_string():
    return "Hello, world!"

def return_object(name):
    return MyObject(name)
Return one value from keywords
${string} = Return String  
Should Be Equal ${string} Hello, world!
${object} = Return Object Robot
Should Be Equal ${object.name} Robot

Keywords can also return values so that they can be assigned into several scalar variables at once, into a list variable, or into scalar variables and a list variable. All these usages require that returned values are Python lists or tuples or in Java arrays, Lists, or Iterators.

def return_two_values():
    return 'first value', 'second value'

def return_multiple_values():
    return ['a', 'list', 'of', 'strings']
Returning multiple values
${var1} ${var2} = Return Two Values  
Should Be Equal ${var1} first value  
Should Be Equal ${var2} second value  
@{list} = Return Two Values    
Should Be Equal @{list}[0] first value  
Should Be Equal @{list}[1] second value  
${s1} ${s2} @{li} = Return Multiple Values
Should Be Equal ${v1} ${v2} a list  
Should Be Equal @{li}[0] @{li}[1] of strings  

Communication when using threads

If a library uses threads, it should generally communicate with the framework only from the main thread. If a worker thread has, for example, a failure to report or something to log, it should pass the information first to the main thread, which can then use exceptions or other mechanisms explained in this section for communication with the framework.

This is especially important when threads are run on background while other keywords are running. Results of communicating with the framework in that case are undefined and can in works case cause a crash or a corrupted output file. If a keyword starts something on background, there should be another keyword that checks the status of the worker thread and reports gathered information accordingly.

Note

Messages logged by non-main threads using the programmatic logging APIs are silently ignored starting from Robot Framework 2.6.2.

4.1.5   Distributing test libraries

Documenting libraries

A test library without documentation about what keywords it contains and what those keywords do is rather useless. To ease maintenance, it is highly recommended that library documentation is included in the source code and generated from it. Basically, that means using docstrings with Python and Javadoc with Java, as in the examples below.

class MyLibrary:
    """This is an example library with some documentation."""

    def keyword_with_short_documentation(self, argument):
        """This keyword has only a short documentation"""
        pass

    def keyword_with_longer_documentation(self):
        """First line of the documentation is here.

        Longer documentation continues here and it can contain
        multiple lines or paragraphs.
        """
        pass
/**
 *  This is an example library with some documentation.
 */
public class MyLibrary {

    /**
     * This keyword has only a short documentation
     */
    public void keywordWithShortDocumentation(String argument) {
    }

    /**
     * First line of the documentation is here.
     *
     * Longer documentation continues here and it can contain
     * multiple lines or paragraphs.
     */
    public void keywordWithLongerDocumentation() {
    }

}

Both Python and Java have tools for creating an API documentation of a library documented as above. However, outputs from these tools can be slightly technical for some users. Another alternative is using Robot Framework's own documentation tool libdoc.py. This tool can create a library documentation from both Python and Java libraries using the static library API, such as the ones above, but it also handles libraries using the dynamic library API and hybrid library API.

The first line of a keyword documentation is used for a special purpose and should contain a short overall description of the keyword. It is used as a short documentation, for example as a tool tip, by libdoc.py and also shown in the test logs. However, the latter does not work with Java libraries using the static API, because their documentations are lost in compilation and not available at runtime.

Note

If you want to use non-ASCII charactes in the documentation of Python libraries, you must either use UTF-8 as your source code encoding or create docstrings as Unicode.

Testing libraries

Any non-trivial test library needs to be thoroughly tested to prevent bugs in them. Of course, this testing should be automated to make it easy to rerun tests when libraries are changed.

Both Python and Java have excellent unit testing tools, and they suite very well for testing libraries. There are no major differences in using them for this purpose compared to using them for some other testing. The developers familiar with these tools do not need to learn anything new, and the developers not familiar with them should learn them anyway.

It is also easy to use Robot Framework itself for testing libraries and that way have actual end-to-end acceptance tests for them. There are plenty of useful keywords in the BuiltIn library for this purpose. One worth mentioning specifically is Run Keyword And Expect Error, which is useful for testing that keywords report errors correctly.

Whether to use a unit- or acceptance-level testing approach depends on the context. If there is a need to simulate the actual system under test, it is often easier on the unit level. On the other hand, acceptance tests ensure that keywords do work through Robot Framework. If you cannot decide, of course it is possible to use both the approaches.

Packaging libraries

After a library is implemented, documented, and tested, it still needs to be distributed to the users. With simple libraries consisting of a single file, it is often enough to ask the users to copy that file somewhere and set the library search path accordingly. More complicated libraries should be packaged to make the installation easier.

Since libraries are normal programming code, they can be packaged using normal packaging tools. With Python, good options include distutils, contained by Python's standard library, and the newer setuptools. A benefit of these tools is that library modules are installed into a location that is automatically in the library search path.

When using Java, it is natural to package libraries into a JAR archive. The JAR package must be put into the library search path before running tests, but it is easy to create a start-up script that does that automatically.

Deprecating keywords

Sometimes there is a need to replace existing keywords with new ones or remove them altogether. Just informing the users about the change may not always be enough, and it is more efficient to get warnings at runtime. To support that, Robot Framework has a capability to mark keywords deprecated. This makes it easier to find old keywords from the test data and remove or replace them.

Keywords are deprecated by starting their documentation with *DEPRECATED*. When these keywords are executed, a warning containing rest of the short documentation is written both into the console and into separate Test Execution Errors section in log files. For example, if following keyword is executed there will be a warning like shown below in the log file.

def example_keyword(argument):
    """*DEPRECATED* Use keyword `Other Keyword` instead.

    This keyword does something to given `argument` and returns the result.
    """
    return do_something(argument)
20080911 16:00:22.650 WARN Keyword 'SomeLibrary.Example Keyword' is deprecated. Use keyword `Other Keyword` instead.

This deprecation system works with most test libraries and also with user keywords. The only exception are keywords implemented in a Java test library that uses the static library interface because their documentation is not available at runtime. With such keywords, it possible to use user keywords as wrappers and deprecate them.

There is a plan to implement a tool that can use the deprecation information for automatically replacing deprecated keywords. The tool will most likely get the name of the new keyword from the documentation so that it searches words inside backticks (`). Thus it would find Other Keyword from the earlier example. Note that libdoc.py also automatically creates internal links using the same syntax.

4.1.6   Dynamic library API

The dynamic API is in most ways similar to the static API. For example, reporting the keyword status, logging, and returning values works exactly the same way. Most importantly, there are no differences in importing dynamic libraries and using their keywords compared to other libraries, so you do not even need to know what APIs the libraries use.

The only difference between static and dynamic libraries is the way how Robot Framework discovers what keywords the library implements, what arguments and documentation they have and how those keywords are actually executed. With the static API, all this is done using reflection (except for the documentation of Java libraries), but dynamic libraries have special methods that are used for these purposes.

One of the benefits of the dynamic API is that you have more flexibility in organizing your library. With the static API, you have all keywords in one class (or module), whereas with the dynamic API, you can, for example, implement each keyword as a separate class, if you want. This use case is not so important with Python, because its dynamic capabilities and multi-inheritance already give plenty of flexibility and the hybrid library API is usually a better option.

Another major use case for the dynamic API is implementing a library so that it is only a proxy for an actual library on some other computer or another JVM. This kind of a proxy library can be very thin, and because keyword names are got dynamically, there is no need to update the proxy when new keywords are added into the actual library.

This section explains how the dynamic API works between Robot Framework and dynamic libraries. It does not matter for Robot Framework how these libraries are actually implemented (for example, how calls to the run_keyword method are mapped to a correct keyword implementation), and many different approaches are possible. However, if you use Java, you may want to examine JavaTools before implementing your own system. This collection of reusable tools supports several ways of creating keywords, and it is likely that it already has a mechanism that suites your needs.

Getting keyword names

Dynamic libraries tell what keywords they implement with the get_keyword_names method. The method also has the alias getKeywordNames that is recommended when writing Java. This method cannot take any arguments, and it must return a list of strings (in Python) or a string array (in Java) containing the names of the keywords that the library implements.

If the returned keyword names contain several words, they can be returned separated with spaces or underscores, or in the camelCase format. For example, ['first keyword', 'second keyword'], ['first_keyword', 'second_keyword'], and ['firstKeyword', 'secondKeyword'] would all result in the keywords First Keyword and Second Keyword.

Dynamic libraries must always have this method. If it is missing, or if calling it fails for some reason, the library is considered a static library, instead.

Running keywords

Dynamic libraries have a special run_keyword (alias runKeyword) method for executing their keywords. When a keyword from a dynamic library is used in the test data, Robot Framework uses the library's run_keyword method to get it executed. This method takes two arguments. The first argument is a string containing the name of the keyword to be executed in the same format as returned by get_keyword_names. The second argument is a list of arguments (an object array in Java) given to the keyword in the test data.

After the library has got the keyword name and arguments, it can execute the keyword freely, but it must use the same mechanism to communicate with the framework as static libraries. This means using exceptions for reporting keyword status, logging by writing to the standard output and using the return statement in run_keyword for returning something.

Every dynamic library must have both the get_keyword_names and run_keyword methods. The rest of the methods in the dynamic API are optional, so the example below shows a working (albeit trivial) dynamic library.

class DynamicExample:

    def get_keyword_names(self):
        return ['first keyword', 'second keyword']

    def run_keyword(self, name, args):
        print "Running keyword %s with arguments %s" % (name, args)

Getting keyword arguments

If a dynamic library only implements the get_keyword_names and run_keyword methods, Robot Framework does not have any information about the arguments that the implemented keywords need. For example, both First Keyword and Second Keyword in the example above could be used with any number of arguments. This is problematic, because most real keywords expect a certain number of keywords, and under these circumstances they would need to check the argument counts themselves.

Dynamic libraries can tell Robot Framework what arguments the keywords that it implements actually expect using get_keyword_arguments (alias getKeywordArguments) method. This method takes the name of a keyword as an argument and returns a list of strings (a string array in Java) containing the arguments accepted by that keyword.

Similarly as static keywords, dynamic keywords can require any number of arguments, have default values and accept a variable number of arguments. The syntax for how to represent all these different situations is explained in the following table. Note that the examples use Python lists of strings, but Java developers should be able to translate them to string arrays.

Representing different arguments with get_keyword_arguments
Expected arguments How to represent Examples Min / Max
No arguments Empty list. [] 0/0
One or more argument List of strings containing argument names. ['one_argument'], ['a1', 'a2', 'a3'] 1/1, 3/3
Default values for arguments Default values separated from names with =. Default values are always considered to be strings. ['arg=default value'], ['a', 'b=1', 'c=2'] 0/1, 1/3
Variable number of arguments Last argument has * before its name. ['*arguments'], ['a', 'b=42', '*rest'] 0/any, 1/any

When the get_keyword_arguments is used, Robot Framework automatically calculates how many arguments the keywords require. If a keyword is used with an invalid number of arguments, an error occurs and run_keyword is not even called. The last column of the table above shows the minimum and maximum argument counts calculated from the presented examples.

The actual argument names do not matter when tests are executed, because only argument counts are of concern to Robot Framework. On the other hand, if the libdoc.py tool is used for documenting the library, arguments are shown in the documentation, in which case they need to have meaningful names.

Getting keyword documentation

The final special method that dynamic libraries can implement is get_keyword_documentation (alias getKeywordDocumentation). It takes a keyword name as an argument and, as the method name implies, returns its documentation as a string.

The returned documentation is used similarly as the keyword documentation string with static libraries implemented with Python. The main use case is getting keywords' documentations into a library documentation generated with libdoc.py. Additionally, the first line of the documentation (until the first \n) is shown in test logs.

Getting general library documentation

The get_keyword_documentation method can also be used for specifying overall library documentation. This documentation is not used when tests are executed, but it can make the documentation generated by libdoc.py much better.

Dynamic libraries can provide both general library documentation and documentation related to taking the library into use. The former is got by calling get_keyword_documentation with special value __intro__, and the latter is got using value __init__. How the documentation is presented is best tested with libdoc.py in practice.

Python based dynamic libraries can also specify the general library documentation directly in the code as the docstring of the library class or its __init__ method. If non-empty documentation is got both directly from the code and from the get_keyword_documentation method, the latter has higher priority.

Note

Getting general library documentation is supported in Robot Framework 2.6.2 and newer.

Summary

All special methods in the dynamic API are listed in the table below. Method names are listed in the underscore format, but their camelCase aliases work exactly the same way.

All special methods in the dynamic API
Name Arguments Purpose
get_keyword_names   Return names of the implemented keywords.
run_keyword name, arguments Execute the specified keyword with given arguments.
get_keyword_arguments name Return keywords' argument specifications. Optional.
get_keyword_documentation name Return keywords' and library's documentation. Optional.

It is possible to write a formal interface specification in Java, as below. However, remember that libraries do not need to implement any explicit interface, because Robot Framework directly checks with reflection if the library has the required get_keyword_names and run_keyword methods. Additionally, get_keyword_arguments and get_keyword_documentation are completely optional.

public interface RobotFrameworkDynamicAPI {

    String[] getKeywordNames();

    Object runKeyword(String name, Object[] arguments);

    String[] getKeywordArguments(String name);

    String getKeywordDocumentation(String name);

}

A good example of using the dynamic API is Robot Framework's own Remote library.

4.1.7   Hybrid library API

The hybrid library API is, as its name implies, a hybrid between the static API and the dynamic API. Just as with the dynamic API, it is possible to implement a library using the hybrid API only as a class.

Getting keyword names

Keyword names are got in the exactly same way as with the dynamic API. In practice, the library needs to have the get_keyword_names or getKeywordNames method returning a list of keyword names that the library implements.

Running keywords

In the hybrid API, there is no run_keyword method for executing keywords. Instead, Robot Framework uses reflection to find methods implementing keywords, similarly as with the static API. A library using the hybrid API can either have those methods implemented directly or, more importantly, it can handle them dynamically.

In Python, it is easy to handle missing methods dynamically with the __getattr__ method. This special method is probably familiar to most Python programmers and they can immediately understand the following example. Others may find it easier to consult Python Reference Manual first.

from somewhere import external_keyword

class HybridExample:

    def get_keyword_names(self):
        return ['my_keyword', 'external_keyword']

    def my_keyword(self, arg):
        print "My Keyword called with '%s'" % arg

    def __getattr__(self, name):
        if name == 'external_keyword':
            return external_keyword
        raise AttributeError("Non-existing attribute '%s'" % name)

Note that __getattr__ does not execute the actual keyword like run_keyword does with the dynamic API. Instead, it only returns a callable object that is then executed by Robot Framework.

Another point to be noted is that Robot Framework uses the same names that are returned from get_keyword_names for finding the methods implementing them. Thus the names of the methods that are implemented in the class itself must be returned in the same format as they are defined. For example, the library above would not work correctly, if get_keyword_names returned My Keyword instead of my_keyword.

The hybrid API is not very useful with Java, because it is not possible to handle missing methods with it. Of course, it is possible to implement all the methods in the library class, but that brings few benefits compared to the static API.

Getting keyword arguments and documentation

When this API is used, Robot Framework uses reflection to find the methods implementing keywords, similarly as with the static API. After getting a reference to the method, it searches for arguments and documentation from it, in the same way as when using the static API. Thus there is no need for special methods for getting arguments and documentation like there is with the dynamic API.

Summary

When implementing a test library in Python, the hybrid API has the same dynamic capabilities as the actual dynamic API. A great benefit with it is that there is no need to have special methods for getting keyword arguments and documentation. It is also often practical that the only real dynamic keywords need to be handled in __getattr__ and others can be implemented directly in the main library class.

Because of the clear benefits and equal capabilities, the hybrid API is in most cases a better alternative than the dynamic API when using Python. One notable exception is implementing a library as a proxy for an actual library implementation elsewhere, because then the actual keyword must be executed elsewhere and the proxy can only pass forward the keyword name and arguments.

A good example of using the hybrid API is Robot Framework's own Telnet library.

4.1.8   Using Robot Framework's internal modules

Test libraries implemented with Python can use Robot Framework's internal modules, for example, to get information about the executed tests and the settings that are used. This powerful mechanism to communicate with the framework should be used with care, though, because all Robot Framework's APIs are not meant to be used by externally and they might change radically between different framework versions.

The safest API to use are methods implementing keywords in the BuiltIn library. Changes to keywords are rare and they are always done so that old usage is first deprecated. One of the most useful methods is replace_variables which allows accessing currently available variables. The following example demonstrates how to get ${OUTPUT_DIR} which is one of the many handy automatic variables. It is also possible to set new variables from libraries using set_test_variable, set_suite_variable and set_global_variable.

import os.path
from robot.libraries.BuiltIn import BuiltIn

def do_something(argument):
    output = do_something_that_creates_a_lot_of_output(argument)
    outputdir = BuiltIn().replace_variables('${OUTPUTDIR}')
    path = os.path.join(outputdir, 'results.txt')
    f = open(path, 'w')
    f.write(output)
    f.close()
    print '*HTML* Output written to <a href="results.txt">results.txt</a>'

The only catch with using methods from BuiltIn is that all run_keyword method variants must be handled specially. Methods that use run_keyword methods have to be registered as run keywords themselves using register_run_keyword method in BuiltIn module. This method's documentation explains why this needs to be done and obviously also how to do it.

The plan is to document all the internal modules better so that it is easier to decide which can be used and how they should be used. If you are unsure is using some API safe, please send a question to either user or developer mailing list.

4.1.9   Extending existing test libraries

This section explains different approaches how to add new functionality to existing test libraries and how to use them in your own libraries otherwise.

Modifying original source code

If you have access to the source code of the library you want to extend, you can naturally modify the source code directly. The biggest problem of this approach is that it can be hard for you to update the original library without affecting your changes. For users it may also be confusing to use a library that has different functionality than the original one. Repackaging the library may also be a big extra task.

This approach works extremely well if the enhancements are generic and you plan to submit them back to the original developers. If your changes are applied to the original library, they are included in the future releases and all the problems discussed above are mitigated. If changes are non-generic, or you for some other reason cannot submit them back, the approaches explained in the subsequent sections probably work better.

Using inheritance

Another straightforward way to extend an existing library is using inheritance. This is illustrated by the example below that adds new Title Should Start With keyword to the SeleniumLibrary. This example uses Python, but you can obviously extend an existing Java library in Java code the same way.

from SeleniumLibrary import SeleniumLibrary

class ExtendedSeleniumLibrary(SeleniumLibrary):

    def title_should_start_with(self, expected):
        title = self.get_title()
        if not title.startswith(expected):
            raise AssertionError("Title '%s' did not start with '%s'"
                                 % (title, expected))

A big difference with this approach compared to modifying the original library is that the new library has a different name than the original. A benefit is that you can easily tell that you are using a custom library, but a big problem is that you cannot easily use the new library with the original. First of all your new library will have same keywords as the original meaning that there is always conflict. Another problem is that the libraries do not share their state.

This approach works well when you start to use a new library and want to add custom enhancements to it from the beginning. Otherwise other mechanisms explained in this section are probably better.

Using other libraries directly

Because test libraries are technically just classes or modules, a simple way to use another library is importing it and using its methods. This approach works great when the methods are static and do not depend on the library state. This is illustrated by the earlier example that uses Robot Framework's BuiltIn library.

If the library has state, however, things may not work as you would hope. The library instance you use in your library will not be the same as the framework uses, and thus changes done by executed keywords are not visible to your library. The next section explains how to get an access to the same library instance that the framework uses.

Getting active library instance from Robot Framework

Robot Framework 2.5.2 added new BuiltIn keyword Get Library Instance that can be used to get the currently active library instance from the framework itself. The library instance returned by this keyword is the same as the framework itself uses, and thus there is no problem seeing the correct library state. Although this functionality is available as a keyword, it is typically used in test libraries directly by importing the BuiltIn library class as discussed earlier. The following example illustrates how to implement the same Title Should Start With keyword as in the earlier example about using inheritance.

from robot.libraries.BuiltIn import BuiltIn

def title_should_start_with(expected):
    seleniumlib = BuiltIn().get_library_instance('SeleniumLibrary')
    title = seleniumlib.get_title()
    if not title.startswith(expected):
        raise AssertionError("Title '%s' did not start with '%s'"
                             % (title, expected))

This approach is clearly better than importing the library directly and using it when the library has a state. The biggest benefit over inheritance is that you can use the original library normally and use the new library in addition to it when needed. That is demonstrated in the example below where the code from the previous examples is expected to be available in a new library SeLibExtensions.

Using library and another library that extends it
Settings Value Value Value
Library SeleniumLibrary    
Library SeLibExtensions    
Test Case Action Argument Argument
Example Open Browser http://example # SeleniumLibrary
Title Should Start With Example # SeLibExtensions

Libraries using dynamic or hybrid API

Test libraries that use the dynamic or hybrid library API often have their own systems how to extend them. With these libraries you need to ask guidance from the library developers or consult the library documentation or source code.

4.2   Remote library interface

The remote library interface provides means for having test libraries on different machines than where Robot Framework itself is running, and also for implementing libraries using other languages than the natively supported Python and Java. For a test library user remote libraries look pretty much the same as any other test library, and developing test libraries using the remote library interface is also very close to creating normal test libraries.

4.2.1   Introduction

There are two main reasons for using the remote library API:

  • It is possible to have actual libraries on different machines than where Robot Framework is running. This allows interesting possibilities for distributed testing.
  • Test libraries can be implemented using any language that supports XML-RPC protocol. Robot Framework 2.1 contains generic remote servers for Python/Jython and Ruby, and the plan is to implement generic servers for other languages like Java and Perl in the future.

The remote library interface is provided by the Remote library that is one of the standard libraries starting from Robot Framework 2.1. This library does not have any keywords of its own, but it works as a proxy between the core framework and keywords implemented elsewhere. The Remote library interacts with actual library implementations through remote servers, and the Remote library and servers communicate using a simple remote protocol on top of an XML-RPC channel. The high level architecture of all this is illustrated in the picture below:

src/ExtendingRobotFramework/remote.png

Robot Framework architecture with Remote library

4.2.2   Taking Remote library into use

Importing Remote library

The Remote library needs to know the address of the remote server but otherwise importing it and using keywords that it provides is no different to how other libraries are used. If you need to use the Remote library multiple times in a test suite, or just want to give it a more descriptive name, you can import it using the WITH NAME syntax.

Importing Remote library
Setting Value Value Value Value
Library Remote http://localhost:8270 WITH NAME Example1
Library Remote http://10.0.0.42:7777 WITH NAME Example2

The URL used by the first example above is also the default address that the Remote library uses if no address is given. Similarly port 8270 is the default port the provided remote servers use. (82 and 70 are the ASCII codes of letters R and F, respectively.)

Starting and stopping remote servers

Before the Remote library can be imported, the remote server providing the actual keywords must be started. If the server is started before launching the test execution, it is possible to use the normal Library setting like in the above example. Alternatively other keywords, for example from OperatingSystem or SSH libraries, can start the server up, but then you may need to use Import Library keyword because the library is not available when the test execution starts.

How a remote server can be stopped depends on how it is implemented. Following methods work with the servers distributed with Robot Framework:

  • Regardless of the library used, remote servers provide Stop Remote Server keyword that can be used from the test data.
  • Remote servers have stop_remote_server method in their XML-RPC interface.
  • Ctrl-C stops the server if it is running on a terminal window. Unfortunately this does not work with all servers on all operating systems.
  • The server process can be terminated using tools provided by the operating system (e.g. kill).

Note

The server may be configured so that users cannot stop it with Stop Remote Server keyword or stop_remote_server method.

4.2.3   Supported argument and return value types

Because the XML-RPC protocol does not support all possible object types, the values transferred between the Remote library and remote servers must be converted to compatible types. This applies to the keyword arguments the Remote library passes to remote servers and to the return values servers give back to the Remote library.

The conversions are done using following rules:

  • Strings, numbers and Boolean values are passed without modifications.
  • The None/nil value is converted to an empty string.
  • Lists (and tuples in Python) are passed as lists so that their contents are converted recursively.
  • Dictionaries/maps are passed so that their values are converted to supported types recursively and keys are converted to strings.
  • Other types are converted to strings.

4.2.4   Using remote servers

Robot Framework 2.1 includes remote server implementations written both in Python and Ruby. These servers, as well as the example libraries shown below and an example test case file, are included in source distributions under tools/remoteserver directory and available also at http://code.google.com/p/robotframework/wiki/RemoteLibrary.

The provided servers are designed so that it is easy to create test libraries using them. With both of the servers the basic procedure is as follows:

  • Create a test library module or class similarly as a normal test library using the static library API. With the Python server it is also possible to use the hybrid library API.
  • Import the remote server class and create an instance of it giving the library instance or module to it as an argument. The listening address and port, possibly got from the command line, can be given as optional arguments.

Both these steps can be done in the same module as illustrated by the examples below. Executing these modules as scripts from the command line will start the remote server so that it serves the keywords implemented in the library.

Python remote library example

This example demonstrates how to use the Python version of the remote server. The example library implements keywords Count Items In Directory and Strings Should Be Equal.

#!/usr/bin/env python

import os
import sys


class ExampleRemoteLibrary:
    """Example library to be used with Robot Framework's remote server.

    This documentation is visible in docs generated by _libdoc.py_
    starting from Robot Framework 2.6.2.
    """

    def __init__(self):
        """Also this doc should be in shown in library doc."""

    def count_items_in_directory(self, path):
        """Returns the number of items in the directory specified by `path`."""
        return len([i for i in os.listdir(path) if not i.startswith('.')])

    def strings_should_be_equal(self, str1, str2):
        print "Comparing '%s' to '%s'" % (str1, str2)
        if str1 != str2:
            raise AssertionError("Given strings are not equal")


if __name__ == '__main__':
    from robotremoteserver import RobotRemoteServer
    RobotRemoteServer(ExampleRemoteLibrary(), *sys.argv[1:])

Ruby remote library example

This example uses the Ruby remote server and provides exactly same keywords as the previous Python example:

#!/usr/bin/env ruby

class ExampleRemoteLibrary

  def count_items_in_directory(path)
    Dir.entries(path).find_all{|i| not i.match('^\.')}.length
  end 

  def strings_should_be_equal(str1, str2)
    puts "Comparing '#{str1}' to '#{str2}'"
    if str1 != str2
      raise RuntimeError, "Given strings are not equal"
    end
  end

end


if __FILE__ == $0
  require "robotremoteserver"
  RobotRemoteServer.new(ExampleRemoteLibrary.new, *ARGV)
end

4.2.5   Remote protocol

This section explains the protocol that is used between the Remote library and remote servers. This information is mainly targeted for people who want to create new remote servers. The provided Python and Ruby servers can also be used as examples.

The remote protocol is implemented on top of XML-RPC, which is a simple remote procedure call protocol using XML over HTTP. Most mainstream languages (Python, Java, C, Ruby, Perl, Javascript, PHP, ...) have a support for XML-RPC either built-in or as extensions.

Required methods

A remote server is an XML-RPC server that must have the same methods in its public interface as the dynamic library API has. Only get_keyword_names and run_keyword are actually required, but get_keyword_arguments and get_keyword_documentation are also recommended. Notice that using camelCase format in method names is not possible currently. How the actual keywords are implemented is not relevant for the Remote library. A remote server can either act as a wrapper for real test libraries, like the provided Python and Ruby servers do, or it can implement keywords itself.

Remote servers should additionally have stop_remote_server method in their public interface to ease stopping them. They should also expose this method as Stop Remote Server keyword automatically so that it can be used in the test data regardless of the test library. Allowing users to stop the server using these methods is not always desirable, and servers can choose to allow disabling them via some configuration parameter.

The provided Python remote server can be used as a reference implementation.

Getting remote keyword names and other information

The Remote library gets a list of keywords that the remote server provides using get_keyword_names method. This method must return the keyword names as a list of strings.

Remote servers can, and should, also implement get_keyword_arguments and get_keyword_documentation methods to provide more information about the keywords. Both of these keywords get the name of the keyword as an argument. Arguments must be returned as a list of strings in the same format as with dynamic libraries, and documentation must be returned as a string.

Starting from Robot Framework 2.6.2, remote servers can also provide general library documentation to be used when generating documenation with libdoc.py tool.

Executing remote keywords

When the Remote library wants the server to execute some keyword, it calls remote server's run_keyword method and passes it the keyword name and a list of arguments. Base types can be used as arguments directly but more complex types are converted to supported types.

The server must return results of the execution in a result dictionary (or map, depending on terminology) containing items explained in the following table.

Entries in the remote result dictionary
Name Explanation
status Mandatory execution status. Either PASS or FAIL.
output Possible output to write into the log file. Must be given as a single string but can contain multiple messages and different log levels in format *INFO* First message\n*INFO* Second\n*WARN* Another message.
return Possible return value. Must be one of the supported types.
error Possible error message. Used only when the execution fails.
traceback Possible stack trace to write into the log file using DEBUG level when the execution fails.

4.3   Using listener interface

Robot Framework has a listener interface that can be used to receive notifications about test execution. Listeners are classes or modules with certain special methods, and they can be implemented both with Python and Java. Example uses of the listener interface include external test monitors, sending a mail message when a test fails, and communicating with other systems.

4.3.1   Taking listeners into use

Listeners are taken into use from the command line with the --listener option, so that the name of the listener is given to it as an argument. The listener name is got from the name of the class or module implementing the listener interface, similarly as test library names are got from classes implementing them. The specified listeners must be in the same module search path where test libraries are searched from when they are imported. Other option is to give an absolute or a relative path to the listener file similarly as with test libraries. It is possible to take multiple listeners into use by using this option several times.

It is also possible to give arguments to listener classes from the command line. Arguments are specified after the listener name (or path) using a colon as a separator. This approach provides only string type arguments and arguments obviously cannot contain colons. However, it should be pretty easy to listeners to go around these limitations.

Examples:

pybot --listener MyListener tests.html
jybot --listener com.company.package.Listener tests.html
pybot --listener path/to/MyListener.py tests.html
pybot --listener module.Listener --listener AnotherListener tests.html
pybot --listener ListenerWithArgs:arg1:arg2
pybot --listener path/to/MyListener.java:argument tests.html

4.3.2   Available listener interface methods

Robot Framework creates an instance of the listener class with given arguments when test execution starts. During the test execution, Robot Framework calls listeners' methods when test suites, test cases and keywords start and end. It also calls the appropriate methods when output files are ready, and finally at the end it calls the close method. A listener is not required to implement any official interface, and it only needs to have the methods it actually needs.

Listener interface versions

The signatures of methods related to test execution progress were changed in Robot Framework 2.1. This change was made so that new information can be added to listener interface without breaking existing listeners. The old signatures will continue to work, but they will be deprecated in some future version, so all new listeners should be implemented with signatures described in the table below. The most recent detailed description of the old listener interface can be found in User Guide of Robot Framework 2.0.4.

Note

A listener must have attribute ROBOT_LISTENER_API_VERSION defined in order to be recognized as a new style listener. Value of the ROBOT_LISTENER_API_VERSION attribute must be 2, either as a string or as an integer. The examples below are implemented as new style listeners.

Listener interface method signatures

All listener methods related to test execution progress have the same signature method(name, attributes), where attributes is a dictionary containing details of the event. The following table lists all the available methods in the listener interface and the contents of the attributes dictionary, where applicable. Keys of the dictionary are strings. All of these methods have also camelCase aliases. Thus, for example, startSuite is a synonym to start_suite.

Available methods in the listener interface
Method Arguments Attributes / Explanation
start_suite name, attributes

Keys in the attribute dictionary:

  • longname: suite name including parent suites
  • doc: test suite documentation
  • metadata: dictionary/map containing free test suite metadata (new in 2.5)
  • suites: names of suites directly in this suite as a list of strings (new in 2.5)
  • tests: names of tests directly in this suite as a list of strings (new in 2.5)
  • totaltests: total number of tests in this suite and all its sub-suites as an integer (new in 2.5)
  • starttime: execution start time
end_suite name, attributes

Keys in the attribute dictionary:

  • longname: test suite name including parents
  • doc: test suite documentation
  • metadata: dictionary/map containing free test suite metadata (new in 2.6)
  • starttime: execution start time
  • endtime: execution end time
  • elapsedtime: execution time in milliseconds as an integer
  • status: either PASS or FAIL
  • statistics: suite statistics (number of passed and failed tests in the suite) as a string
  • message: error message if the suite setup or teardown has failed, empty otherwise
start_test name, attributes

Keys in the attribute dictionary:

  • longname: test name including parent suites
  • doc: test case documentation
  • tags: test case tags as a list of strings
  • critical: yes or no depending is test considered critical or not (new in 2.6)
  • template: contains the name of the template used for the test. If the test is not templated it will be an empty string (new in 2.6)
  • starttime: execution start time
end_test name, attributes

Keys in the attribute dictionary:

  • longname: test name including parent suites
  • doc: test case documentation
  • tags: test case tags as a list of strings
  • critical: yes or no depending is test considered critical or not (new in 2.6)
  • template: contains the name of the template used for the test. If the test is not templated it will be an empty string (new in 2.6)
  • starttime: execution start time
  • endtime: execution end time
  • elapsedtime: execution time in milliseconds as an integer
  • status: either PASS or FAIL
  • message: status message, normally an error message or an empty string
start_keyword name, attributes

Keys in the attribute dictionary:

  • type: string Keyword for normal keywords and Test Setup, Test Teardown, Suite Setup or Suite Teardown for keywords used in suite/test setup/teardown (new in 2.6)
  • doc: keyword documentation
  • args: keyword's arguments as a list of strings
  • starttime: execution start time
end_keyword name, attributes

Keys in the attribute dictionary:

  • type: same as with start_keyword
  • doc: keyword documentation
  • args: keyword's arguments as a list of strings
  • starttime: execution start time
  • endtime: execution end time
  • elapsedtime: execution time in milliseconds as an integer
  • status: either PASS or FAIL
log_message message

Called when an executed keyword writes a log message. message is a dictionary with the following keys:

  • message: the content of the message
  • level: log level used in logging the message
  • timestamp: message creation time, format is YYYY-MM-DD hh:mm:ss.mil
  • html: string yes or no denoting whether the message should be interpreted as HTML or not
message message Called when the framework itself writes a syslog message. message is a dictionary with same keys as with log_message method.
output_file path Called when writing to an output file is finished. The path is an absolute path to the file.
log_file path Called when writing to a log file is finished. The path is an absolute path to the file.
report_file path Called when writing to a report file is finished. The path is an absolute path to the file.
summary_file path Not available anymore in Robot Framework 2.6 or newer.
debug_file path Called when writing to a debug file is finished. The path is an absolute path to the file.
close   Called after all test suites, and test cases in them, have been executed.

The available methods and their arguments are also shown in a formal Java interface specification below. Contents of the java.util.Map attributes are as in the table above. It should be remembered that a listener does not need to implement any explicit interface or have all these methods.

public interface RobotListenerInterface {
    public static final int ROBOT_LISTENER_API_VERSION = 2;
    void startSuite(String name, java.util.Map attributes);
    void endSuite(String name, java.util.Map attributes);
    void startTest(String name, java.util.Map attributes);
    void endTest(String name, java.util.Map attributes);
    void startKeyword(String name, java.util.Map attributes);
    void endKeyword(String name, java.util.Map attributes);
    void logMessage(java.util.Map message);
    void message(java.util.Map message);
    void outputFile(String path);
    void logFile(String path);
    void reportFile(String path);
    void debugFile(String path);
    void close();
}

4.3.3   Listeners logging

Robot Framework 2.6 introduced new programmatic logging APIs that also listeners can utilize. There are some limitations, however, and how different listener methods can log messages is explained in the table below.

How listener methods can log
Methods Explanation
start_keyword, end_keyword, log_message Messages are logged to the normal log file under the executed keyword.
start_suite, end_suite, start_test, end_test Messages are logged to the syslog. Warnings are shown also in the execution errors section of the normal log file.
message Messages are normally logged to the syslog. If this method is used while a keyword is executing, messages are logged to the normal log file.
Other methods Messages are only logged to the syslog.

Note

To avoid recursion, messages logged by listeners are not sent to listener methods log_message and message.

Warning

There were severe problems with listeners logging prior to Robot Framework 2.6.2. Using this functionality with earlier versions is thus not recommended.

4.3.4   Listener examples

The first simple example is implemented in a Python module. It mainly illustrates that using the listener interface is not very complicated.

ROBOT_LISTENER_API_VERSION = 2

def start_test(name, attrs):
    print 'Executing test %s' % name

def start_keyword(name, attrs):
    print 'Executing keyword %s with arguments %s' % (name, attrs['args'])

def log_file(path):
    print 'Test log available at %s' % path

def close():
    print 'All tests executed'

The second example, which still uses Python, is slightly more complicated. It writes all the information it gets into a text file in a temporary directory without much formatting. The filename may be given from the command line, but also has a default value. Note that in real usage, the debug file functionality available through the command line option --debugfile is probably more useful than this example.

import os.path
import tempfile


class PythonListener:

    ROBOT_LISTENER_API_VERSION = 2

    def __init__(self, filename='listen.txt'):
        outpath = os.path.join(tempfile.gettempdir(), filename)
        self.outfile = open(outpath, 'w')

    def start_suite(self, name, attrs):
        self.outfile.write("%s '%s'\n" % (name, attrs['doc']))

    def start_test(self, name, attrs):
        tags = ' '.join(attrs['tags'])
        self.outfile.write("- %s '%s' [ %s ] :: " % (name, attrs['doc'], tags))

    def end_test(self, name, attrs):
        if attrs['status'] == 'PASS':
            self.outfile.write('PASS\n')
        else:
            self.outfile.write('FAIL: %s\n' % attrs['message'])

     def end_suite(self, name, attrs):
         self.outfile.write('%s\n%s\n' % (attrs['status'], attrs['message']))

     def close(self):
         self.outfile.close()

The third example implements the same functionality as the previous one, but uses Java instead of Python.

import java.io.*;
import java.util.Map;
import java.util.List;


public class JavaListener {

    public static final int ROBOT_LISTENER_API_VERSION = 2;
    public static final String DEFAULT_FILENAME = "listen_java.txt";
    private BufferedWriter outfile = null;

    public JavaListener() throws IOException {
        this(DEFAULT_FILENAME);
    }

    public JavaListener(String filename) throws IOException {
        String tmpdir = System.getProperty("java.io.tmpdir");
        String sep = System.getProperty("file.separator");
        String outpath = tmpdir + sep + filename;
        outfile = new BufferedWriter(new FileWriter(outpath));
    }

    public void startSuite(String name, Map attrs) throws IOException {
        outfile.write(name + " '" + attrs.get("doc") + "'\n");
    }

    public void startTest(String name, Map attrs) throws IOException {
        outfile.write("- " + name + " '" + attrs.get("doc") + "' [ ");
        List tags = (List)attrs.get("tags");
        for (int i=0; i < tags.size(); i++) {
           outfile.write(tags.get(i) + " ");
        }
        outfile.write(" ] :: ");
    }

    public void endTest(String name, Map attrs) throws IOException {
        String status = attrs.get("status").toString();
        if (status.equals("PASS")) {
            outfile.write("PASS\n");
        }
        else {
            outfile.write("FAIL: " + attrs.get("message") + "\n");
        }
    }

    public void endSuite(String name, Map attrs) throws IOException {
        outfile.write(attrs.get("status") + "\n" + attrs.get("message") + "\n");
    }

    public void close() throws IOException {
        outfile.close();
    }

}

4.4   Using internal APIs

Robot Framework has some public APIs which are intended to help in developing supporting tools or extending the processing of input or output data. These APIs are implemented as Python modules, and as such can only be used from Python and Jython scripts and programs.

Unfortunately, these APIs are not particularly well documented, and are subject to change and refinement in the future. The plan is to enhance the documentation in the future, but before that the options for getting more information are asking help from Robot Framework developers, investigating existing supporting tools that use these APIs, or just taking a look at the source code of Robot Framework.

4.4.1   Executed test data

This API consists of a factory method for reading a Robot Framework output file into a TestSuite object that contains all the relevant information about the results of the test execution. Signature of method is TestSuite(outpath), where outpath is a path to an existing output file. The returned TestSuite object can be used to process the results of the test run.

Here is an example that reads a given output file and marks each test case whose execution time is longer than three minutes failed. The TestSuite object is then serialized and normal log and report files could be generated with rebot.

#!/usr/bin/env python

"""Usage: check_test_times.py inpath [outpath]

Reads result of a test run from Robot output file and checks that no test 
took longer than 3 minutest to execute. If outpath is not given, the
result is written over the original file.
"""

import sys
from robot.output import TestSuite


def check_tests(inpath, outpath=None):
    if not outpath:
        outpath = inpath
    suite = TestSuite(inpath)
    _check_execution_times(suite)
    suite.write_to_file(outpath)

def _check_execution_times(suite):
    for test in suite.tests:
        if test.status == 'PASS' and test.elapsedtime > 1000 * 60 * 3:
            test.status = 'FAIL'
            test.message = 'Test execution time was too long: %s' % test.elapsedtime
    for suite in suite.suites:
        _check_execution_times(suite)


if __name__ == '__main__':
    try:
        check_tests(*sys.argv[1:])
    except TypeError:
        print __doc__

4.4.2   Test execution

This API consists of run method, which can be used for starting the test execution. Signature of the method is run(*datasources, **options), where datasources are paths to files and directories to be executed and options are same as normal command line options without hyphens.

from robot import run

run('tests.html', log='mylog.html', include=['tag1', 'tag2'])

Equivalent command line usage would be:

pybot --log mylog.html --include tag1 --include tag2 tests.html

Warning

This method can be used only once in a given context. This problem will be fixed in future releases.

4.4.3   Parsed test data

Package robot.parsing contains tools for parsing and handling test data. TestCaseFile and TestDataDirectory classes can be instantiated with named argument source to start parsing existing test data. Example below shows how to parse names of tests from a test file. For more details please see the source code of Robot Framework directly.

from robot.parsing import TestCaseFile

suite = TestCaseFile(source='path/to/tests.html')
print 'Suite: ', suite.name
for test in suite.testcase_table:
    print test.name

4.4.4   Runnable test data

This API consists of a factory method for parsing given input files into a runnable TestSuite object. The signature of this robot.running.TestSuite method is TestSuite(datasources, settings), where data sources are paths to files and directories similarly as when executing tests from the command line.

4.4.5   Configuring logging

Robot Framework has a global logger that is responsible for error reporting and logging in general. This LOGGER instance is a proxy and it is possible to register new loggers to it. Registered loggers get notifications when something happens and they can report events however they want. A console logger writing warnings and errors into the standard error stream is registered automatically but it can be disabled. For more information about how to register loggers and what methods loggers can implement, see the source code and documentation of robot.output.LOGGER.

4.5   Using Robot Framework from Java

Starting from Robot Framework 2.5.2 Robot Framework is also distributed as a standalone jar file that contains both Jython and Robot Framework. This allows command line execution with only Java installed, but the jar file also provides an API for Java usage. The current API documentation is available online.

4.5.1   Running tests via the API

The simple code below demonstrates how Robot Framework test execution can be started from a Java program:

import org.robotframework.RobotFramework;

public class Test {

    public void runTests() {
        int rc = RobotFramework.run(new String[] { "--outputdir", "/tmp", "mytests" });
        if (rc == 0)
            System.out.println("All tests passed");
        else if (rc <= 250)
            System.out.println(rc + " tests failed.");
        else
            System.out.println("Error occurred");
    }

}

Return value of RobotFramework.run has same meaning as return code of Robot Framework execution.

5   Appendices

5.1   All available settings in test data

5.1.1   Setting table

The Setting table is used to import test libraries, resource files and variable files and to define metadata for test suites and test cases. It can be included in test case files and resource files. Note that in a resource file, a Setting table can only include settings for importing libraries, resources, and variables.

Settings available in the Setting table
Name Description
Library Used for taking test libraries into use.
Resource Used for taking resource files into use.
Variables Used for taking variable files into use.
Documentation Used for specifying a test suite or resource file documentation.
Metadata Used for setting free test suite metadata.
Suite Setup Used for specifying the suite setup.
Suite Teardown Used for specifying the suite teardown.
Suite Precondition A synonym for Suite Setup.
Suite Postcondition A synonym for Suite Teardown.
Force Tags Used for specifying forced values for tags when tagging test cases.
Default Tags Used for specifying default values for tags when tagging test cases.
Test Setup Used for specifying a default test setup.
Test Teardown Used for specifying a default test teardown.
Test Precondition A synonym for Test Setup.
Test Postcondition A synonym for Test Teardown.
Test Template Used for specifying a default template keyword for test cases.
Test Timeout Used for specifying a default test case timeout.

Note

All setting names can optionally include a colon at the end, for example Documentation:. This can make reading the settings easier especially when using the plain text format. This is a new feature in Robot Framework 2.5.5.

5.1.2   Test Case table

The settings in the Test Case table are always specific to the test case for which they are defined. Some of these settings override the default values defined in the Settings table.

Settings available in the Test Case table
Name Description
[Documentation] Used for specifying a test case documentation.
[Tags] Used for tagging test cases.
[Setup] Used for specifying a test setup.
[Teardown] Used for specifying a test teardown.
[Precondition] A synonym for [Setup].
[Postcondition] A synonym for [Teardown].
[Template] Used for specifying a template keyword.
[Timeout] Used for specifying a test case timeout.

5.1.3   Keyword table

Settings in the Keyword table are specific to the user keyword for which they are defined.

Settings available in the Keyword table
Name Description
[Documentation] Used for specifying a user keyword documentation.
[Arguments] Used for specifying user keyword arguments.
[Return] Used for specifying user keyword return values.
[Timeout] Used for specifying a user keyword timeout.

5.2   All command line options

This appendix lists all the command line options that are available when executing test cases with pybot or jybot, and when post-processing outputs with rebot.

5.2.1   Command line options for test execution

-N, --name <name>
 Sets the name of the top-level test suite.
-D, --doc <document>
 Sets the documentation of the top-level test suite.
-M, --metadata <name:value>
 Sets free metadata for the top level test suite.
-G, --settag <tag>
 Sets the tag(s) to all executed test cases.
-t, --test <name>
 Selects the test cases by name.
-s, --suite <name>
 Selects the test suites by name.
-i, --include <tag>
 Selects the test cases by tag.
-e, --exclude <tag>
 Selects the test cases by tag.
-c, --critical <tag>
 Tests that have the given tag are considered critical.
-n, --noncritical <tag>
 Tests that have the given tag are not critical.
-v, --variable <name:value>
 Sets individual variables.
-V, --variablefile <path:args>
 Sets variables using variable files.
-d, --outputdir <dir>
 Defines where to create output files.
-o, --output <file>
 Sets the path to the generated output file.
-l, --log <file>
 Sets the path to the generated log file.
-r, --report <file>
 Sets the path to the generated report file.
-S, --summary <file>
 Summary files are not supported in Robot Framework 2.6 or newer.
-x, --xunitfile <file>
 Sets the path to the generated XUnit compatible result file.
-b, --debugfile <file>
 A debug file that is written during execution.
-T, --timestampoutputs
 Adds a timestamp to all output files.
--splitlog Split log file into smaller pieces that open in browser transparently.
--splitoutputs <level>
 Splitting outputs is not supported in Robot Framework 2.6 or newer.
--logtitle <title>
 Sets a title for the generated test log.
--reporttitle <title>
 Sets a title for the generated test report.
--reportbackground <colors>
 Sets background colors of the generated report.
--summarytitle <title>
 Summary files are not supported in Robot Framework 2.6 or newer.
-L, --loglevel <level>
 Sets the threshold level for logging.
--suitestatlevel <level>
 Defines how many levels to show in the Statistics by Suite table in outputs.
--tagstatinclude <tag>
 Includes only these tags in the Statistics by Tag table.
--tagstatexclude <tag>
 Excludes these tags from the Statistics by Tag table.
--tagstatcombine <tags:title>
 Creates combined statistics based on tags.
--tagdoc <pattern:doc>
 Adds documentation to the specified tags.
--tagstatlink <pattern:link:title>
 Adds external links to the Statistics by Tag table.
--listener <name:args>
 Sets a listener for monitoring test execution.
--warnonskippedfiles
 Show a warning when an invalid file is skipped.
--nostatusrc Sets the return code to zero regardless of failures in test cases. Error codes are returned normally.
--runemptysuite
 Executes tests also if the top level test suite is empty.
--runmode <mode>
 Sets the execution mode for this test run. Valid modes are ExitOnFailure, SkipTeardownOnExit, DryRun, and Random:<what>.
-W, --monitorwidth <chars>
 Sets the width of the console output.
-C, --monitorcolors <on|off|force>
 Specifies are colors used in the console.
-P, --pythonpath <path>
 Additional locations where to search test libraries from when they are imported.
-E, --escape <what:with>
 Escapes characters that are problematic in the console.
-A, --argumentfile <path>
 A text file to read more arguments from.
-h, --help Prints usage instructions.
--version Prints the version information.

5.2.2   Command line options for post-processing outputs

-N, --name <name>
 Sets the name of the top level test suite.
-D, --doc <document>
 Sets the documentation of the top-level test suite.
-M, --metadata <name:value>
 Sets free metadata for the top-level test suite.
-G, --settag <tag>
 Sets the tag(s) to all processed test cases.
-t, --test <name>
 Selects the test cases by name.
-s, --suite <name>
 Selects the test suites by name.
-i, --include <tag>
 Selects the test cases by tag.
-e, --exclude <tag>
 Selects the test cases by tag.
-c, --critical <tag>
 Tests that have the given tag are considered critical.
-n, --noncritical <tag>
 Tests that have the given tag are not critical.
-d, --outputdir <dir>
 Defines where to create output files.
-o, --output <file>
 Sets the path to the generated output file.
-l, --log <file>
 Sets the path to the generated log file.
-r, --report <file>
 Sets the path to the generated report file.
-S, --summary <file>
 Summary files are not supported in Robot Framework 2.6 or newer.
-x, --xunitfile <file>
 Sets the path to the generated XUnit compatible result file.
-T, --timestampoutputs
 Adds a timestamp to all output files.
--splitlog Split log file into smaller pieces that open in browser transparently.
--splitoutputs <level>
 Splitting outputs is not supported in Robot Framework 2.6 or newer.
--logtitle <title>
 Sets a title for the generated test log.
--reporttitle <title>
 Sets a title for the generated test report.
--reportbackground <colors>
 Sets background colors of the generated report.
--summarytitle <title>
 Summary files are not supported in Robot Framework 2.6 or newer.
-L, --loglevel <level>
 Sets the threshold level to select log messages.
--suitestatlevel <level>
 Defines how many levels to show in the Statistics by Suite table in outputs.
--tagstatinclude <tag>
 Includes only these tags in the Statistics by Tag table.
--tagstatexclude <tag>
 Excludes these tags from the Statistics by Tag table.
--tagstatcombine <tags:title>
 Creates combined statistics based on tags.
--tagdoc <pattern:doc>
 Adds documentation to the specified tags.
--tagstatlink <pattern:link:title>
 Adds external links to the Statistics by Tag table. table in outputs.
--removekeywords <all|passed>
 Removes keyword data from the generated outputs.
--starttime <timestamp>
 Sets the starting time of test execution when creating reports.
--endtime <timestamp>
 Sets the ending time of test execution when creating reports.
--nostatusrc Sets the return code to zero regardless of failures in test cases. Error codes are returned normally.
-E, --escape <what:with>
 Escapes characters that are problematic in the console.
-A, --argumentfile <path>
 A text file to read more arguments from.
-h, --help Prints usage instructions.
--version Prints the version information.

5.3   Test data templates

These templates can be used when creating test data for Robot Framework. There are templates both for test case and resource files, and resource templates can also be used to create test suite initialization files. Templates are available both in HTML and TSV format and they can be customized freely.

testcase_template.html
Test case file template in HTML format.
testcase_template.tsv
Test case file template in TSV format.
resource_template.html
Resource file template in HTML format.
resource_template.tsv
Resource file template in TSV format.
attd_template.html
Template for creating test cases in Acceptance Test-Driven Development (ATDD) style. These tests are created from high-level keywords needing no arguments, and the template has been simplified accordingly.

Templates are available through this user guide, they are included in the source distribution, and they can also be downloaded from http://code.google.com/p/robotframework/wiki/Templates.

5.4   Supporting tools

The available supporting tools for Robot Framework are described in this appendix.

5.4.1   Internal tools

These tools are distributed with Robot Framework. They are included in the source distribution and also available through http://code.google.com/p/robotframework/wiki/SupportingTools.

Library documentation tool

libdoc.py is tool for generating HTML or XML documentation from keywords of a test library or a resource file.

Test data documentation tool

testdoc.py is tool for generating high level documentation of a given test suite, including the names of suites and tests as well as top-level keywords.

Historical reporting tool

risto.py is a tool for generating graphs about historical statistics of test executions.

Test result diffing tool

robotdiff.py is a tool for generating diff reports from Robot Framework output files.

Execution time reporting tool

times2csv.py is a tool for generating start, end and elapsed time information about suites, tests and keywords in CSV format.

File viewing tool

fileviewer.py is a graphical tool implementing UNIX tail -like functionality. It is especially designed to view debug files.

One click installer

One click installer is an AutoIT script that installs Robot Framework and its dependencies.

Test status checker tool

statuschecker.py is a tool for verifying that test case statuses and messages and also keyword log messages are as expected.

5.4.2   External tools

These tools are developed as separate projects.

Test data editing tool (RIDE)

RIDE is a standalone tool for editing test data. It helps in creating, editing and maintaining of Robot Framework test data. The project pages are at http://code.google.com/p/robotframework-ride/.

Manual test execution tool (mabot)

mabot is a standalone tool for reporting manual test execution results. It enables storing and reporting manual test cases along with automated Robot Framework test cases. The project pages are at http://code.google.com/p/robotframework-mabot/.

Tools for creating Java test libraries

JavaTools is an external collection of tools that simplify creation of larger Java test libraries by offering several dynamic ways of resolving available keywords at runtime. For more information, see http://code.google.com/p/robotframework-javatools/.

5.5   Documentation formatting

It is possible to use simple HTML formatting with test suite, test case and user keyword documentation in the test data, as well as when documenting test libraries. The formatting is similar to the style used in most wikis, and it is designed to be understandable both as plain text and after the HTML transformation.

5.5.1   Representing newlines

The documentation used for test suites, test cases and keywords is subject to general parsing rules of the test data. This means that normal newlines are not preserved, and dividing documentation into lines and paragraphs requires using a literal newline character sequence (\n), as illustrated in the example below.

Setting Value
Documentation First line.\n
\n
Second paragraph, this time\n
with multiple lines.

With library documentations normal newlines are enough, and for example the following keyword documentation would create same end result as the above test suite documentation.

def example_keyword():
    """First line.

    Second paragraph, this time
    with multiple lines.
    """
    pass

5.5.2   Bold and italic

Bold text can be created by having an asterisk before and after the selected word or words, for example *this is bold*. Italic style works similarly, but the special character to use is an underscore, for example _italic_. It is also possible to have bold italic with the syntax _*bold italic*_.

An asterisk or an underscore alone, or in the middle of a word, does not start formatting, but punctuation characters before or after them are allowed. Both bold and italic are limited for formatting text on one line, and formatting spanning several lines must be explicitly started and stopped on every line.

Bold and italic examples
Unformatted Formatted
*bold* bold
_italic_ italic
*bold* and then _italic_ bold and then italic
_*bold italic*_, _italic_, nothing bold italic, italic, nothing
This is *bold*\n
*on multiple*\n
*lines*.
This is bold
on multiple
lines.

5.5.3   URLs

All strings that look like URLs are automatically converted into clickable links. Additionally, URLs that end with extension .jpg, .jpeg, .png, .gif or .bmp (case-insensitive) will automatically create images. For example URLs like http://some.url are turned into links, and http:///server/image.jpg and file:///path/chart.png into images.

The automatic conversion of URLs to links is applied to all the data in logs and reports, but creating images is done only for test suite, test case and keyword documentation.

5.5.4   Tables

Tables are created using the pipe character with whitespace around it as a cell boundary and the newline as a row separator. In library documentations normal newlines are enough, but in test suite, test case and keyword documentations the explicit newline character sequence (\n) is needed:

| *A*  | *B*   | *C*   |\n
| _1_  | Hello | world |\n
| _2_  | Hi    |       |\n

The created table always has a thin border and the text is left-aligned. Formatting using bold and italic works also in table cells, so it is possible to create headers. For example the above documentation would be formatted like this:

A B C
1 Hello world
2 Hi  

5.5.5   Horizontal ruler

Horizontal rulers (the <hr> tag) make it possible to separate larger sections from each others, and they can be created by having three hyphens alone in a line. With documentations in the test data literal newlines are, again, required:

Some text here.\n
\n
---\n
\n
More text...

5.6   Time format

Robot Framework has its own time format that is used by several keywords (for example Sleep and Wait Until Keyword Succeeds) as well as test case and user keyword timeouts. This format is meant to be both flexible to use and easy to understand.

5.6.1   Time as number

The time can always be given as a plain number, in which case it is interpreted to be seconds. Both integers and floating point numbers work, and it is possible to use either real numbers or strings containing numerical values. This format is useful, for example, when the actual time value is calculated.

5.6.2   Time as text

Representing the time as text means using a format such as 2 minutes 42 seconds, which is normally easier to understand than just having the value as seconds. It is, for example, not so easy to understand how long a time 4200 is in seconds, but 1 hour 10 minutes is clear immediately.

The basic idea of this format is having first a number and then a text specifying what time that number represents. Numbers can be either integers or floating point numbers, the whole format is case and space insensitive, and the available specifier texts are:

  • days, day, d
  • hours, hour, h
  • minutes, minute, mins, min, m
  • seconds, second, secs, sec, s
  • milliseconds, millisecond, millis, ms

Examples:

1 min 30 secs
1.5 minutes
90 s
1 day 2 hours 3 minutes 4 seconds 5 milliseconds
1d 2h 3m 4s 5ms