ℹ️ Skipped - page is already crawled
| Filter | Status | Condition | Details |
|---|---|---|---|
| HTTP status | PASS | download_http_code = 200 | HTTP 200 |
| Age cutoff | PASS | download_stamp > now() - 6 MONTH | 0.1 months ago |
| History drop | PASS | isNull(history_drop_reason) | No drop reason |
| Spam/ban | PASS | fh_dont_index != 1 AND ml_spam_score = 0 | ml_spam_score=0 |
| Canonical | PASS | meta_canonical IS NULL OR = '' OR = src_unparsed | Not set |
| Property | Value |
|---|---|
| URL | https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html |
| Last Crawled | 2026-04-09 17:07:47 (2 days ago) |
| First Indexed | 2017-06-11 20:04:05 (8 years ago) |
| HTTP Status Code | 200 |
| Meta Title | Robot Framework User Guide |
| Meta Description | null |
| Meta Canonical | null |
| Boilerpipe Text | Version 7.4.2
Copyright © 2008-2015 Nokia Networks
Copyright © 2016- Robot Framework Foundation
Table of Contents
1 Getting started
1.1 Introduction
1.1.1 Why Robot Framework?
1.1.2 High-level architecture
1.1.3 Screenshots
1.1.4 Getting more information
1.2 Copyright and license
1.3 Installation instructions
1.3.1 Python installation
1.3.2 Installing using pip
1.3.3 Installing from source
1.3.4 Verifying installation
1.3.5 Dependencies
1.3.6 Virtual environments
1.4 Demonstrations
2 Creating test data
2.1 Test data syntax
2.1.1 Files and directories
2.1.2 Test data sections
2.1.3 Supported file formats
2.1.4 Rules for parsing the data
2.1.5 Localization
2.1.6 Style
2.2 Creating test cases
2.2.1 Test case syntax
2.2.2 Using arguments
2.2.3 Failures
2.2.4 Test case name and documentation
2.2.5 Tagging test cases
2.2.6 Test setup and teardown
2.2.7 Test templates
2.2.8 Different test case styles
2.3 Creating tasks
2.3.1 Task syntax
2.3.2 Task related settings
2.4 Creating test suites
2.4.1 Suite files
2.4.2 Suite directories
2.4.3 Suite name
2.4.4 Suite documentation
2.4.5 Free suite metadata
2.4.6 Suite setup and teardown
2.5 Using test libraries
2.5.1 Importing libraries
2.5.2 Specifying library to import
2.5.3 Setting custom name to library
2.5.4 Standard libraries
2.5.5 External libraries
2.6 Variables
2.6.1 Introduction
2.6.2 Using variables
2.6.3 Creating variables
2.6.4 Built-in variables
2.6.5 Variable priorities and scopes
2.6.6 Advanced variable features
2.7 Creating user keywords
2.7.1 User keyword syntax
2.7.2 User keyword name and documentation
2.7.3 User keyword tags
2.7.4 User keyword arguments
2.7.5 Embedding arguments into keyword name
2.7.6 User keyword return values
2.7.7 User keyword setup and teardown
2.7.8 Private user keywords
2.7.9 Recursion
2.8 Resource and variable files
2.8.1 Resource files
2.8.2 Variable files
2.9 Control structures
2.9.1
FOR
loops
2.9.2
WHILE loops
2.9.3 Loop control using
BREAK
and
CONTINUE
2.9.4
IF/ELSE
syntax
2.9.5
TRY/EXCEPT
syntax
2.9.6
GROUP
syntax
2.10 Advanced features
2.10.1 Handling keywords with same names
2.10.2 Timeouts
2.10.3 Parallel execution of keywords
3 Executing test cases
3.1 Basic usage
3.1.1 Starting test execution
3.1.2 Using command line options
3.1.3 Test results
3.1.4 Argument files
3.1.5 Getting help and version information
3.1.6 Creating start-up scripts
3.1.7 Making
*.robot
files executable
3.1.8 Debugging problems
3.2 Test execution
3.2.1 Execution flow
3.2.2 Test and suite statuses
3.2.3 Continuing on failure
3.2.4 Stopping test execution gracefully
3.3 Task execution
3.3.1 Generic automation mode
3.3.2 Task related command line options
3.4 Post-processing outputs
3.4.1 Using Rebot
3.4.2 Creating reports, logs and output files
3.4.3 Combining outputs
3.4.4 Merging outputs
3.4.5 JSON output files
3.5 Configuring execution
3.5.1 Selecting files to parse
3.5.2 Selecting test cases
3.5.3 Setting metadata
3.5.4 Configuring where to search libraries and other extensions
3.5.5 Setting variables
3.5.6 Dry run
3.5.7 Randomizing execution order
3.5.8 Programmatic modification of test data
3.5.9 Controlling console output
3.5.10 Setting listeners
3.6 Output files
3.6.1 Different output files
3.6.2 Log levels
3.6.3 Splitting logs
3.6.4 Configuring statistics
3.6.5 Removing and flattening keywords
3.6.6 Automatically expanding keywords
3.6.7 Setting start and end time of execution
3.6.8 Limiting error message length in reports
3.6.9 Programmatic modification of results
3.6.10 System log
4 Extending Robot Framework
4.1 Creating test libraries
4.1.1 Introduction
4.1.2 Creating test library class or module
4.1.3 Creating keywords
4.1.4 Communicating with Robot Framework
4.1.5 Distributing test libraries
4.1.6 Dynamic library API
4.1.7 Hybrid library API
4.1.8 Handling Robot Framework's timeouts
4.1.9 Using Robot Framework's internal modules
4.1.10 Extending existing test libraries
4.2 Remote library interface
4.2.1 Introduction
4.2.2 Putting Remote library to use
4.2.3 Supported argument and return value types
4.2.4 Remote protocol
4.3 Listener interface
4.3.1 Listener structure
4.3.2 Listener interface versions
4.3.3 Taking listeners into use
4.3.4 Listener calling order
4.3.5 Listener examples
4.4 Parser interface
4.4.1 Taking parsers into use
4.4.2 Parser API
4.4.3 Examples
5 Supporting Tools
5.1 Library documentation tool (Libdoc)
5.1.1 General usage
5.1.2 Writing documentation
5.1.3 Documentation syntax
5.1.4 Internal linking
5.1.5 Representing arguments
5.1.6 Libdoc example
5.2 Test data documentation tool (Testdoc)
5.2.1 General usage
5.2.2 Generating documentation
5.3 Test data clean-up tool (Tidy)
5.4 External tools
6 Appendices
6.1 Available settings
6.1.1 Setting section
6.1.2 Test Case section
6.1.3 Keyword section
6.2 Command line options
6.2.1 Command line options for test execution
6.2.2 Command line options for post-processing outputs
6.2.3 Environment variables for execution and post-processing
6.3 Translations
6.3.1 Arabic (ar)
6.3.2 Bulgarian (bg)
6.3.3 Bosnian (bs)
6.3.4 Czech (cs)
6.3.5 German (de)
6.3.6 Spanish (es)
6.3.7 Finnish (fi)
6.3.8 French (fr)
6.3.9 Hindi (hi)
6.3.10 Italian (it)
6.3.11 Japanese (ja)
6.3.12 Korean (ko)
6.3.13 Dutch (nl)
6.3.14 Polish (pl)
6.3.15 Portuguese (pt)
6.3.16 Brazilian Portuguese (pt-BR)
6.3.17 Romanian (ro)
6.3.18 Russian (ru)
6.3.19 Swedish (sv)
6.3.20 Thai (th)
6.3.21 Turkish (tr)
6.3.22 Ukrainian (uk)
6.3.23 Vietnamese (vi)
6.3.24 Chinese Simplified (zh-CN)
6.3.25 Chinese Traditional (zh-TW)
6.4 Documentation formatting
6.4.1 Handling whitespace in test data
6.4.2 Paragraphs
6.4.3 Inline styles
6.4.4 URLs
6.4.5 Custom links and images
6.4.6 Section titles
6.4.7 Tables
6.4.8 Lists
6.4.9 Preformatted text
6.4.10 Horizontal ruler
6.5 Time format
6.5.1 Time as number
6.5.2 Time as time string
6.5.3 Time as "timer" string
6.6 Boolean arguments
6.7 Evaluating expressions
6.7.1 Introduction
6.7.2 Evaluation namespace
6.7.3 Using variables
6.8 Registrations
6.8.1 Suite file extensions
6.8.2 Resource file extensions
6.8.3 Media type
6.8.4 Remote server port
1 Getting started
1.1 Introduction
1.2 Copyright and license
1.3 Installation instructions
1.4 Demonstrations
1.1 Introduction
Robot Framework is a Python-based, extensible keyword-driven automation
framework for acceptance testing, acceptance test driven development (ATDD),
behavior driven development (BDD) and robotic process automation (RPA). It
can be used in distributed, heterogeneous environments, where automation
requires using different technologies and interfaces.
The framework has a rich ecosystem around it consisting of various generic
libraries and tools that are developed as separate projects. For more
information about Robot Framework and the ecosystem, see
http://robotframework.org
.
Robot Framework is open source software released under the
Apache License
2.0
. Its development is sponsored by the
Robot Framework Foundation
.
Note
The official RPA support was added in Robot Framework 3.1.
This User Guide still talks mainly about creating tests, test data,
and test libraries, but same concepts apply also when
creating
tasks
.
1.1.1 Why Robot Framework?
1.1.2 High-level architecture
1.1.3 Screenshots
1.1.4 Getting more information
Project pages
Mailing lists
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 Python.
Provides a
command line interface
and XML based
output files
for
integration into existing build infrastructure (continuous integration
systems).
Provides support for testing web applications, rest APIs, mobile applications,
running processes, connecting to remote systems via Telnet or 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.
Robot Framework architecture
The
test data
is in simple, easy-to-edit tabular format. When
Robot Framework is started, it processes the 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
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
.
Test case file
Reports and logs
1.1.4 Getting more information
Project pages
The number one place to find more information about Robot Framework
and the rich ecosystem around it is
http://robotframework.org
.
Robot Framework itself is hosted on
GitHub
.
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.
1.2 Copyright and license
Robot Framework is open source software provided under the
Apache License
2.0
. Robot Framework documentation such as this User Guide use the
Creative Commons Attribution 3.0 Unported
license. Most libraries and tools
in the larger ecosystem around the framework are also open source, but they
may use different licenses.
The full Robot Framework copyright notice is included below:
Copyright 2008-2015 Nokia Networks
Copyright 2016- Robot Framework Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
1.3 Installation instructions
These instructions cover installing
Robot Framework
and its preconditions on different operating systems. If you already have
Python
installed, you can install Robot Framework using
the standard package manager
pip
:
pip install robotframework
1.3.1 Python installation
Installing Python on Linux
Installing Python on Windows
Installing Python on macOS
PyPy installation
Configuring
PATH
1.3.2 Installing using pip
Running
pip
command
Installing and uninstalling Robot Framework
1.3.3 Installing from source
1.3.4 Verifying installation
1.3.5 Dependencies
1.3.6 Virtual environments
1.3.1 Python installation
Robot Framework
is implemented using
Python
, and a precondition to install it
is having Python or its alternative implementation
PyPy
installed. Another recommended precondition is having the
pip
package manager
available.
Robot Framework requires Python 3.8 or newer. The latest version that supports
Python 3.6 and 3.7 is
Robot Framework 6.1.1
. If you need to use Python 2,
Jython
or
IronPython
,
you can use
Robot Framework 4.1.3
.
Installing Python on Linux
On Linux you should have suitable Python installation with
pip
available
by default. If not, you need to consult your distributions documentation
to learn how to install them. This is also true if you want to use some other
Python version than the one provided by your distribution by default.
To check what Python version you have installed, you can run
python --version
command in a terminal:
$
python
--version
Python
3
.10.13
Notice that if your distribution provides also older Python 2, running
python
may use that. To use Python 3, you can use
python3
command or even more version
specific command like
python3.8
. You need to use these version specific variants
also if you have multiple Python 3 versions installed and need to pinpoint which
one to use:
$
python3.11
--version
Python
3
.11.7
$
python3.12
--version
Python
3
.12.1
Installing Robot Framework directly under the system provided Python
has a risk that possible problems can affect the whole Python installation
used also by the operating system itself. Nowadays
Linux distributions typically use
user installs
by default to avoid such
problems, but users can also themselves decide to use
virtual environments
.
Installing Python on Windows
On Windows Python is not available by default, but it is easy to install.
The recommended way to install it is using the official Windows installers available
at
http://python.org
. For other alternatives, such as installing from the
Microsoft Store, see the
official Python documentation
.
When installing Python on Windows, it is recommended to add Python to
PATH
to make it and tools like pip and Robot Framework easier to execute from
the command line. When using the
official installer
, you just need
to select the
Add Python 3.x to PATH
checkbox on the first dialog.
To make sure Python installation has been successful and Python has been
added to
PATH
, you can open the command prompt and execute
python --version
:
C
:
\
Python 3.10.9
If you install multiple Python versions on Windows, the version that is used
when you execute
python
is the one first in
PATH
. If you need to use others,
the easiest way is using the
py launcher
:
C
:
\
Python 3.10.9
C
:
\
Python 3.12.1
Installing Python on macOS
MacOS does not provide Python 3 compatible Python version by default, so it
needs to be installed separately. The recommended approach is using the official
macOS installers available at
http://python.org
. If you are using a package
manager like
Homebrew
, installing Python via it is
possible as well.
You can validate Python installation on macOS using
python --version
like on
other operating systems.
PyPy installation
PyPy
is an alternative Python implementation. Its main advantage over the
standard Python implementation is that it can be faster and use less memory,
but this depends on the context where and how it is used. If execution speed
is important, at least testing PyPy is probably a good idea.
Installing PyPy is a straightforward procedure and you can find both installers
and installation instructions at
http://pypy.org
. To validate that PyPy installation
was successful, run
pypy --version
or
pypy3 --version
.
Note
Using Robot Framework with PyPy is officially supported only on Linux.
Configuring
PATH
The
PATH environment variable
lists directories where commands executed in
a system are searched from. To make using Python,
pip
and Robot Framework easier
from the command line, it is recommended to add the Python installation directory
as well as the directory where commands like
pip
and
robot
are installed
into
PATH
.
When using Python on Linux or macOS, Python and tools installed with it should be
automatically in
PATH
. If you nevertheless need to update
PATH
, you
typically need to edit some system wide or user specific configuration file.
Which file to edit and how depends on the operating system and you need to
consult its documentation for more details.
On Windows the easiest way to make sure
PATH
is configured correctly is
setting the
Add Python 3.x to PATH
checkbox when
running the installer
.
To manually modify
PATH
on Windows, follow these steps:
Find
Environment Variables
under
Settings
. There are variables affecting
the whole system and variables affecting only the current user. Modifying
the former will require admin rights, but modifying the latter is typically
enough.
Select
PATH
(often written like
Path
) and click
Edit
. If you are
editing user variables and
PATH
does not exist, click
New
instead.
Add both the Python installation directory and the
Scripts
directory
under the installation directory into
PATH
.
Exit the dialog with
Ok
to save the changes.
Start a new command prompt for the changes to take effect.
1.3.2 Installing using pip
These instructions cover installing Robot Framework using
pip
, the standard
Python package manager. If you are using some other package manager like
Conda
, you can use it instead but need to study its
documentation for instructions.
When installing Python, you typically get pip installed automatically. If
that is not the case, you need to check the documentation of that Python
installation for instructions how to install it separately.
Running
pip
command
Typically you use pip by running the
pip
command, but on Linux you may need
to use
pip3
or even more Python version specific variant like
pip3.8
instead. When running
pip
or any of its variants, the pip version that is
found first in
PATH
will be used. If you have multiple Python versions
installed, you may need to pinpoint which exact version you want to use.
This is typically easiest done by running
python -m pip
and substituting
python
with the Python version you want to use.
To make sure you have pip available, you can run
pip --version
or equivalent.
Examples on Linux:
$
pip
--version
pip
23
.2.1
from
...
(
python
3
.10
)
$
python3.12
-m
pip
--version
pip
23
.3.1
from
...
(
python
3
.12
)
Examples on Windows:
C
:
\
pip 23.2.1 from ... (python 3.10)
C
:
\
pip 23.3.2 from ... (python 3.12)
In the subsequent sections pip is always run using the
pip
command. You may
need to use some of the other approaches explained above in your environment.
Installing and uninstalling Robot Framework
The easiest way to use pip is by letting it find and download packages it
installs from the
Python Package Index (PyPI)
, but it can also install
packages downloaded from the PyPI separately. The most common usages are
shown below and
pip
documentation has more information and examples.
pip
install
robotframework
pip
install
--upgrade
robotframework
pip
install
--upgrade
--pre
robotframework
pip
install
robotframework
==
7
.0
pip
install
robotframework-7.0-py3-none-any.whl
pip
install
https://github.com/robotframework/robotframework/archive/master.zip
pip
uninstall
robotframework
1.3.3 Installing from source
Another installation alternative is getting Robot Framework source code
and installing it using the provided
setup.py
script. This approach is
recommended only if you do not have
pip
available for some reason.
You can get the source code by downloading a source distribution package
from
PyPI
and extracting it. An alternative is cloning the
GitHub
repository and checking out the needed release tag.
Once you have the source code, you can install it with the following command:
python
setup.py
install
The
setup.py
script accepts several arguments allowing, for example,
installation into a non-default location that does not require administrative
rights. It is also used for creating different distribution packages. Run
python setup.py --help
for more details.
1.3.4 Verifying installation
To make sure that the correct Robot Framework version has been installed, run
the following command:
$
robot
--version
Robot
Framework
7
.0
(
Python
3
.10.3
on
linux
)
If running these commands fails with a message saying that the command is
not found or recognized, a good first step is double-checking the
PATH
configuration.
If you have installed Robot Framework under multiple Python versions,
running
robot
will execute the one first in
PATH
. To select explicitly,
you can run
python -m robot
and substitute
python
with the right Python
version.
$
python3.12
-m
robot
--version
Robot
Framework
7
.0
(
Python
3
.12.1
on
linux
)
C:
\>
py
-3.11
-m
robot
--version
Robot
Framework
7
.0
(
Python
3
.11.7
on
win32
)
1.3.5 Dependencies
Robot Framework core functionality has no mandatory dependencies other than
Python and its standard library. Some individual features may require optional
dependencies to be installed, though. What dependencies are needed is always
explained in the relevant documentation.
1.3.6 Virtual environments
Python
virtual environments
allow Python packages to be installed in
an isolated location for a particular system or application, rather than
installing all packages into the same global location. They have
two main use cases:
Install packages needed by different projects into their own environments.
This avoids conflicts if projects need different versions of same packages.
Avoid installing everything under the global Python installation. This is
especially important on Linux where the global Python installation may be
used by the distribution itself and messing it up can cause severe problems.
1.4 Demonstrations
There are several demo projects that introduce Robot Framework and help getting
started with it.
Quick Start Guide
Introduces the most important features of Robot Framework and acts as
an executable demo.
Robot Framework demo
Simple example test cases. Demonstrates also creating custom test libraries.
Web testing demo
Demonstrates how to create tests and higher level keywords. The system
under test is a simple web page that is tested using
SeleniumLibrary
.
ATDD with Robot Framework
Demonstrates how to use Robot Framework when following
Acceptance Test Driven Development (ATDD) process.
2 Creating test data
2.1 Test data syntax
2.2 Creating test cases
2.3 Creating tasks
2.4 Creating test suites
2.5 Using test libraries
2.6 Variables
2.7 Creating user keywords
2.8 Resource and variable files
2.9 Control structures
2.10 Advanced features
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.
Although this section mostly uses term
test
, the same rules apply also
when
creating tasks
.
2.1.1 Files and directories
2.1.2 Test data sections
2.1.3 Supported file formats
Space separated format
Pipe separated format
reStructuredText format
JSON format
2.1.4 Rules for parsing the data
Ignored data
Escaping
Dividing data to several rows
2.1.5 Localization
Enabling languages
Built-in languages
Custom language files
Contributing translations
2.1.6 Style
2.1.1 Files and directories
The hierarchical structure for arranging test cases is built as follows:
Test cases are created in
suite 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
suite directory
has suites created from test
case files as its child 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
configuring the created test suite.
In addition to this, there are:
Test libraries
containing the lowest-level keywords.
Resource files
with
variables
and higher-level
user keywords
.
Variable files
to provide more flexible ways to create variables
than resource files.
Test case files, test suite initialization files and resource files are
all created using Robot Framework test data syntax. Test libraries and
variable files are created using "real" programming languages, most
often Python.
2.1.2 Test data sections
Robot Framework data is defined in different sections, often also
called tables, listed below:
Different sections in data
Section
Used for
Settings
1) Importing
test libraries
,
resource files
and
variable files
.
2) Defining metadata for
test suites
and
test cases
.
Variables
Defining
variables
that can be used
elsewhere in the test data.
Test Cases
Creating test cases
from available
keywords.
Tasks
Creating tasks
using available
keywords. Single file can only contain
either tests or tasks.
Keywords
Creating user keywords
from existing
lower-level keywords
Comments
Additional comments or data. Ignored by
Robot Framework.
Different sections are recognized by their header row. The recommended
header format is
*** Settings ***
, but the header is case-insensitive,
surrounding spaces are optional, and the number of asterisk characters can
vary as long as there is at least one asterisk in the beginning. For example,
also
*settings
would be recognized as a section header.
Robot Framework supports also singular headers like
*** Setting ***,
but that
support was deprecated in Robot Framework 6.0. There is a visible deprecation
warning starting from Robot Framework 7.0 and singular headers will eventually
not be supported at all.
The header row can contain also other data than the actual section header.
The extra data must be separated from the section header using the data
format dependent separator, typically two or more spaces. These extra headers
are ignored at parsing time, but they can be used for documenting
purposes. This is especially useful when creating test cases using the
data-driven style
.
Possible data before the first section is ignored.
Note
Section headers can be
localized
. See the
Translations
appendix for
supported translations.
2.1.3 Supported file formats
The most common approach to create Robot Framework data is using the
space separated format
where pieces of the data, such as keywords
and their arguments, are separated from each others with two or more spaces.
An alternative is using the
pipe separated format
where the separator is
the pipe character surrounded with spaces (
|
).
Suite files typically use the
.robot
extension, but what files are
parsed
can be configured
.
Resource files
can use the
.robot
extension as well, but using the dedicated
.resource
extension is
recommended and may be mandated in the future. Files containing non-ASCII
characters must be saved using the UTF-8 encoding.
Robot Framework supports also
reStructuredText
files so that normal
Robot Framework data is
embedded into code blocks
. Only files with
the
.robot.rst
extension are parsed by default. If you would
rather use just
.rst
or
.rest
extension, that needs to be
configured separately.
Robot Framework data can also be created in the
JSON format
that is targeted
more for tool developers than normal Robot Framework users. Only JSON files
with the custom
.rbt
extension are parsed by default.
Earlier Robot Framework versions supported data also in HTML and TSV formats.
The TSV format still works if the data is compatible with the
space separated
format
, but the support for the HTML format has been removed altogether.
If you encounter such data files, you need to convert them to the plain text
format to be able to use them with Robot Framework 3.2 or newer. The easiest
way to do that is using the
Tidy
tool, but you must use the version included
with Robot Framework 3.1 because newer versions do not understand the HTML
format at all.
Space separated format
When Robot Framework parses data, it first splits the data to lines and then
lines to tokens such as keywords and arguments. When using the space
separated format, the separator between tokens is two or more spaces or
alternatively one or more tab characters. In addition to the normal ASCII
space, any Unicode character considered to be a space (e.g. no-break space)
works as a separator. The number of spaces used as separator can vary, as
long as there are at least two, making it possible to align the data nicely
in settings and elsewhere when it makes the data easier to understand.
*** Settings ***
Documentation
Example using the space separated format.
Library
OperatingSystem
*** Variables ***
${
MESSAGE
}
Hello, world!
*** Test Cases ***
My Test
[
Documentation
]
Example test.
Log
${
MESSAGE
}
My Keyword
${
CURDIR
}
Another Test
Should Be Equal
${
MESSAGE
}
Hello, world!
*** Keywords ***
My Keyword
[
Arguments
] ${
path
}
Directory Should Exist
${
path
}
Because tabs and consecutive spaces are considered separators, they must
be escaped if they are needed in keyword arguments or elsewhere
in the actual data. It is possible to use special escape syntax like
\t
for tab and
\xA0
for no-break space as well as
built-in variables
${SPACE}
and
${EMPTY}
. See the
Escaping
section for details.
Tip
Although using two spaces as a separator is enough, it is recommended
to use four spaces to make the separator easier to recognize.
Note
Prior to Robot Framework 3.2, non-ASCII spaces used in the data
were converted to ASCII spaces during parsing. Nowadays all data
is preserved as-is.
Pipe separated format
The biggest problem of the space delimited format is that visually
separating keywords from 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 delimited variant can
work better because it makes the separator more visible.
One file can contain both space separated and pipe separated lines.
Pipe separated lines are recognized by the mandatory leading pipe character,
but the pipe at the end of the line is optional. There must always be at
least one space or tab on both sides of the pipe except at the beginning and
at the end of the line. There is no need to align the pipes, but that often
makes the data easier to read.
|
*** Settings ***
|
|
Documentation
|
Example using the pipe separated format.
|
Library
|
OperatingSystem
|
*** Variables ***
|
| ${
MESSAGE
} |
Hello, world!
|
*** Test Cases ***
| | |
|
My Test
| [
Documentation
] |
Example test.
|
| |
Log
| ${
MESSAGE
} |
| |
My Keyword
| ${
CURDIR
} |
|
Another Test
|
Should Be Equal
| ${
MESSAGE
} |
Hello, world!
|
*** Keywords ***
| | |
|
My Keyword
| [
Arguments
] | ${
path
} |
| |
Directory Should Exist
| ${
path
} |
When using the pipe separated format, consecutive spaces or tabs inside
arguments do not need to be escaped. Similarly empty columns do not need
to be escaped except
if they are at the end
. Possible pipes surrounded by
spaces in the actual test data must be escaped with a backslash, though:
|
*** Test Cases ***
| | | |
|
Escaping Pipe
| ${
file count
} = |
Execute Command
|
ls -1 *.txt \| wc -l
|
| |
Should Be Equal
| ${
file count
} |
42
|
Note
Preserving consecutive spaces and tabs in arguments is new
in Robot Framework 3.2. Prior to it non-ASCII spaces used in
the data were also converted to ASCII spaces.
reStructuredText format
reStructuredText
(reST) is an 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. reST documents are most often compiled to HTML,
but also other output formats are supported. Using reST with Robot Framework
allows you to mix richly formatted documents and test data in a concise text
format that is easy to work with using simple text editors, diff tools, and
source control systems.
When using Robot Framework with reStructuredText files, normal Robot Framework
data is embedded to so called code blocks. In standard reST code blocks are
marked using the
code
directive, but Robot Framework supports also
code-block
or
sourcecode
directives used by the
Sphinx
tool.
reStructuredText example
------------------------
This text is outside code blocks and thus ignored.
..
code
::
robotframework
*** Settings ***
Documentation
Example using the reStructuredText format.
Library
OperatingSystem
*** Variables ***
${
MESSAGE
}
Hello, world!
*** Test Cases ***
My Test
[
Documentation
]
Example test.
Log
${
MESSAGE
}
My Keyword
${
CURDIR
}
Another Test
Should Be Equal
${
MESSAGE
}
Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
..
code
::
robotframework
# Both space and pipe separated formats are supported.
|
*** Keywords ***
| | |
|
My Keyword
| [
Arguments
] | ${
path
} |
| |
Directory Should Exist
| ${
path
} |
..
code
::
python
# This code block is ignored.
def
example
():
print
(
'Hello, world!'
)
Robot Framework supports reStructuredText files using
.robot.rst
,
.rst
and
.rest
extensions. To avoid parsing unrelated
reStructuredText files, only files with the
.robot.rst
extension
are parsed by default when executing a directory. Parsing files with
other extensions
can be enabled
by using either
--parseinclude
or
--extension
option.
When Robot Framework parses reStructuredText files, errors below level
SEVERE
are ignored to avoid noise about possible non-standard directives
and other such markup. This may hide also real errors, but they can be seen
when processing files using reStructuredText tooling normally.
Note
Parsing
.robot.rst
files automatically is new in
Robot Framework 6.1.
JSON format
Robot Framework supports data also in the
JSON
format. This format is designed
more for tool developers than for regular Robot Framework users and it is not
meant to be edited manually. Its most important use cases are:
Transferring data between processes and machines. A suite can be converted
to JSON in one machine and recreated somewhere else.
Saving a suite, possibly a nested suite, constructed from normal Robot Framework
data into a single JSON file that is faster to parse.
Alternative data format for external tools generating tests or tasks.
Note
The JSON data support is new in Robot Framework 6.1 and it can be
enhanced in future Robot Framework versions. If you have an enhancement
idea or believe you have encountered a bug, please submit an
issue
or start a discussion thread on the
#devel
channel on our
Slack
.
Converting suite to JSON
A suite structure can be serialized into JSON by using the
TestSuite.to_json
method. When used without arguments, it returns JSON data as a string, but
it also accepts a path or an open file where to write JSON data along with
configuration options related to JSON formatting:
from
robot.running
import
TestSuite
# Create suite based on data on the file system.
suite
=
TestSuite
.
from_file_system
(
'/path/to/data'
)
# Get JSON data as a string.
data
=
suite
.
to_json
()
# Save JSON data to a file with custom indentation.
suite
.
to_json
(
'data.rbt'
,
indent
=
2
)
If you would rather work with Python data and then convert that to JSON
or some other format yourself, you can use
TestSuite.to_dict
instead.
Creating suite from JSON
A suite can be constructed from JSON data using the
TestSuite.from_json
method. It works both with JSON strings and paths to JSON files:
from
robot.running
import
TestSuite
# Create suite from JSON data in a file.
suite
=
TestSuite
.
from_json
(
'data.rbt'
)
# Create suite from a JSON string.
suite
=
TestSuite
.
from_json
(
'{"name": "Suite", "tests": [{"name": "Test"}]}'
)
# Execute suite. Notice that log and report needs to be created separately.
suite
.
run
(
output
=
'example.xml'
)
If you have data as a Python dictionary, you can use
TestSuite.from_dict
instead. Regardless of how a suite is recreated, it exists only in memory and
original data files on the file system are not recreated.
As the above example demonstrates, the created suite can be executed using
the
TestSuite.run
method. It may, however, be easier to execute a JSON file
directly as explained in the following section.
Executing JSON files
When executing tests or tasks using the
robot
command, JSON files with
the custom
.rbt
extension are parsed automatically. This includes
running individual JSON files like
robot tests.rbt
and running directories
containing
.rbt
files. If you would rather use the standard
.json
extension, you need to
configure which files are parsed
.
Adjusting suite source
Suite source in the data got from
TestSuite.to_json
and
TestSuite.to_dict
is in absolute format. If a suite is recreated later on a different machine,
the source may thus not match the directory structure on that machine. To
avoid that, it is possible to use the
TestSuite.adjust_source
method to
make the suite source relative before getting the data and add a correct root
directory after the suite is recreated:
from
robot.running
import
TestSuite
# Create a suite, adjust source and convert to JSON.
suite
=
TestSuite
.
from_file_system
(
'/path/to/data'
)
suite
.
adjust_source
(
relative_to
=
'/path/to'
)
suite
.
to_json
(
'data.rbt'
)
# Recreate suite elsewhere and adjust source accordingly.
suite
=
TestSuite
.
from_json
(
'data.rbt'
)
suite
.
adjust_source
(
root
=
'/new/path/to'
)
JSON structure
Imports, variables and keywords created in suite files are included in the
generated JSON along with tests and tasks. The exact JSON structure is documented
in the
running.json
schema file
.
2.1.4 Rules for parsing the data
Ignored data
When Robot Framework parses the test data files, it ignores:
All data before the first
test data section
.
Data in the
Comments
section.
All empty rows.
All empty cells at the end of rows when using the
pipe separated format
.
All single backslashes (
\
) when not used for
escaping
.
All characters following the hash character (
#
), when it is the first
character of a cell. This means that hash marks can be used to enter
comments in the 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, place it to the documentation or other metadata of
test cases or suites, or log it with the
BuiltIn
keywords
Log
or
Comment
.
Escaping
The escape character in Robot Framework test data is the backslash
(
\
) and additionally
built-in variables
${EMPTY}
and
${SPACE}
can often be used for escaping. Different escaping mechanisms are
discussed in the sections below.
Escaping special characters
The backslash character can be used to escape special characters
so that their literal values are used.
Escaping special characters
Character
Meaning
Examples
\$
Dollar sign, never starts a
scalar variable
.
\${notvar}
\@
At sign, never starts a
list variable
.
\@{notvar}
\&
Ampersand, never starts a
dictionary variable
.
\&{notvar}
\%
Percent sign, never starts an
environment variable
.
\%{notvar}
\#
Hash sign, never starts a
comment
.
\# not comment
\=
Equal sign, never part of
named argument syntax
.
not\=named
\|
Pipe character, not a separator in the
pipe separated format
.
ls -1 *.txt \| wc -l
\\
Backslash character, never escapes anything.
c:\\temp, \\${var}
Forming escape sequences
The backslash character also allows creating special escape sequences that are
recognized as characters that would otherwise be hard or impossible to create
in the test data.
Escape sequences
Sequence
Meaning
Examples
\n
Newline character.
first line\n2nd line
\r
Carriage return character
text\rmore text
\t
Tab character.
text\tmore text
\xhh
Character with hex value
hh
.
null byte: \x00, ä: \xE4
\uhhhh
Character with hex value
hhhh
.
snowman: \u2603
\Uhhhhhhhh
Character with hex value
hhhhhhhh
.
love hotel: \U0001f3e9
Note
All strings created in the test data, including characters like
\x02
, are Unicode and must be explicitly converted to
byte strings if needed. This can be done, for example, using
Convert To Bytes
or
Encode String To Bytes
keywords
in
BuiltIn
and
String
libraries, respectively, or with
something like
value.encode('UTF-8')
in Python code.
Note
If invalid hexadecimal values are used with
\x
,
\u
or
\U
escapes, the end result is the original value without
the backslash character. For example,
\xAX
(not hex) and
\U00110000
(too large value) result with
xAX
and
U00110000
, respectively. This behavior may change in
the future, though.
Note
Built-in variable
${\n}
can be used if operating system
dependent line terminator is needed (
\r\n
on Windows and
\n
elsewhere).
Handling empty values
When using the
space separated format
, the number of spaces used as
a separator can vary and thus empty values cannot be recognized unless they
are escaped. Empty cells can be escaped either with the backslash character
or with
built-in variable
${EMPTY}
. The latter is typically recommended
as it is easier to understand.
*** Test Cases ***
Using backslash
Do Something
first arg
\
Do Something
\
second arg
Using
${
EMPTY
}
Do Something
first arg
${
EMPTY
}
Do Something
${
EMPTY
}
second arg
When using the
pipe separated format
, empty values need to be escaped
only when they are at the end of the row:
|
*** Test Cases ***
| | | |
|
Using backslash
|
Do Something
|
first arg
|
\
|
| |
Do Something
| |
second arg
|
| | | | |
|
Using
${
EMPTY
} |
Do Something
|
first arg
| ${
EMPTY
} |
| |
Do Something
| |
second arg
|
Handling spaces
Spaces, especially consecutive spaces, as part of arguments for keywords or
needed otherwise are problematic for two reasons:
Two or more consecutive spaces is considered a separator when using the
space separated format
.
Leading and trailing spaces are ignored when using the
pipe separated format
.
In these cases spaces need to be escaped. Similarly as when escaping empty
values, it is possible to do that either by using the backslash character or
by using the
built-in variable
${SPACE}
.
Escaping spaces examples
Escaping with backslash
Escaping with
${SPACE}
Notes
\ leading space
${SPACE}leading space
trailing space \
trailing space${SPACE}
Backslash must be after the space.
\ \
${SPACE}
Backslash needed on both sides.
consecutive \ \ spaces
consecutive${SPACE * 3}spaces
Using
extended variable syntax
.
As the above examples show, using the
${SPACE}
variable often makes the
test data easier to understand. It is especially handy in combination with
the
extended variable syntax
when more than one space is needed.
Dividing data to several rows
If there is more data than readily fits a row, it is possible to split it
and start continuing rows with ellipsis (
...
). Ellipses can be indented
to match the indentation of the starting row and they must always be followed
by the normal test data separator.
In most places split lines have exact same semantics as lines that are not
split. Exceptions to this rule are
suite
,
test
and
keyword
documentation
as well
suite metadata
. With them split values are automatically
joined together with the newline character
to ease creating multiline
values.
The
...
syntax allows also splitting variables in the
Variable section
.
When long scalar variables (e.g.
${STRING}
) are split to multiple rows,
the final value is got by concatenating the rows together. The separator is
a space by default, but that can be changed by starting the value with
SEPARATOR=<sep>
.
Splitting lines is illustrated in the following two examples containing
exactly same data without and with splitting.
*** Settings ***
Documentation
Here we have documentation for this suite.\nDocumentation is often quite long.\n\nIt can also contain multiple paragraphs.
Test Tags
test tag 1
test tag 2
test tag 3
test tag 4
test tag 5
*** Variables ***
${
STRING
}
This is a long string. It has multiple sentences. It does not have newlines.
${
MULTILINE
}
This is a long multiline string.\nThis is the second line.\nThis is the third and the last line.
@{
LIST
}
this
list
is
quite
long
and
items in it can also be long
&{
DICT
}
first=This value is pretty long.
second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[
Tags
]
you
probably
do
not
have
this
many
tags
in
real
life
Do X
first argument
second argument
third argument
fourth argument
fifth argument
sixth argument
${
var
} =
Get X
first argument passed to this keyword is pretty long
second argument passed to this keyword is long too
*** Settings ***
Documentation
Here we have documentation for this suite.
...
Documentation is often quite long.
...
...
It can also contain multiple paragraphs.
Test Tags
test tag 1
test tag 2
test tag 3
...
test tag 4
test tag 5
*** Variables ***
${
STRING
}
This is a long string.
...
It has multiple sentences.
...
It does not have newlines.
${
MULTILINE
}
SEPARATOR=\n
...
This is a long multiline string.
...
This is the second line.
...
This is the third and the last line.
@{
LIST
}
this
list
is
quite
long
and
...
items in it can also be long
&{
DICT
}
first=This value is pretty long.
...
second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[
Tags
]
you
probably
do
not
have
this
many
...
tags
in
real
life
Do X
first argument
second argument
third argument
...
fourth argument
fifth argument
sixth argument
${
var
} =
Get X
...
first argument passed to this keyword is pretty long
...
second argument passed to this keyword is long too
2.1.5 Localization
Robot Framework localization efforts were started in Robot Framework 6.0
that allowed translation of
section headers
,
settings
,
Given/When/Then prefixes
used in Behavior Driven Development (BDD), and
true and false strings
used in automatic Boolean argument conversion.
The plan is to extend localization support in the future, for example,
to log and report and possibly also to control structures.
This section explains how to
activate languages
, what
built-in languages
are supported, how to create
custom language files
and how new translations
can be
contributed
.
Enabling languages
Using command line option
The main mechanism to activate languages is specifying them from the command line
using the
--language
option. When enabling
built-in languages
,
it is possible to use either the language name like
Finnish
or the language
code like
fi
. Both names and codes are case and space insensitive and also
the hyphen (
-
) is ignored. To enable multiple languages, the
--language
option needs to be used multiple times:
robot --language Finnish testit.robot
robot --language pt --language ptbr testes.robot
The same
--language
option is also used when activating
custom language files
. With them the value can be either a path to the file or,
if the file is in the
module search path
, the module name:
robot --language Custom.py tests.robot
robot --language MyLang tests.robot
For backwards compatibility reasons, and to support partial translations,
English is always activated automatically. Future versions may allow disabling
it.
Pre-file configuration
It is also possible to enable languages directly in data files by having
a line
Language: <value>
(case-insensitive) before any of the section
headers. The value after the colon is interpreted the same way as with
the
--language
option:
Language: Finnish
*** Asetukset ***
Dokumentaatio Example using Finnish.
If there is a need to enable multiple languages, the
Language:
line
can be repeated. These configuration lines cannot be in comments so something like
# Language: Finnish
has no effect.
Due to technical limitations, the per-file language configuration affects also
parsing subsequent files as well as the whole execution. This
behavior is likely to change in the future and
should not
be relied upon.
If you use per-file configuration, use it with all files or enable languages
globally with the
--language
option.
Built-in languages
The following languages are supported out-of-the-box. Click the language name
to see the actual translations:
Arabic (ar)
Bulgarian (bg)
Bosnian (bs)
Czech (cs)
German (de)
Spanish (es)
Finnish (fi)
French (fr)
Hindi (hi)
Italian (it)
Japanese (ja)
Korean (ko)
Dutch (nl)
Polish (pl)
Portuguese (pt)
Brazilian Portuguese (pt-BR)
Romanian (ro)
Russian (ru)
Swedish (sv)
Thai (th)
Turkish (tr)
Ukrainian (uk)
Vietnamese (vi)
Chinese Simplified (zh-CN)
Chinese Traditional (zh-TW)
All these translations have been provided by the awesome Robot Framework
community. If a language you are interested in is not included, you can
consider
contributing
it!
Custom language files
If a language you would need is not available as a built-in language, or you
want to create a totally custom language for some specific need, you can easily
create a custom language file. Language files are Python files that contain
one or more language definitions that are all loaded when the language file
is taken into use. Language definitions are created by extending the
robot.api.Language
base class and overriding class attributes as needed:
from
robot.api
import
Language
class
Example
(
Language
):
test_cases_header
=
'Validations'
tags_setting
=
'Labels'
given_prefixes
=
[
'Assuming'
]
true_strings
=
[
'OK'
,
'
\N{THUMBS UP SIGN}
'
]
Assuming the above code would be in file
example.py
, a path to that
file or just the module name
example
could be used when the language file
is
activated
.
The above example adds only some of the possible translations. That is fine
because English is automatically enabled anyway. Most values must be specified
as strings, but BDD prefixes and true/false strings allow more than one value
and must be given as lists. For more examples, see Robot Framework's internal
languages
module that contains the
Language
class as well as all built-in
language definitions.
Contributing translations
If you want to add translation for a new language or enhance existing, head
to
Crowdin
that we use for collaboration. For more details, see the
separate
Localization
project, and for questions and free discussion join
the
#localization
channel on our
Slack
.
2.1.6 Style
Robot Framework syntax creates a simple programming language, and similarly as with
other languages, it is important to think about the coding style. Robot Framework
syntax is pretty flexible on purpose, but there are some generally recommended
conventions:
Four space indentation.
Four space separation between keywords and arguments, settings and their values, etc...
In some cases it makes sense to use more than four spaces.
For example when aligning values in the Settings or Variables section or
in
data-driven style
.
Global
variables
using capital letters like
${EXAMPLE}
and local variables
using lower-case letters like
${example}
.
Consistency within a single file and preferably within the whole project.
One case where there currently is no strong convention is keyword capitalization.
Robot Framework itself typically uses title case like
Example Keyword
in
documentation and elsewhere, and this style is often used in Robot Framework data
as well. It does not work too well with longer, sentence-like keywords such as
Log into system as an admin
, though.
Teams and organizations using Robot Framework should have their own coding standards.
The community developed
Robot Framework Style Guide
is an excellent
starting point that can be amended as needed. It is also possible to enforce these
conventions by using the
Robocop
linter and the
Robotidy
code formatter.
2.2 Creating test cases
This section describes the overall test case syntax. Organizing test
cases into
test suites
using
suite files
and
suite
directories
is discussed in the next section.
When using Robot Framework for other automation purposes than test
automation, it is recommended to create
tasks
instead of tests.
The task syntax is for most parts identical to the test syntax,
and the differences are explained in the
Creating tasks
section.
2.2.1 Test case syntax
Basic syntax
Settings in the Test Case section
Test case related settings in the Setting section
2.2.2 Using arguments
Positional arguments
Default values
Variable number of arguments
Named arguments
Free named arguments
Named-only arguments
Arguments embedded to keyword names
2.2.3 Failures
When test case fails
Error messages
2.2.4 Test case name and documentation
2.2.5 Tagging test cases
Deprecation of
Force Tags
and
Default Tags
Reserved tags
2.2.6 Test setup and teardown
2.2.7 Test templates
Basic usage
Templates with multiple iterations
Templates with embedded arguments
Templates with
FOR
loops
Templates with
IF/ELSE
structures
2.2.8 Different test case styles
Keyword-driven style
Data-driven style
Behavior-driven style
2.2.1 Test case syntax
Basic syntax
Test cases are constructed in test case sections from the available
keywords. Keywords can be imported from
test libraries
or
resource
files
, or created in the
keyword section
of the test case file
itself.
The first column in the test case section 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 section. It is
an error to have something between the section 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.
*** Test Cases ***
Valid Login
Open Login Page
Input Username
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
Note
Although test case names can contain any character, using
?
and
especially
*
is not generally recommended because they are
considered to be
wildcards
when
selecting test cases
.
For example, trying to run only a test with name
Example *
like
--test 'Example *'
will actually run any test starting with
Example
.
Settings in the Test Case section
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
.
[Setup]
,
[Teardown]
Specify
test setup and teardown
.
[Tags]
Used for
tagging test cases
.
[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.
Note
Setting names are case-insensitive, but the format used above is
recommended. Settings used to be also space-insensitive, but that was
deprecated in Robot Framework 3.1 and trying to use something like
[T a g s]
causes an error in Robot Framework 3.2. Possible spaces
between brackets and the name (e.g.
[ Tags ]
) are still allowed.
Example test case with settings:
*** Test Cases ***
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
tool, but the same information is available on
documentation generated by generic documentation tools such as
pydoc
.
Positional 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.
*** Test Cases ***
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
. 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.
*** Test Cases ***
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 that a keyword accepts any number of arguments.
These so called
varargs
can be combined with mandatory arguments
and arguments with default values, but they are always given after
them. In the documentation they have an asterisk before the argument
name like
*varargs
.
For example,
Remove Files
and
Join Paths
keywords from
the
OperatingSystem
library 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.
*** Test Cases ***
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
The named argument syntax makes using arguments with
default values
more
flexible, and allows explicitly labeling what a certain argument value means.
Technically named arguments work exactly like
keyword arguments
in Python.
Basic syntax
It is possible to name an argument given to a keyword by prefixing the value
with the name of the argument like
arg=value
. This is especially
useful when multiple arguments have default values, as it is
possible to name only some the arguments and let others use their defaults.
For example, if a keyword accepts arguments
arg1=a, arg2=b, arg3=c
,
and it is called with one argument
arg3=override
, arguments
arg1
and
arg2
get their default values, but
arg3
gets value
override
. If this sounds complicated, the
named arguments
example
below hopefully makes it more clear.
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 neither
Arg=value
nor
ARG=value
works. The latter means that spaces are not allowed before the
=
sign, and possible spaces after it are considered part of the given value.
When the named argument syntax is used with
user keywords
, the argument
names must be given without the
${}
decoration. For example, user
keyword with arguments
${arg1}=first, ${arg2}=second
must be used
like
arg2=override
.
Using normal positional arguments after named arguments like, for example,
| Keyword | arg=value | positional |
, does not work.
The relative order of the named arguments does not matter.
Named arguments with variables
It is possible to use
variables
in both named argument names and values.
If the value is a single
scalar variable
, it is passed to the keyword as-is.
This allows using any objects, not only strings, as values also when using
the named argument syntax. For example, calling a keyword like
arg=${object}
will pass the variable
${object}
to the keyword without converting it to
a string.
If variables are used in named argument names, variables are resolved before
matching them against argument names.
The named argument syntax requires the equal sign to be written literally
in the keyword call. This means that variable alone can never trigger the
named argument syntax, not even if it has a value like
foo=bar
. This is
important to remember especially when wrapping keywords into other keywords.
If, for example, a keyword takes a
variable number of arguments
like
@{args}
and passes all of them to another keyword using the same
@{args}
syntax, possible
named=arg
syntax used in the calling side is not recognized.
This is illustrated by the example below.
*** Test Cases ***
Example
Run Program
shell=True
# This will not come as a named argument to Run Process
*** Keywords ***
Run Program
[
Arguments
] @{
args
}
Run Process
program.py
@{
args
}
# Named arguments are not recognized from inside @{args}
If keyword needs to accept and pass forward any named arguments, it must be
changed to accept
free named arguments
. See
free named argument examples
for a wrapper keyword version that can pass both positional and named
arguments forward.
Escaping named arguments syntax
The named argument syntax is used only when the part of the argument
before the equal sign matches one of the keyword's arguments. It is possible
that there is a positional argument with a literal value like
foo=quux
,
and also an unrelated argument with name
foo
. In this case the argument
foo
either incorrectly gets the value
quux
or, more likely,
there is a syntax error.
In these rare cases where there are accidental matches, it is possible to
use the backslash character to
escape
the syntax like
foo\=quux
.
Now the argument will get a literal value
foo=quux
. Note that escaping
is not needed if there are no arguments with name
foo
, but because it
makes the situation more explicit, it may nevertheless be a good idea.
Where named arguments are supported
As already explained, the named argument syntax works with keywords. In
addition to that, it also works when
importing libraries
.
Naming arguments is supported by
user keywords
and by most
test libraries
.
The only exceptions are Python keywords explicitly using
positional-only arguments
.
Named arguments example
The following example demonstrates using the named arguments syntax with
library keywords, user keywords, and when importing the
Telnet
test library.
*** Settings ***
Library
Telnet
prompt=$
default_log_level=DEBUG
*** Test Cases ***
Example
Open connection
10.0.0.42
port=
${
PORT
}
alias=example
List files
options=-lh
List files
path=/tmp
options=-l
*** Keywords ***
List files
[
Arguments
] ${
path
}
=.
${
options
}
=
Execute command
ls
${
options
}
${
path
}
Free named arguments
Robot Framework supports
free named arguments
, often also called
free
keyword arguments
or
kwargs
, similarly as
Python supports **kwargs
.
What this means is that a keyword can receive all arguments that use
the
named argument syntax
(
name=value
) and do not match any arguments
specified in the signature of the keyword.
Free named arguments are supported by same keyword types than
normal named
arguments
. How keywords specify that they accept free named arguments
depends on the keyword type. For example,
Python based keywords
simply use
**kwargs
and
user keywords
use
&{kwargs}
.
Free named arguments support variables similarly as
named arguments
. In practice that means that variables
can be used both in names and values, but the escape sign must always be
visible literally. For example, both
foo=${bar}
and
${foo}=${bar}
are
valid, as long as the variables that are used exist. An extra limitation is
that free argument names must always be strings.
Examples
As the first example of using free named arguments, let's take a look at
Run Process
keyword in the
Process
library. It has a signature
command, *arguments, **configuration
, which means that it takes the command
to execute (
command
), its arguments as
variable number of arguments
(
*arguments
) and finally optional configuration parameters as free named
arguments (
**configuration
). The example below also shows that variables
work with free keyword arguments exactly like when
using the named argument
syntax
.
*** Test Cases ***
Free Named Arguments
Run Process
program.py
arg1
arg2
cwd=/home/user
Run Process
program.py
argument
shell=True
env=
${
ENVIRON
}
See
Free keyword arguments (**kwargs)
section under
Creating test
libraries
for more information about using the free named arguments syntax
in your custom test libraries.
As the second example, let's create a wrapper
user keyword
for running the
program.py
in the above example. The wrapper keyword
Run Program
accepts all positional and named arguments and passes them forward to
Run Process
along with the name of the command to execute.
*** Test Cases ***
Free Named Arguments
Run Program
arg1
arg2
cwd=/home/user
Run Program
argument
shell=True
env=
${
ENVIRON
}
*** Keywords ***
Run Program
[
Arguments
] @{
args
} &{
config
}
Run Process
program.py
@{
args
} &{
config
}
Named-only arguments
Keywords can accept arguments that must
always be named using the
named argument syntax
. If, for example,
a keyword would accept a single named-only argument
example
, it would
always need to be used like
example=value
and using just
value
would
not work. This syntax is inspired by Python's
keyword-only arguments
syntax.
For most parts named-only arguments work the same way as
named arguments
.
The main difference is that libraries implemented with Python 2 using
the
static library API
do not support this syntax
.
As an example of using the
named-only arguments with user keywords
, here
is a variation of the
Run Program
in the above
free named argument
examples
that only supports configuring
shell
:
*** Test Cases ***
Named-only Arguments
Run Program
arg1
arg2
# 'shell' is False (default)
Run Program
argument
shell=True
# 'shell' is True
*** Keywords ***
Run Program
[
Arguments
] @{
args
} ${
shell
}
=False
Run Process
program.py
@{
args
}
shell=
${
shell
}
Arguments embedded to keyword names
A totally different approach to specify arguments is embedding them
into keyword names. This syntax is supported by both
test library keywords
and
user keywords
.
2.2.3 Failures
When test case fails
A test case fails if any of the keyword it uses fails. Normally this means that
execution of that test case is stopped, possible
test teardown
is executed,
and then execution continues from the next test case. It is also possible to
use special
continuable failures
if stopping test execution is not desired.
Error messages
The error message assigned to a failed test case is got directly from the
failed keyword. Often the error message is created by the keyword itself, but
some keywords allow configuring them.
In some circumstances, for example when continuable failures are used,
a test case can fail multiple times. In that case the final error message
is got by combining the individual errors. Very long error messages are
automatically cut from the middle
to keep
reports
easier to read, but
full error messages are always visible in
log files
as messages of
the failed keywords.
By default error messages are normal text, but
they can
contain HTML formatting
. This
is enabled by starting the error message with marker string
*HTML*
.
This marker will be removed from the final error message shown in reports
and logs. Using HTML in a custom message is shown in the second example below.
*** Test Cases ***
Normal Error
Fail
This is a rather boring example...
HTML Error
${
number
} =
Get Number
Should Be Equal
${
number
}
42
*HTML* Number is not my <b>MAGIC</b> number.
2.2.4 Test case name and documentation
The test case name comes directly from the Test Case section: 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.
Starting from Robot Framework 3.2, possible
variables
in the test case name
are resolved so that the final name will contain the variable value. If
the variable does not exist, its name is left unchanged.
*** Variables ***
${
MAX AMOUNT
} ${
5000000
}
*** Test Cases ***
Amount cannot be larger than
${
MAX AMOUNT
}
# ...
The
[Documentation]
setting allows setting free form
documentation for a test case. That text is shown in the command line
output and in the resulting logs and reports.
If documentation gets long, it can be
split into multiple rows
.
It is possible to use simple
HTML formatting
and
variables
can
be used to make the documentation dynamic. Possible non-existing
variables are left unchanged.
*** Test Cases ***
Simple
[
Documentation
]
Simple and short documentation.
No Operation
Multiple lines
[
Documentation
]
First row of the documentation.
...
...
Documentation continues here. These rows form
...
a paragraph when shown in HTML outputs.
No Operation
Formatting
[
Documentation
]
...
This list has:
...
- *bold*
...
- _italics_
...
- 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.5 Tagging test cases
Using tags in Robot Framework is a simple, yet powerful mechanism for
classifying test cases and also
user keywords
. Tags are free text and
Robot Framework itself has no special meaning for them except for the
reserved tags
discussed below. Tags can be used at least for the following
purposes:
They 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 and skipped) are
automatically collected based on them.
They can be used to
include and exclude
as well as to
skip
test cases.
There are multiple ways how to specify tags for test cases explained below:
Test Tags
setting in the Settings section
All tests in a test case file with this setting always get specified tags.
If this setting is used in a
suite initialization file
, all tests
in child suites get these tags.
[Tags]
setting with each test case
Tests get these tags in addition to tags specified using the
Test Tags
setting. The
[Tags]
setting also allows removing tags set with
Test Tags
by using the
-tag
syntax.
--settag
command line option
All tests get tags set with this option in addition to tags they got elsewhere.
Set Tags
,
Remove Tags
,
Fail
and
Pass Execution
keywords
These
BuiltIn
keywords can be used to manipulate tags dynamically
during the test execution.
Example:
*** Settings ***
Test Tags
requirement: 42
smoke
*** Variables ***
${
HOST
}
10.0.1.42
*** Test Cases ***
No own tags
[
Documentation
]
Test has tags 'requirement: 42' and 'smoke'.
No Operation
Own tags
[
Documentation
]
Test has tags 'requirement: 42', 'smoke' and 'not ready'.
[
Tags
]
not ready
No Operation
Own tags with variable
[
Documentation
]
Test has tags 'requirement: 42', 'smoke' and 'host: 10.0.1.42'.
[
Tags
]
host:
${
HOST
}
No Operation
Remove common tag
[
Documentation
]
Test has only tag 'requirement: 42'.
[
Tags
]
-smoke
No Operation
Remove common tag using a pattern
[
Documentation
]
Test has only tag 'smoke'.
[
Tags
]
-requirement: *
No Operation
Set Tags and Remove Tags keywords
[
Documentation
]
This test has tags 'smoke', 'example' and 'another'.
Set Tags
example
another
Remove Tags
requirement: *
As the example shows, tags can be created using variables, but otherwise they
preserve the exact name used in the data. When tags are compared, for example,
to collect statistics, to select test to be executed, or to remove duplicates,
comparisons are case, space and underscore insensitive.
As demonstrated by the above examples, removing tags using
-tag
syntax supports
simple patterns
like
-requirement: *
. Tags starting with a hyphen have no
special meaning otherwise than with the
[Tags]
setting. If there is
a need to set a tag starting with a hyphen with
[Tags]
, it is possible
to use the
escaped
format like
\-tag
.
At the moment the
-tag
syntax can be used for removing tags only with the
[Tags]
setting, but the plan is to support this functionality also
with the
Test Tags
setting in Robot Framework 8.0 (
#5250
).
Setting tags having a literal value that starts with a hyphen in
Test Tags
was deprecated in Robot Framework 7.2 (
#5252
). The escaped format like
\-tag
can be used if tags with such values are needed.
Note
The
Test Tags
setting is new in Robot Framework 6.0.
Earlier versions support
Force Tags
and
Default Tags
settings discussed in the next section.
Note
The
-tag
syntax for removing tags using the
[Tags]
setting
is new in Robot Framework 7.0.
2.2.6 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.
A setup and a 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
.
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. In addition, 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 section. Individual test cases can
also have their own setup or teardown. They are defined with the
[Setup]
or
[Teardown]
settings in the test case
section 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. It is also possible to use value
NONE
to indicate that
a test has no setup/teardown.
*** Settings ***
Test Setup
Open Application
App A
Test Teardown
Close Application
*** Test Cases ***
Default values
[
Documentation
]
Setup and teardown from setting section
Do Something
Overridden setup
[
Documentation
]
Own setup, teardown from setting section
[
Setup
]
Open Application
App B
Do Something
No teardown
[
Documentation
]
Default setup, no teardown at all
Do Something
[
Teardown
]
No teardown 2
[
Documentation
]
Setup and teardown can be disabled also with special value NONE
Do Something
[
Teardown
]
NONE
Using variables
[
Documentation
]
Setup and teardown specified using variables
[
Setup
] ${
SETUP
}
Do Something
[
Teardown
] ${
TEARDOWN
}
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.7 Test templates
Test templates convert normal
keyword-driven
test cases into
data-driven
tests. Whereas the body of a keyword-driven test case
is constructed from keywords and their possible arguments, test cases with
template contain only the arguments for the template keyword.
Instead of repeating the same keyword multiple times per test and/or with all
tests in a file, it is possible to use it only per test or just once per file.
Template keywords can accept both normal positional and named arguments, as
well as arguments embedded to the keyword name. Unlike with other settings,
it is not possible to define a template using a variable.
Basic usage
How a keyword accepting normal positional arguments can be used as a template
is illustrated by the following example test cases. These two tests are
functionally fully identical.
*** Test Cases ***
Normal test case
Example keyword
first argument
second argument
Templated test case
[
Template
]
Example keyword
first argument
second argument
As the example 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 section, 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 section, and
an empty value for
[Template]
means that the test has no
template even when
Test Template
is used. It is also possible
to use value
NONE
to indicate that a test has no template.
Using keywords with
default values
or accepting
variable number of arguments
,
as well as using
named arguments
and
free named arguments
, work with templates
exactly like they work otherwise. Using
variables
in arguments is also
supported normally.
Templates with multiple iterations
If a templated test case has multiple data rows in its body, the template
is applied for all the rows one by one. This
means that the same keyword is executed multiple times, once with data
on each row.
*** Settings ***
Test Template
Example keyword
*** Test Cases ***
Templated test case
first round 1
first round 2
second round 1
second round 2
third round 1
third round 2
Templated tests are special so that all iterations are executed even if one
or more of them is failed or skipped. The aggregated result of a templated
test with multiple iterations is:
FAIL if any of the iterations failed.
PASS if there were no failures and at least one iteration passed.
SKIP if all iterations were skipped.
Note
It is possible to use the
continue on failure
mode also with normal
tests, but with the templated tests the mode is on automatically. If
needed, the mode can also be
disabled
with templates by using the
robot:stop-on-failure
tag.
Note
Running all iterations if one or more is skipped is new in Robot
Framework 7.2. With earlier versions the execution stopped for the
first skipped iteration and the test got the SKIP status regardless
of the status of the earlier iterations.
Templates with embedded arguments
Templates support a variation of
the
embedded argument syntax
. With templates this syntax works so
that if the template keyword has variables in its name, they are considered
placeholders for arguments and replaced with the actual arguments
used with the template. The resulting keyword is then used without positional
arguments. This is best illustrated with an example:
*** Test Cases ***
Normal test case with embedded arguments
The result of 1 + 1 should be 2
The result of 1 + 2 should be 3
Template with embedded arguments
[
Template
]
The result of
${
calculation
}
should be
${
expected
}
1 + 1
2
1 + 2
3
*** Keywords ***
The result of
${
calculation
}
should be
${
expected
}
${
result
} =
Calculate
${
calculation
}
Should Be Equal
${
result
} ${
expected
}
When embedded arguments are used with templates, the number of arguments in
the template keyword name must match the number of arguments it is used with.
The argument names do not need to match the arguments of the original keyword,
though, and it is also possible to use different arguments altogether:
*** Test Cases ***
Different argument names
[
Template
]
The result of
${
foo
}
should be
${
bar
}
1 + 1
2
1 + 2
3
Only some arguments
[
Template
]
The result of
${
calculation
}
should be 3
1 + 2
4 - 1
New arguments
[
Template
]
The
${
meaning
}
of
${
life
}
should be 42
result
21 * 2
The main benefit of using embedded arguments with templates is that
argument names are specified explicitly. When using normal arguments,
the same effect can be achieved by naming the columns that contain
arguments. This is illustrated by the
data-driven style
example in
the next section.
Templates with
FOR
loops
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.
*** Test Cases ***
Template with FOR loop
[
Template
]
Example keyword
FOR
${
item
}
IN
@{
ITEMS
}
${
item
}
2nd arg
END
FOR
${
index
}
IN RANGE
42
1st arg
${
index
}
END
Templates with
IF/ELSE
structures
IF/ELSE structures
can be also used together with templates.
This can be useful, for example, when used together with
FOR loops
to
filter executed arguments.
*** Test Cases ***
Template with FOR and IF
[
Template
]
Example keyword
FOR
${
item
}
IN
@{
ITEMS
}
IF
${
item
}
< 5
${
item
}
2nd arg
END
END
2.2.8 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, often 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.
*** Settings ***
Test Template
Login with invalid credentials should fail
*** Test Cases ***
USERNAME
PASSWORD
Invalid User Name
invalid
${
VALID PASSWORD
}
Invalid Password
${
VALID USER
}
invalid
Invalid User Name and Password
invalid
invalid
Empty User Name
${
EMPTY
} ${
VALID PASSWORD
}
Empty Password
${
VALID USER
} ${
EMPTY
}
Empty User Name and Password
${
EMPTY
} ${
EMPTY
}
Tip
Naming columns like in the example above makes tests easier to
understand. This is possible because on the header row other
cells except the first one
are ignored
.
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.
*** Test Cases ***
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
}
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) or
Specification by Example
.
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
or
But
may be used if a step has more
than one action.
*** Test Cases ***
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/But
prefixes
Prefixes
Given
,
When
,
Then
,
And
and
But
can be omitted when creating keywords. For example,
Given login page is open
in the above example is typically implemented without the word
Given
so that the name is just
Login page is open
. Omitting prefixes allows using
the same keyword with different prefixes. For example,
Welcome page
should be open
could be used as
Then welcome page should be open
or
and welcome page should be open
.
Note
These prefixes can be
localized
. See the
Translations
appendix
for supported translations.
Embedding data to keywords
When writing concrete examples it is useful to be able to pass actual data to
keyword implementations. This can be done by
embedding arguments into keyword name
.
2.3 Creating tasks
In addition to test automation, Robot Framework can be used for other
automation purposes, including
robotic process automation
(RPA).
It has always been possible, but Robot Framework 3.1 added official
support for automating
tasks
, not only tests. For most parts creating
tasks works the same way as
creating tests
and the only real difference
is in terminology. Tasks can also be organized into
suites
exactly like
test cases.
2.3.1 Task syntax
2.3.2 Task related settings
2.3.1 Task syntax
Tasks are created based on the available keywords exactly like test cases,
and the task syntax is in general identical to the
test case syntax
.
The main difference is that tasks are created in Task sections
instead of Test Case sections:
*** Tasks ***
Process invoice
Read information from PDF
Validate information
Submit information to backend system
Validate information is visible in web UI
It is an error to have both tests and tasks in same file.
2.4 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. Same concepts apply also when
creating tasks
, but the terminology differs.
2.4.1 Suite files
2.4.2 Suite directories
Suite initialization files
2.4.3 Suite name
2.4.4 Suite documentation
2.4.5 Free suite metadata
2.4.6 Suite setup and teardown
2.4.1 Suite files
Robot Framework test cases
are created
using test case sections in
suite files, also known as 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 section can be used to customize the suite:
Name
Used for setting a custom
suite name
. The default name is created based
on the file or directory name.
Documentation
Used for specifying a
suite documentation
.
Metadata
Used for setting
free suite metadata
as name-value pairs.
Suite Setup
,
Suite Teardown
Specify
suite setup and teardown
.
Note
Setting names are case-insensitive, but the format used above is recommended.
2.4.2 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 in
supported file formats
are processed.
Other files are ignored.
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.
Suite 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 suite initialization
file. An initialization file name must always be of the format
__init__.ext
, where the extension must be one of the
supported
file formats
(typically
__init__.robot
).
The name format is borrowed from Python, where files named in this manner
denote that a directory is a module.
Starting from Robot Framework 6.1, it is also possible to define a suite
initialization file for automatically created suite when starting the test
execution by giving multiple
paths
.
Initialization files have the same structure and syntax as test case files,
except that they cannot have test case sections and not all settings are
supported. Variables and keywords created or imported in initialization files
are not
available in the lower level suites. If you need to share
variables or keywords, you can put them into
resource files
that can be
imported both by initialization and test case files.
The main usage for initialization files is specifying suite related
settings similarly as in
suite files
, but setting some
test case
related settings
is also possible. How to use different settings in the
initialization files is explained below.
Name
,
Documentation
,
Metadata
,
Suite Setup
,
Suite Teardown
These suite specific settings work the same way in suite initialization files
as in suite files.
Test Tags
Specified tags are unconditionally set to all tests in all suite files
this directory contains, recursively. New in Robot Framework 6.1. The
deprecated
Force Tags
needs to be used with older versions.
Test Setup
,
Test Teardown
,
Test Timeout
Set the default value for test setup/teardown or test timeout to all test
cases this directory contains. Can be overridden on lower level.
Notice that keywords used as setups and teardowns must be available in
test case files where tests using them are. Defining keywords in the
initialization file itself is not enough.
Task Setup
,
Task Teardown
,
Task Tags
,
Task Timeout
Aliases for
Test Setup
,
Test Teardown
,
Test Tags
and
Test Timeout
, respectively, that can be used when
creating tasks
, not tests.
Test Template
,
Default Tags
Not supported in initialization files.
*** Settings ***
Documentation
Example suite
Suite Setup
Do Something
${
MESSAGE
}
Test Tags
example
Library
SomeLibrary
*** Variables ***
${
MESSAGE
}
Hello, world!
*** Keywords ***
Do Something
[
Arguments
] ${
args
}
Some Keyword
${
arg
}
Another Keyword
Note
When you run a suite file or directory, possible suite initialization
files in higher level directories are not taken into account. If that
is not desired, run the appropriate higher level suite directory and use
the
--suite
option to select which child suite inside it is executed.
2.4.3 Suite name
The test suite name is constructed from the file or directory name by default.
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.robot
becomes
Some Tests
and
My_test_directory
becomes
My test directory
.
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.robot
and
02__more_tests.robot
create test
suites
Some Tests
and
More Tests
, respectively, and
the former is executed before the latter.
Starting from Robot Framework 6.1, it is also possible to give a custom name
to a suite by using the
Name
setting in the Setting section:
*** Settings ***
Name
Custom suite name
The name of the top-level suite
can be overridden
from the command line with
the
--name
option.
2.4.4 Suite documentation
The documentation for a test suite is set using the
Documentation
setting in the Settings section. It can be used both in
suite files
and in
suite initialization files
. Suite documentation has exactly
the same characteristics regarding to where it is shown and how it can
be created as
test case documentation
. For details about the syntax
see the
Documentation formatting
appendix.
*** Settings ***
Documentation
An example suite documentation with *some* _formatting_.
...
Long documentation can be split into multiple lines.
The documentation of the top-level suite
can be overridden
from
the command line with the
--doc
option.
2.4.6 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 suite 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
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 section with
Suite Setup
and
Suite Teardown
settings,
respectively. 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.
Note that 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.5 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.5.1 Importing libraries
Using
Library
setting
Using
Import Library
keyword
2.5.2 Specifying library to import
Using library name
Using physical path to library
2.5.3 Setting custom name to library
2.5.4 Standard libraries
Normal standard libraries
Remote library
2.5.5 External libraries
2.5.1 Importing libraries
Test libraries are typically imported using the
Library
setting,
but it is also possible to use the
Import Library
keyword.
Using
Library
setting
Libraries are normally imported in the Settings section using the
Library
setting with the library name or path as its value.
Unlike most of the other data, the library name or path
is both case- and space-sensitive. If a library is in a package,
the full name including the 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.
*** Settings ***
Library
OperatingSystem
Library
path/to/MyLibrary.py
Library
my.package.TestLibrary
Library
LibraryAcceptingArguments
arg1
arg2
Library
${
LIBRARY
}
It is possible to import test libraries in
suite files
,
resource files
and
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 or path 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.
*** Test Cases ***
Example
Do Something
Import Library
MyLibrary
arg1
arg2
KW From MyLibrary
2.5.2 Specifying library to import
Libraries to import can be specified either by using the library name
or the path to the library. These approaches work the same way regardless
if the library is imported using the
Library
setting or the
Import Library
keyword.
Using library name
The most common way to specify a test library to import is using its name.
In these cases Robot Framework tries to find the class or module
implementing the library from the
module search path
. Libraries that
are installed somehow ought to be in the module search path automatically,
but with other libraries the search path may need to be configured separately.
*** Settings ***
Library
OperatingSystem
Library
CustomLibrary
possible
arguments
Library
librarymodule.LibraryClass
The biggest benefit of this approach is that when the module 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 module search path.
If the library is a file, the path to it must contain extension,
i.e.
.py
. If a library is implemented
as a directory, the path to it must have a trailing forward slash (
/
)
if the path is relative. With absolute paths the trailing slash is optional.
Following examples demonstrate these different usages.
*** Settings ***
Library
PythonLibrary.py
Library
relative/path/PythonDirLib/
possible
arguments
Library
${
RESOURCES
}
/Example.py
2.5.3 Setting custom name to 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.
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
AS
(case-sensitive) after the library name and then
having the new name after that. The specified name is shown in
logs and must be used in the test data when using keywords' full name
(
LibraryName.Keyword Name
).
*** Settings ***
Library
packagename.TestLib
AS
TestLib
Library
${
LIBRARY
}
AS
MyName
Possible arguments to the library are placed between the
original library name and the
AS
marker. The following example
illustrates how the same library can be imported several times with
different arguments:
*** Settings ***
Library
SomeLibrary
localhost
1234
AS
LocalLib
Library
SomeLibrary
server.domain
8080
AS
RemoteLib
*** Test Cases ***
Example
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 section and when using the
Import Library
keyword.
Note
Prior to Robot Framework 6.0 the marker to use when giving a custom name
to a library was
WITH NAME
instead of
AS
. The old syntax continues
to work, but it is considered deprecated and will eventually be removed.
2.5.4 Standard libraries
Some test libraries are distributed with Robot Framework and these
libraries are called
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.
Remote library
In addition to the normal standard libraries listed above, there is
also
Remote
library that 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 this concept.
2.5.5 External libraries
Any test library that is not one of the standard libraries is, by
definition,
an external library
. The Robot Framework open source community
has implemented several generic libraries, such as
SeleniumLibrary
and
SwingLibrary
, which are not packaged with the core framework. A list of
publicly available libraries can be found from
http://robotframework.org
.
Generic and custom libraries can obviously also be implemented by teams using
Robot Framework. See
Creating test libraries
section for more information
about that topic.
Different external libraries can have a totally different mechanism
for installing them and taking them into use. Sometimes they may also require
some other dependencies to be installed separately. All libraries
should have clear installation and usage documentation and they should
preferably automate the installation process.
2.6 Variables
2.6.1 Introduction
2.6.2 Using variables
Scalar variable syntax
List variable syntax
Dictionary variable syntax
Accessing list and dictionary items
Environment variables
2.6.3 Creating variables
Variable section
Using variable files
Command line variables
Return values from keywords
VAR
syntax
Set Test/Suite/Global Variable
keywords
Variable type conversion
Secret variables
2.6.4 Built-in variables
Operating-system variables
Number variables
Boolean and None/null variables
Space and empty variables
Automatic variables
2.6.5 Variable priorities and scopes
Variable priorities
Variable scopes
2.6.6 Advanced variable features
Extended variable syntax
Extended variable assignment
Variables inside variables
Inline Python evaluation
2.6.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 and Keyword sections, 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 has its own variables that can be used as
scalars
,
lists
or
dictionaries
using syntax
${SCALAR}
,
@{LIST}
and
&{DICT}
,
respectively. In addition to this,
environment variables
can be used
directly with syntax
%{ENV_VAR}
.
Variables are useful, for example, in these cases:
When values used in multiple places in the data change often. When using variables,
you only need to make changes in one place where the variable is defined.
When creating system-independent and operating-system-independent data.
Using variables instead of hard-coded values 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 RESOURCES:/opt/resources
--variable HOST:10.0.0.2:1234
). This also facilitates
localization testing, which often involves running the same tests
with different localized strings.
When there is a need to have objects other than strings as arguments
for keywords. This is not possible without variables, unless keywords
themselves support argument conversion.
When different keywords, even in different test libraries, need to
communicate. You can assign a return value from one keyword to a
variable and pass it as an argument to another.
When values in the test data are long or otherwise complicated. For
example, using
${URL}
is more convenient than using something like
http://long.domain.name:8080/path/to/service?foo=1&bar=2&zap=42
.
If a non-existent 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.6.2 Using variables
This section explains how to use variables using the normal scalar
variable syntax
${var}
, how to expand lists and dictionaries
like
@{var}
and
&{var}
, respectively, and how to use environment
variables like
%{var}
. Different ways how to create variables are discussed
in the next section.
Robot Framework variables, similarly as keywords, are
case-insensitive, and also spaces and underscores are
ignored. However, it is recommended to use capital letters with
global variables (for example,
${PATH}
or
${TWO WORDS}
)
and small letters with local variables that are only available in certain
test cases or user keywords (for example,
${my var}
). Much more
importantly, though, case should be used consistently.
A variable name, such as
${example}
, consists of the variable identifier
(
$
,
@
,
&
,
%
), curly braces (
{
,
}
), and the base name between the
braces. When creating variables, there may also be a
variable type definition
after the base name like
${example: int}
.
The variable base name can contain any characters. It is, however, highly
recommended to use only alphabetic characters, numbers, underscores and spaces.
That is a requirement for using the
extended variable syntax
already now and
in the future that may be required with all variables.
Scalar variable syntax
The most common way to use variables in Robot Framework test data is using
the scalar variable syntax like
${var}
. When this syntax is used, the
variable name is replaced with its value as-is. Most of the time variable
values are strings, but variables can contain any object, including numbers,
lists, dictionaries, or even custom objects.
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,
these two example test cases are equivalent:
*** Test Cases ***
Constants
Log
Hello
Log
Hello, world!!
Variables
Log
${
GREET
}
Log
${
GREET
}
,
${
NAME
}
!!
When a scalar variable is used alone without any text or other variables
around it, like in
${GREET}
above, the variable is replaced with
its value as-is and the value can be any object. If the variable is not used
alone, like
${GREER}, ${NAME}!!
above, its value is first converted into
a string and then concatenated with the other data.
Note
Variable values are used as-is without string conversion 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 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 Python
object:
class
MyObj
:
def
__str__
(
self
):
return
"Hi, terra!"
With these two variables set, we then have the following test data:
*** Test Cases ***
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, terra!"
Scalar variables containing bytes
Variables containing
bytes
or
bytearrays
are handled slightly differently
than other variables containing non-string values:
If they are used alone, everything works exactly as with other objects and
their values are passed to keywords as-is.
If they are concatenated only with other variables that also contain bytes or
bytearrays, the result is bytes instead of a string.
If they are concatenated with strings or with variables containing other
types than bytes or bytearrays, they are converted to strings like other
objects, but they have a different string representation than they normally
have in Python. With Python the string representation contains surrounding
quotes and a
b
prefix like
b'\x00'
, but with Robot Framework quotes
and the prefix are omitted, and each byte is mapped to a Unicode code point
with the same ordinal. In practice this is same as converting bytes to strings
using the Latin-1 encoding. This format has a big benefit that the resulting
string can be converted back to bytes, for example, by using the
BuiltIn
keyword
Convert To Bytes
or by automatic
argument conversion
.
The following examples demonstrates using bytes and bytearrays would work
exactly the same way. Variable
${a}
is expected to contain bytes
\x00\x01
and variable
${b}
bytes
a\xe4
.
*** Test Cases ***
Bytes alone
[
Documentation
]
Keyword gets bytes '\x00\x01'.
Keyword
${
a
}
Bytes concatenated with bytes
[
Documentation
]
Keyword gets bytes '\x00\x01a\xe4'.
Keyword
${
a
}${
b
}
Bytes concatenated with others
[
Documentation
]
Keyword gets string '=\x00\x01a\xe4='.
Keyword
=
${
a
}${
b
}
=
Note
Getting bytes when variables containing bytes are concatenated is new
in Robot Framework 7.2. With earlier versions the result was a string.
Note
All bytes being mapped to matching Unicode code points in string
representation is new Robot Framework 7.2. With earlier versions,
only bytes in the ASCII range were mapped directly to code points and
other bytes were represented in an escaped format.
List variable syntax
When a variable is used as a scalar like
${EXAMPLE}
, its value is be
used as-is. If a variable value is a list or list-like, it is also possible
to use it as a list variable like
@{EXAMPLE}
. In this case the list is expanded
and individual items are passed in as separate arguments.
This is easiest to explain with an example. Assuming that a variable
${USER}
contains a list with two items
robot
and
secret
, the first two of these tests
are equivalent:
*** Test Cases ***
Constants
Login
robot
secret
List variable
Login
@{
USER
}
List as scalar
Keyword
${
USER
}
The third test above illustrates that a variable containing a list can be used
also as a scalar. In that test the keyword gets the whole list as a single argument.
Starting from Robot Framework 4.0, list expansion can be used in combination with
list item access
making these usages possible:
*** Test Cases ***
Nested container
${
nested
} =
Evaluate
[['a', 'b', 'c'], {'key': ['x', 'y']}]
Log Many
@{
nested
}[
0
]
# Logs 'a', 'b' and 'c'.
Log Many
@{
nested
}[
1
]
[key]
# Logs 'x' and 'y'.
Slice
${
items
} =
Create List
first
second
third
Log Many
@{
items
}[
1:
]
# Logs 'second' and 'third'.
Using list variables with other data
It is possible to use list variables with other arguments, including
other list variables.
*** Test Cases ***
Example
Keyword
@{
LIST
}
more
args
Keyword
${
SCALAR
} @{
LIST
}
constant
Keyword
@{
LIST
} @{
ANOTHER
} @{
ONE MORE
}
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.
*** Settings ***
Library
ExampleLibrary
@{
LIB ARGS
}
# This works
Library
${
LIBRARY
} @{
LIB ARGS
}
# This works
Library
@{
LIBRARY AND ARGS
}
# This does not work
Suite Setup
Some Keyword
@{
KW ARGS
}
# This works
Suite Setup
${
KEYWORD
} @{
KW ARGS
}
# This works
Suite Setup
@{
KEYWORD AND ARGS
}
# This does not work
Test Tags
@{
TAGS
}
# This works
Dictionary variable syntax
As discussed above, a variable containing a list can be used as a
list
variable
to pass list items to a keyword as individual arguments.
Similarly, a variable containing a Python dictionary or a dictionary-like
object can be used as a dictionary variable like
&{EXAMPLE}
. In practice
this means that the dictionary is expanded and individual items are passed as
named arguments
to the keyword. Assuming that a variable
&{USER}
has a
value
{'name': 'robot', 'password': 'secret'}
, the first two test cases
below are equivalent:
*** Test Cases ***
Constants
Login
name=robot
password=secret
Dictionary variable
Login
&{
USER
}
Dictionary as scalar
Keyword
${
USER
}
The third test above illustrates that a variable containing a dictionary can be used
also as a scalar. In that test the keyword gets the whole dictionary as a single argument.
Starting from Robot Framework 4.0, dictionary expansion can be used in combination with
dictionary item access
making usages like
&{nested}[key]
possible.
Using dictionary variables with other data
It is possible to use dictionary variables with other arguments, including
other dictionary variables. Because
named argument syntax
requires positional
arguments to be before named argument, dictionaries can only be followed by
named arguments or other dictionaries.
*** Test Cases ***
Example
Keyword
&{
DICT
}
named=arg
Keyword
positional
@{
LIST
} &{
DICT
}
Keyword
&{
DICT
} &{
ANOTHER
} &{
ONE MORE
}
Using dictionary variables with settings
Dictionary variables cannot generally be used with settings. The only exception
are imports, setups and teardowns where dictionaries can be used as arguments.
*** Settings ***
Library
ExampleLibrary
&{
LIB ARGS
}
Suite Setup
Some Keyword
&{
KW ARGS
}
named=arg
Accessing list and dictionary items
It is possible to access items of subscriptable variables, e.g. lists and dictionaries,
using special syntax like
${var}[item]
or
${var}[nested][item]
.
Starting from Robot Framework 4.0, it is also possible to use item access together with
list expansion
and
dictionary expansion
by using syntax
@{var}[item]
and
&{var}[item]
, respectively.
Note
Prior to Robot Framework 3.1, the normal item access syntax was
@{var}[item]
with lists and
&{var}[item]
with dictionaries. Robot Framework 3.1 introduced
the generic
${var}[item]
syntax along with some other nice enhancements and
the old item access syntax was deprecated in Robot Framework 3.2.
Accessing sequence items
It is possible to access a certain item of a variable containing a
sequence
(e.g. list, string or bytes) with the syntax
${var}[index]
, where
index
is the index of the selected value. Indices start from zero, negative indices
can be used to access items from the end, and trying to access an item with
too large an index causes an error. Indices are automatically converted to
integers, and it is also possible to use variables as indices.
*** Test Cases ***
Positive index
Login
${
USER
}
[0]
${
USER
}
[1]
Title Should Be
Welcome
${
USER
}
[0]!
Negative index
Keyword
${
SEQUENCE
}
[-1]
Index defined as variable
Keyword
${
SEQUENCE
}
[
${
INDEX
}
]
Sequence item access supports also the
same "slice" functionality as Python
with syntax like
${var}[1:]
. With this syntax, you do not get a single
item, but a
slice
of the original sequence. Same way as with Python, you can
specify the start index, the end index, and the step:
*** Test Cases ***
Start index
Keyword
${
SEQUENCE
}
[1:]
End index
Keyword
${
SEQUENCE
}
[:4]
Start and end
Keyword
${
SEQUENCE
}
[2:-1]
Step
Keyword
${
SEQUENCE
}
[::2]
Keyword
${
SEQUENCE
}
[1:-1:10]
Note
Prior to Robot Framework 3.2, item and slice access was only supported
with variables containing lists, tuples, or other objects considered
list-like. Nowadays all sequences, including strings and bytes, are
supported.
Accessing individual dictionary items
It is possible to access a certain value of a dictionary variable
with the syntax
${NAME}[key]
, where
key
is the name of the
selected value. Keys are considered to be strings, but non-strings
keys can be used as variables. Dictionary values accessed in this
manner can be used similarly as scalar variables.
If a dictionary is created in Robot Framework data, it is possible to access
values also using the attribute access syntax like
${NAME.key}
. See the
Creating dictionaries
section for more details about this syntax.
*** Test Cases ***
Dictionary variable item
Login
${
USER
}
[name]
${
USER
}
[password]
Title Should Be
Welcome
${
USER
}
[name]!
Key defined as variable
Log Many
${
DICT
}
[
${
KEY
}
]
${
DICT
}
[
${
42
}
]
Attribute access
Login
${
USER.name
} ${
USER.password
}
Title Should Be
Welcome
${
USER.name
}
!
Nested item access
Also nested subscriptable variables can be accessed using the same
item access syntax like
${var}[item1][item2]
. This is especially useful
when working with JSON data often returned by REST services. For example,
if a variable
${DATA}
contains
[{'id': 1, 'name': 'Robot'},
{'id': 2, 'name': 'Mr. X'}]
, this tests would pass:
*** Test Cases ***
Nested item access
Should Be Equal
${
DATA
}
[0][name]
Robot
Should Be Equal
${
DATA
}
[1][id]
${
2
}
Environment variables
Robot Framework allows using environment variables in the test data using
the syntax
%{ENV_VAR_NAME}
. They are limited to string values. It is
possible to specify a default value, that is used if the environment
variable does not exists, by separating the variable name and the default
value with an equal sign like
%{ENV_VAR_NAME=default value}
.
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.
*** Test Cases ***
Environment variables
Log
Current user:
%{
USER
}
Run
%{
JAVA_HOME
}${
/
}
javac
Environment variable with default
Set Port
%{
APPLICATION_PORT=8080
}
Note
Support for specifying the default value is new in Robot Framework 3.2.
2.6.3 Creating variables
Variables can be created using different approaches discussed in this section:
In the
Variable section
Using
variable files
On the
command line
Based on
return values from keywords
Using the
VAR syntax
Using
Set Test/Suite/Global Variable keywords
In addition to this, there are various automatically available
built-in variables
and also
user keyword arguments
and
FOR loops
create variables. In most
places where variables are created, it is possible to use
variable type conversion
to easily create variables with non-string values. An important application for
conversions is creating
secret variables
.
Variable section
The most common source for variables are Variable sections in
suite files
and
resource files
. Variable sections 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
variables cannot be created dynamically. If that is a problem,
variable files
can be used instead.
Creating scalar values
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 section 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.
*** Variables ***
${
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.
*** Variables ***
${
NAME
} =
Robot Framework
${
VERSION
} =
2.0
If a scalar variable has a long value, it can be
split into multiple rows
by using the
...
syntax. By default rows are concatenated together using
a space, but this can be changed by using a
separator
configuration
option after the last value:
*** Variables ***
${
EXAMPLE
}
This value is joined
...
together with a space.
${
MULTILINE
}
First line.
...
Second line.
...
Third line.
...
separator=\n
The
separator
option is new in Robot Framework 7.0, but also older versions
support configuring the separator. With them the first value can contain a
special
SEPARATOR
marker:
*** Variables ***
${
MULTILINE
}
SEPARATOR=\n
...
First line.
...
Second line.
...
Third line.
Both the
separator
option and the
SEPARATOR
marker are case-sensitive.
Using the
separator
option is recommended, unless there is a need to
support also older versions.
Creating lists
Creating lists is as easy as creating scalar values. Again, the
variable name is in the first column of the Variable section and
values in the subsequent columns, but this time the variable name must
start with
@
instead of
$
. A list can have any number of items,
including zero, and items can be
split into several rows
if needed.
*** Variables ***
@{
NAMES
}
Matti
Teppo
@{
NAMES2
} @{
NAMES
}
Seppo
@{
NOTHING
}
@{
MANY
}
one
two
three
four
...
five
six
seven
Note
As discussed in the
List variable syntax
section, variables
containing lists can be used as scalars like
${NAMES}
and
by using the list expansion syntax like
@{NAMES}
.
Creating dictionaries
Dictionaries can be created in the Variable section similarly as lists.
The differences are that the name must now start with
&
and that items need
to be created using the
name=value
syntax or based on existing dictionary variables.
If there are multiple items with same name, the last value has precedence.
If a name contains a literal equal sign, it can be
escaped
with a backslash like
\=
.
*** Variables ***
&{
USER 1
}
name=Matti
address=xxx
phone=123
&{
USER 2
}
name=Teppo
address=yyy
phone=456
&{
MANY
}
first=1
second=
${
2
} ${
3
}
=third
&{
EVEN MORE
} &{
MANY
}
first=override
empty=
...
=empty
key\=here=value
Note
As discussed in the
Dictionary variable syntax
section, variables
containing dictionaries can be used as scalars like
${USER 1}
and
by using the dictionary expansion syntax like
&{USER 1}
.
Unlike with normal Python dictionaries, values of dictionaries created using
this syntax can be accessed as attributes, which means that it is possible
to use
extended variable syntax
like
${VAR.key}
. This only works if the
key is a valid attribute name and does not match any normal attribute Python
dictionaries have, though. For example, individual value
${USER}[name]
can
also be accessed like
${USER.name}
, but using
${MANY.3}
is not possible.
Tip
With nested dictionaries keys are accessible like
${DATA.nested.key}
.
Dictionaries are also ordered. This means that if they are iterated,
their items always come in the order they are defined. This can be useful, for example,
if dictionaries are used as
list variables
with
FOR loops
or otherwise.
When a dictionary is used as a list variable, the actual value contains
dictionary keys. For example,
@{MANY}
variable would have a value
['first',
'second', 3]
.
Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the variable name
dynamically based on another variable:
*** Variables ***
${
X
}
Y
${${
X
}}
Z
# Name is created based on '${X}'.
*** Test Cases ***
Dynamically created name
Should Be Equal
${
Y
}
Z
Using variable files
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
.
Command line variables
Variables can be set from the command line either individually with
the
--variable (-v)
option or using the aforementioned variable files
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 section and in
variable files imported in the Setting section.
The syntax for setting individual variables is
--variable name:value
,
where
name
is the name of the variable without the
${}
decoration and
value
is its value. Several variables can be set by using this option several times.
--variable
EXAMPLE:value
--variable
HOST:localhost:7272
--variable
USER:robot
In the examples above, variables are set so that:
${EXAMPLE}
gets value
value
, and
${HOST}
and
${USER}
get values
localhost:7272
and
robot
, respectively.
The basic syntax for taking
variable files
into use from the command line is
--variablefile path/to/variables.py
and the
Taking variable files into
use
section explains this more thoroughly. 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 assigned into variables. This
allows communication between different keywords even in different libraries
by passing created variables forward as arguments to other keywords.
Variables set in this manner are otherwise similar to any other
variables, but they are available only in the
local scope
where they are created. Thus it is not possible, for example, to set
a variable like this 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 the
VAR syntax
or
Set Test/Suite/Global Variable keywords
as explained in the subsequent sections.
Assigning scalar variables
Any value returned by a keyword can be assigned to a
scalar variable
.
As illustrated by the example below, the required syntax is very simple:
*** Test Cases ***
Returning
${
x
} =
Get X
an argument
Log
We got
${
x
}
!
In the above example the value returned by the
Get X
keyword
is first set into the variable
${x}
and then used by the
Log
keyword. Having the equals sign
=
after the name of the assigned variable is
not obligatory, but it makes the assignment more explicit. Creating
local variables like this works both in test case and user keyword level.
Notice that although a value is assigned to a scalar variable, it can
be used as a
list variable
if it has a list-like value and as a
dictionary
variable
if it has a dictionary-like value.
*** Test Cases ***
List assigned to scalar variable
${
list
} =
Create List
first
second
third
Length Should Be
${
list
}
3
Log Many
@{
list
}
Assigning variable items
Starting from Robot Framework 6.1, when working with variables that support
item assignment such as lists or dictionaries, it is possible to set their values
by specifying the index or key of the item using the syntax
${var}[item]
where the
item
part can itself contain a variable:
*** Test Cases ***
List item assignment
${
list
} =
Create List
one
two
three
four
${
list
}
[0] =
Set Variable
first
${
list
}
[
${
1
}
] =
Set Variable
second
${
list
}
[2:3] =
Create List
third
${
list
}
[-1] =
Set Variable
last
Log Many
@{
list
}
# Logs 'first', 'second', 'third' and 'last'
Dictionary item assignment
${
dict
} =
Create Dictionary
first_name=unknown
${
dict
}
[first_name] =
Set Variable
John
${
dict
}
[last_name] =
Set Variable
Doe
Log
${
dictionary
}
# Logs {'first_name': 'John', 'last_name': 'Doe'}
Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the name of the assigned
variable dynamically based on another variable:
*** Test Cases ***
Dynamically created name
${
x
} =
Set Variable
y
${${
x
}} =
Set Variable
z
# Name is created based on '${x}'.
Should Be Equal
${
y
}
z
Assigning list variables
If a keyword returns a list or any list-like object, it is possible to
assign it to a
list variable
:
*** Test Cases ***
Assign to list variable
@{
list
} =
Create List
first
second
third
Length Should Be
${
list
}
3
Log Many
@{
list
}
Because all Robot Framework variables are stored in the same namespace, there is
not much difference between assigning a value to a scalar variable or a list
variable. This can be seen by comparing the above example with the earlier
example with the
List assigned to scalar variable
test case. The main
differences are that when creating a list variable, Robot Framework
automatically verifies that the value is a list or list-like, and the stored
variable value will be a new list created from the return value. When
assigning to a scalar variable, the return value is not verified and the
stored value will be the exact same object that was returned.
Assigning dictionary variables
If a keyword returns a dictionary or any dictionary-like object, it is possible
to assign it to a
dictionary variable
:
*** Test Cases ***
Assign to dictionary variable
&{
dict
} =
Create Dictionary
first=1
second=
${
2
} ${
3
}
=third
Length Should Be
${
dict
}
3
Do Something
&{
dict
}
Log
${
dict.first
}
Because all Robot Framework variables are stored in the same namespace, it would
also be possible to assign a dictionary into a scalar variable and use it
later as a dictionary when needed. There are, however, some concrete benefits
in creating a dictionary variable explicitly. First of all, Robot Framework
verifies that the returned value is a dictionary or dictionary-like similarly
as it verifies that list variables can only get a list-like value.
A bigger benefit is that the value is converted into a special dictionary
that is used also when
creating dictionaries
in the Variable section.
Values in these dictionaries can be accessed using attribute access like
${dict.first}
in the above example.
Assigning multiple variables
If a keyword returns a list or a list-like object, it is possible to assign
individual values into multiple scalar variables or into scalar variables and
a list variable.
*** Test Cases ***
Assign multiple
${
a
} ${
b
} ${
c
} =
Get Three
${
first
} @{
rest
} =
Get Three
@{
before
} ${
last
} =
Get Three
${
begin
} @{
middle
} ${
end
} =
Get Three
Assuming that the keyword
Get Three
returns a list
[1, 2, 3]
,
the following variables are created:
${a}
,
${b}
and
${c}
with values
1
,
2
, and
3
, respectively.
${first}
with value
1
, and
@{rest}
with value
[2, 3]
.
@{before}
with value
[1, 2]
and
${last}
with value
3
.
${begin}
with value
1
,
@{middle}
with value
[2]
and
${end}
with
value
3
.
It is an error if the returned list has more or less values than there are
scalar variables to assign. Additionally, only one list variable is allowed
and dictionary variables can only be assigned alone.
Automatically logging assigned variable value
To make it easier to understand what happens during execution,
the beginning of value that is assigned is automatically logged.
The default is to show 200 first characters, but this can be changed
by using the
--maxassignlength
command line option when
running tests. If the value is zero or negative, the whole assigned
value is hidden.
--maxassignlength
1000
--maxassignlength
0
The reason the value is not logged fully is that it could be really
big. If you always want to see a certain value fully, it is possible
to use the
BuiltIn
Log
keyword to log it after the assignment.
Note
The
--maxassignlength
option is new in Robot Framework 5.0.
VAR
syntax
Starting from Robot Framework 7.0, it is possible to create variables inside
tests and user keywords using the
VAR
syntax. The
VAR
marker is case-sensitive
and it must be followed by a variable name and value. Other than the mandatory
VAR
, the overall syntax is mostly the same as when creating variables
in the
Variable section
.
The new syntax aims to make creating variables simpler and more uniform. It is
especially indented to replace the
BuiltIn
keywords
Set Variable
,
Set Local Variable
,
Set Test Variable
,
Set Suite Variable
and
Set Global Variable
, but it can be used instead of
Catenate
,
Create List
and
Create Dictionary
as well.
Creating scalar variables
In simple cases scalar variables are created by just giving a variable name
and its value. The value can be a hard-coded string or it can itself contain
a variable. If the value is long, it is possible to split it into multiple
columns and rows. In that case parts are joined together with a space by default,
but the separator to use can be specified with the
separator
configuration
option. It is possible to have an optional
=
after the variable name the same
way as when creating variables based on
return values from keywords
and in
the
Variable section
.
*** Test Cases ***
Scalar examples
VAR
${
simple
}
variable
VAR
${
equals
}
=
this works too
VAR
${
variable
}
value contains
${
simple
}
VAR
${
sentence
}
This is a bit longer variable value
...
that is split into multiple rows.
...
These parts are joined with a space.
VAR
${
multiline
}
This is another longer value.
...
This time there is a custom separator.
...
As the result this becomes a multiline string.
...
separator=\n
Creating lists and dictionaries
List and dictionary variables are created similarly as scalar variables,
but the variable names must start with
@
and
&
, respectively.
When creating dictionaries, items must be specified using the
name=value
syntax.
*** Test Cases ***
List examples
VAR
@{
two items
}
Robot
Framework
VAR
@{
empty list
}
VAR
@{
lot of stuff
}
...
first item
...
second item
...
third item
...
fourth item
...
last item
Dictionary examples
VAR
&{
two items
}
name=Robot Framework
url=http://robotframework.org
VAR
&{
empty dict
}
VAR
&{
lot of stuff
}
...
first=1
...
second=2
...
third=3
...
fourth=4
...
last=5
Scope
Variables created with the
VAR
syntax are are available only within the test
or user keyword where they are created. That can, however, be altered by using
the
scope
configuration option. Supported values are:
LOCAL
Make the variable available in the current local scope. This is the default.
TEST
Make the variable available within the current test. This includes all keywords
called by the test. If used on the suite level, makes the variable available in
suite setup and teardown, but not in tests or possible child suites.
Prior to Robot Framework 7.2, using this scope on the suite level was an error.
TASK
Alias for
TEST
that can be used when
creating tasks
.
SUITE
Make the variable available within the current suite. This includes all subsequent
tests in that suite, but not tests in possible child suites.
SUITES
Make the variable available within the current suite and in its child suites.
New in Robot Framework 7.1.
GLOBAL
Make the variable available globally. This includes all subsequent keywords and tests.
Although Robot Framework variables are case-insensitive, it is recommended to
use capital letters with non-local variable names.
*** Variables ***
${
SUITE
}
this value is overridden
*** Test Cases ***
Scope example
VAR
${
local
}
local value
VAR
${
TEST
}
test value
scope=TEST
VAR
${
SUITE
}
suite value
scope=SUITE
VAR
${
SUITES
}
nested suite value
scope=SUITES
VAR
${
GLOBAL
}
global value
scope=GLOBAL
Should Be Equal
${
local
}
local value
Should Be Equal
${
TEST
}
test value
Should Be Equal
${
SUITE
}
suite value
Should Be Equal
${
SUITES
}
nested suite value
Should Be Equal
${
GLOBAL
}
global value
Keyword
Should Be Equal
${
TEST
}
new test value
Should Be Equal
${
SUITE
}
new suite value
Should Be Equal
${
SUITES
}
new nested suite value
Should Be Equal
${
GLOBAL
}
new global value
Scope example, part 2
Should Be Equal
${
SUITE
}
new suite value
Should Be Equal
${
SUITES
}
new nested suite value
Should Be Equal
${
GLOBAL
}
new global value
*** Keywords ***
Keyword
Should Be Equal
${
TEST
}
test value
Should Be Equal
${
SUITE
}
suite value
Should Be Equal
${
SUITES
}
nested suite value
Should Be Equal
${
GLOBAL
}
global value
VAR
${
TEST
}
new
${
TEST
}
scope=TEST
VAR
${
SUITE
}
new
${
SUITE
}
scope=SUITE
VAR
${
SUITES
}
new
${
SUITES
}
scope=SUITES
VAR
${
GLOBAL
}
new
${
GLOBAL
}
scope=GLOBAL
Should Be Equal
${
TEST
}
new test value
Should Be Equal
${
SUITE
}
new suite value
Should Be Equal
${
SUITES
}
new nested suite value
Should Be Equal
${
GLOBAL
}
new global value
Creating variables conditionally
The
VAR
syntax works with
IF/ELSE structures
which makes it easy to create
variables conditionally. In simple cases using
inline IF
can be convenient.
*** Test Cases ***
IF/ELSE example
IF
"
${
ENV
}
" == "devel"
VAR
${
address
}
127.0.0.1
VAR
${
name
}
demo
ELSE
VAR
${
address
}
192.168.1.42
VAR
${
name
}
robot
END
Inline IF
IF
"
${
ENV
}
" == "devel"
VAR
${
name
}
demo
ELSE
VAR
${
name
}
robot
Creating variable name based on another variable
If there is a need, variable name can also be created dynamically based on
another variable.
*** Test Cases ***
Dynamic name
VAR
${
x
}
y
# Normal assignment.
VAR
${${
x
}}
z
# Name created dynamically.
Should Be Equal
${
y
}
z
Set Test/Suite/Global Variable
keywords
Note
The
VAR
syntax is recommended over these keywords when using
Robot Framework 7.0 or newer.
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. It is an error to call
Set Test Variable
outside the scope of a test (e.g. in a Suite Setup or Teardown).
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 section
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 variables on the command line
using the
--variable
and
--variablefile
options. Because this keyword can change variables
everywhere, it should be used with care.
Note
Set Test/Suite/Global Variable
keywords set named
variables directly into
test, suite or global variable scope
and return nothing. On the other hand, another
BuiltIn
keyword
Set Variable
sets local variables using
return values
.
Variable type conversion
Variable values are typically strings, but non-string values are often needed
as well. Various ways how to create variables with non-string values has
already been discussed:
Variable files
allow creating any kind of objects.
Return values from keywords
can contain any objects.
Variables can be created based on existing variables that contain non-string values.
@{list}
and
&{dict}
syntax allows creating lists and dictionaries natively.
In addition to the above, it is possible to specify the variable type like
${name: int}
when creating variables, and the value is converted to
the specified type automatically. This is called
variable type conversion
and how it works in practice is discussed in this section.
Note
Variable type conversion is new in Robot Framework 7.3.
Variable type syntax
The general variable types syntax is
${name: type}
in the data
and
name: type:value
on the command line
. The space after the colon is mandatory
in both cases. Although variable name can in some contexts be created dynamically
based on another variable, the type and the type separator must be always specified
as literal values.
Variable type conversion supports the same base types that the
argument conversion
supports with library keywords. For example,
${number: int}
means that the value
of the variable
${number}
is converted to an integer.
Variable type conversion supports also
specifying multiple possible types
using the union syntax. For example,
${number: int | float}
means that the
value is first converted to an integer and, if that fails, then to a floating
point number.
Also
parameterized types
are supported. For example,
${numbers: list[int]}
means that the value is converted to a list of integers.
The biggest limitations compared to the argument conversion with library
keywords is that
Enum
and
TypedDict
conversions are not supported and
that custom converters cannot be used. These limitations may be lifted in
the future versions.
Note
Variable conversion is supported only when variables are created,
not when they are used.
Variable conversion in data
In the data variable conversion works when creating variables in the
Variable section
, with the
VAR syntax
and based on
return values from keywords
:
*** Variables ***
${
VERSION: float
}
7.3
${
CRITICAL: list[int]
}
[3278, 5368, 5417]
*** Test Cases ***
Variables section
Should Be Equal
${
VERSION
} ${
7.3
}
Should Be Equal
${
CRITICAL
} ${
{[3278, 5368, 5417]
}
}
VAR syntax
VAR
${
number: int
}
42
Should Be Equal
${
number
} ${
42
}
Assignment
# In simple cases the VAR syntax is more convenient.
${
number: int
} =
Set Variable
42
Should Be Equal
${
number
} ${
42
}
# In this case conversion is more useful.
${
match
} ${
version: float
} =
Should Match Regexp
RF 7.3
^RF (\\d+\\.\\d+)$
Should Be Equal
${
match
}
RF 7.3
Should Be Equal
${
version
} ${
7.3
}
Note
In addition to the above, variable type conversion works also with
user keyword arguments
and with
FOR loops
. See their documentation
for more details.
Note
Variable type conversion
does not
work with
Set Test/Suite/Global Variable
keywords
. The
VAR syntax
needs to be used instead.
Conversion with
@{list}
and
&{dict}
variables
Type conversion works also when creating
lists
and
dictionaries
using
@{list}
and
&{dict}
syntax. With lists the type is specified
like
@{name: type}
and the type is the type of the list items. With dictionaries
the type of the dictionary values can be specified like
&{name: type}
. If
there is a need to specify also the key type, it is possible to use syntax
&{name: ktype=vtype}
.
*** Variables ***
@{
NUMBERS: int
}
1
2
3
4
5
&{
DATES: date
}
rc1=2025-05-08
final=2025-05-30
&{
PRIORITIES: int=str
}
3278=Critical
4173=High
5334=High
An alternative way to create lists and dictionaries is creating
${scalar}
variables,
using
list
and
dict
types, possibly parameterizing them, and giving values as
Python list and dictionary literals:
*** Variables ***
${
NUMBERS: list[int]
}
[1, 2, 3, 4, 5]
${
DATES: list[date]
}
{'rc1': '2025-05-08', 'final': '2025-05-30'}
${
PRIORITIES: dict[int, str]
}
{3278: 'Critical', 4173: 'High', 5334: 'High'}
Using Python list and dictionary literals can be somewhat complicated especially
for non-programmers. The main benefit of this approach is that it supports also
nested structures without needing to use temporary values. The following examples
create the same
${PAYLOAD}
variable using different approaches:
*** Variables ***
@{
CHILDREN: int
}
2
13
15
&{
PAYLOAD: dict
}
id=
${
1
}
name=Robot
children=
${
CHILDREN
}
*** Variables ***
${
PAYLOAD: dict
}
{'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}
Variable conversion on command line
Variable conversion works also with the
command line variables
that are
created using the
--variable
option. The syntax is
name: type:value
and,
due to the space being mandatory, the whole option value typically needs to
be quoted. Following examples demonstrate some possible usages for this
functionality:
--variable "ITERATIONS: int:99"
--variable "PAYLOAD: dict:{'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}"
--variable "START_TIME: datetime:now"
Failing conversion
If type conversion fails, there is an error and the variable is not created.
Conversion fails if the value cannot be converted to the specified
type or if the type itself is not supported:
*** Test Cases ***
Invalid value
VAR
${
example: int
}
invalid
Invalid type
VAR
${
example: invalid
}
123
Secret variables
An important usage for
variable type conversion
is creating so called
secret variables
. These variables encapsulate their values so that the real
values are
not logged even on the trace level
when variables are passed
between keywords as arguments and return values.
The actual value is available via the
value
attribute of a secret variable.
It is mainly meant to be used by
library keywords
that accept
secret values
,
but it can be accessed also in the data using the
extended variable syntax
like
${secret.value}
. Accessing the value in the data makes it visible in the
log file similarly as if it was a normal variable, so that should only be done for
debugging or testing purposes.
Warning
Secret variables do not hide or encrypt their values. The real values
are thus available for all code that can access these variables directly
or indirectly via Robot Framework APIs.
Note
Secret variables are new in Robot Framework 7.4.
Creating secrets in data
In the data secret variables can be created in the
Variable section
and
by using the
VAR syntax
. To avoid secret values being visible to everyone who
has access to the data, it is not possible to create secret variables using
literal values. Instead the value must be created using an existing secret variable
or an
environment variable
like
%{NAME}
. In both cases joining a secret value
with a literal value like
%{SECRET}123
is allowed as well.
If showing the secret variable in the data is not an issue, it is possible to use
environment variable default values like
%{NAME=default}
. The name can even be
left empty like
%{=secret}
to always use the default value.
*** Variables ***
${
NORMAL: Secret
} ${
XXX
}
# ${XXX} must itself be a secret variable.
${
ENVIRON: Secret
} %{
EXAMPLE
}
# Environment variables are supported directly.
${
DEFAULT: Secret
} %{
=robot123
}
# Environment variable defaults work as well.
${
JOIN: Secret
} ${
XXX
}
-123
# Joining secrets with literals is ok.
${
LITERAL: Secret
}
robot123
# This fails.
Also list and dictionary variables support secret values:
*** Variables ***
@{
LIST: Secret
} ${
XXX
} %{
EXAMPLE
} %{
=robot123
} ${
XXX
}
-123
&{
DICT: Secret
}
normal=
${
XXX
}
env=
%{
EXAMPLE
}
env_default=
%{
=robot123
}
join=
${
XXX
}
-123
Note
The above examples utilize the Variable section, but the syntax to create
secret variables is exactly the same when using the
VAR syntax
.
Creating secrets on command line
Command line variable conversion
supports secret values directly:
--variable "PASSWORD: Secret:robot123"
Having the secret value directly visible on the command line history or in continuous
integration system logs can be a security risk. One way to mitigate that is using
environment variables:
--variable "PASSWORD: Secret:$PASSWORD"
Many systems running tests or tasks also support hiding secret values used on
the command line.
Creating secrets programmatically
Secrets can be created programmatically by using the
robot.api.types.Secret
class. This is most commonly done by
libraries
and
variable files
, but also
pre-run modifiers
and
listeners
can utilize secrets if needed.
The simplest possible example of the programmatic usage is a variable file:
from
robot.api.types
import
Secret
USERNAME
=
"robot"
PASSWORD
=
Secret
(
"robot123"
)
Creating a keyword returning a secret is not much more complicated either:
from
robot.api.types
import
Secret
def
get_token
():
return
Secret
(
"e5805f56-92e1-11f0-a798-8782a78eb4b5"
)
Note
Both examples above have the actual secret value visible in the code.
When working with real secret values, it is typically better to read
secrets from environment variables, get them from external systems or
generate them randomly.
2.6.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.
${/}
The system directory path separator.
/
in UNIX-like
systems and
\
in Windows.
${:}
The system path element separator.
:
in UNIX-like
systems and
;
in Windows.
${\n}
The system line separator.
\n
in UNIX-like systems
and
\r\n
in Windows.
*** Test Cases ***
Example
Create Binary File
${
CURDIR
}${
/
}
input.data
Some text here
${
\n
}
on two lines
Set Environment Variable
CLASSPATH
${
TEMPDIR
}${
:
}${
CURDIR
}${
/
}
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.
*** Test Cases ***
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
It is possible to create integers also from binary, octal, and
hexadecimal values using
0b
,
0o
and
0x
prefixes, respectively.
The syntax is case insensitive.
*** Test Cases ***
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
can
be created using the variable syntax similarly as numbers.
*** Test Cases ***
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
These variables are case-insensitive, so for example
${True}
and
${true}
are equivalent. Keywords accepting Boolean values typically do automatic
argument conversion and handle string values like
True
and
false
as
expected. In such cases using the variable syntax is not required.
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.
*** Test Cases ***
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
}
\
There is also an empty
list variable
@{EMPTY}
and an empty
dictionary
variable
&{EMPTY}
. Because they have no content, they basically
vanish when used somewhere in the test data. They are useful, for example,
with
test templates
when the
template keyword is used without
arguments
or when overriding list or dictionary variables in different
scopes. Modifying the value of
@{EMPTY}
or
&{EMPTY}
is not possible.
*** Test Cases ***
Template
[
Template
]
Some keyword
@{
EMPTY
}
Override
Set Global Variable
@{
LIST
} @{
EMPTY
}
Set Suite Variable
&{
DICT
} &{
EMPTY
}
Note
${SPACE}
represents the ASCII space (
\x20
) and
other spaces
should be specified using the
escape sequences
like
\xA0
(NO-BREAK SPACE) and
\u3000
(IDEOGRAPHIC SPACE).
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. Altering the value of
these variables does not affect the original values, but some values
can be changed dynamically using keywords from the
BuiltIn
library.
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. Can be modified dynamically using
Set Tags
and
Remove Tags
keywords.
Test case
${TEST DOCUMENTATION}
The documentation of the current test case. Can be set
dynamically using using
Set Test Documentation
keyword.
Test case
${TEST STATUS}
The status of the current test case, either PASS or
FAIL.
Test
teardown
${TEST MESSAGE}
The 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.
Everywhere
${SUITE DOCUMENTATION}
The documentation of the current test suite. Can be
set dynamically using using
Set Suite
Documentation
keyword.
Everywhere
&{SUITE METADATA}
The free metadata of the current test suite. Can be
set using
Set Suite Metadata
keyword.
Everywhere
${SUITE STATUS}
The status of the current test suite, either PASS or
FAIL.
Suite
teardown
${SUITE MESSAGE}
The full message of the current test suite, including
statistics.
Suite
teardown
${KEYWORD STATUS}
The status of the current keyword, either PASS or
FAIL.
User
keyword
teardown
${KEYWORD MESSAGE}
The possible error message of the current keyword.
User
keyword
teardown
${LOG LEVEL}
Current
log level
.
Everywhere
${OUTPUT DIR}
An absolute path to the
output directory
as
a string.
Everywhere
${OUTPUT FILE}
An absolute path to the
output file
as a string or
a string
NONE
if the output file is not created.
Everywhere
${LOG FILE}
An absolute path to the
log file
as a string or
a string
NONE
if the log file is not created.
Everywhere
${REPORT FILE}
An absolute path to the
report file
as a string or
a string
NONE
if the report file is not created.
Everywhere
${DEBUG FILE}
An absolute path to the
debug file
as a string or
a string
NONE
if the debug file is not created.
Everywhere
&{OPTIONS}
A dictionary exposing command line options. The
dictionary keys match the command line options and
can be accessed both like
${OPTIONS}[key]
and
${OPTIONS.key}
. Available options:
${OPTIONS.exclude}
(
--exclude
)
${OPTIONS.include}
(
--include
)
${OPTIONS.skip}
(
--skip
)
${OPTIONS.skip_on_failure}
(
--skip-on-failure
)
${OPTIONS.console_width}
(integer,
--console-width
)
${OPTIONS.rpa}
(boolean,
--rpa
)
${OPTIONS}
itself was added in RF 5.0,
${OPTIONS.console_width}
in RF 7.1 and
${OPTIONS.rpa}
in RF 7.3.
More options can be exposed later.
Everywhere
Suite related variables
${SUITE SOURCE}
,
${SUITE NAME}
,
${SUITE DOCUMENTATION}
and
&{SUITE METADATA}
as well as options related to command line options like
${LOG FILE}
and
&{OPTIONS}
are available already when libraries and variable
files are imported. Possible variables in these automatic variables are not yet
resolved at the import time, though.
2.6.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 on 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 sections 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 section in a test case file
Variables created using the
Variable section
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 sections are available in all other sections
in the file where they are created. This means that they can be used also
in the Setting section, 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 section 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 section of the file that imports them. This
is due to the Variable section being processed before the Setting section
where the resource files and variable files are imported.
Variables set during test execution
Variables set during the test execution using
return values from keywords
,
VAR syntax
or
Set Test/Suite/Global Variable keywords
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 section 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 local 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
by using the
VAR syntax
or the
Set Global Variable
keyword 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 sections, imported from
resource and variable files
,
or set during the test execution using the
VAR syntax
or the
Set Suite Variable
keyword.
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 with the test case scope are visible in a test case and in
all user keywords the test uses. Initially there are no variables in
this scope, but it is possible to create them by using the
VAR syntax
or
the
Set Test Variable
keyword anywhere in a test case.
If a variable with the test scope is created in suite setup, the variable is
available everywhere within that suite setup as well as in the corresponding suite
teardown, but it is not seen by tests or possible child suites. If such
a variable is created in a suite teardown, the variable is available only
in that teardown.
Also variables in the test case scope are to some extend global. It is
thus generally recommended to use capital letters with them too.
Note
Creating variables with the test scope in a suite setup or teardown
caused an error prior to Robot Framework 7.2.
Local scope
Test cases and user keywords have a local variable scope that is not
seen by other tests or keywords. Local variables can be created using
return values
from executed keywords and with the
VAR syntax
,
and user keywords also get them as
arguments
.
It is recommended to use lower-case letters with local variables.
2.6.6 Advanced variable features
Extended variable syntax
Extended variable syntax allows accessing attributes of an object assigned
to a variable (for example,
${object.attribute}
) and even calling
its methods (for example,
${obj.get_name()}
).
Extended variable syntax is a powerful feature, but it should
be used with care. Accessing attributes is normally not a problem, on
the contrary, because one variable containing an object with 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 pretty complicated to understand.
If that happens, it is recommended to move the code into a 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
eat
(
self
,
what
):
return
f
'
{
self
.
name
}
eats
{
what
}
'
def
__str__
(
self
):
return
self
.
name
OBJECT
=
MyObject
(
'Robot'
)
DICTIONARY
=
{
1
:
'one'
,
2
:
'two'
,
3
:
'three'
}
*** Test Cases ***
Example
KW 1
${
OBJECT.name
}
KW 2
${
OBJECT.eat('Cucumber')
}
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 eats Cucumber
KW 3
gets string
two
The extended variable syntax is evaluated in the following order:
The variable is searched using the full variable name. The extended
variable syntax is evaluated only if no matching variable is found.
The name of the base variable is created. The body of the name
consists of all the characters after the opening
{
until
the first occurrence of a character that is not an alphanumeric character,
an underscore or a space. For example, base variables of
${OBJECT.name}
and
${DICTIONARY[2]}
) are
OBJECT
and
DICTIONARY
, respectively.
A variable matching the base name is searched. If there is no match, an
exception is raised and the test case fails.
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.
The whole extended variable is replaced with the value returned
from the evaluation.
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.
*** Test Cases ***
String
VAR
${
string
}
abc
Log
${
string.upper()
}
# Logs 'ABC'
Log
${
string * 2
}
# Logs 'abcabc'
Number
VAR
${
number
} ${
-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.
Extended variable syntax works also in
list variable
and
dictionary variable
contexts. If, for example, an object assigned to a variable
${EXTENDED}
has
an attribute
attribute
that contains a list as a value, it can be
used as a list variable
@{EXTENDED.attribute}
.
Extended variable assignment
It is possible to set attributes of
objects stored to scalar variables using
keyword return values
and
a variation of the
extended variable syntax
. Assuming we have
variable
${OBJECT}
from the previous examples, attributes could
be set to it like in the example below.
*** Test Cases ***
Example
${
OBJECT.name
} =
Set Variable
New name
${
OBJECT.new_attr
} =
Set Variable
New attribute
The extended variable assignment syntax is evaluated using the
following rules:
The assigned variable must be a scalar variable and have at least
one dot. Otherwise the extended assignment syntax is not used and
the variable is assigned normally.
If there exists a variable with the full name
(e.g.
${OBJECT.name}
in the example above) that variable
will be assigned a new value and the extended syntax is not used.
The name of the base variable is created. The body of the name
consists of all the characters between the opening
${
and
the last dot, for example,
OBJECT
in
${OBJECT.name}
and
foo.bar
in
${foo.bar.zap}
. As the second example
illustrates, the base name may contain normal extended variable
syntax.
The name of the attribute to set is created by taking all the
characters between the last dot and the closing
}
, for
example,
name
in
${OBJECT.name}
. If the name does not
start with a letter or underscore and contain only these characters
and numbers, the attribute is considered invalid and the extended
syntax is not used. A new variable with the full name is created
instead.
A variable matching the base name is searched. If no variable is
found, the extended syntax is not used and, instead, a new variable
is created using the full variable name.
If the found variable is a string or a number, the extended syntax
is ignored and a new variable created using the full name. This is
done because you cannot add new attributes to Python strings or
numbers, and this way the syntax is also less backwards-incompatible.
If all the previous rules match, the attribute is set to the base
variable. If setting fails for any reason, an exception is raised
and the test fails.
Note
Unlike when assigning variables normally using
return
values from keywords
, changes to variables done using the
extended assign syntax are not limited to the current
scope. Because no new variable is created but instead the
state of an existing variable is changed, all tests and
keywords that see that variable will also see the changes.
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.
*** Variables ***
${
JOHN HOME
}
/home/john
${
JANE HOME
}
/home/jane
*** Test Cases ***
Example
${
name
} =
Get Name
Do X
${${
name
}
HOME
}
Inline Python evaluation
Variable syntax can also be used for evaluating Python expressions. The
basic syntax is
${{expression}}
i.e. there are double curly braces around
the expression. The
expression
can be any valid Python expression such as
${{1 + 2}}
or
${{['a', 'list']}}
. Spaces around the expression are allowed,
so also
${{ 1 + 2 }}
and
${{ ['a', 'list'] }}
are valid. In addition to
using normal
scalar variables
, also
list variables
and
dictionary variables
support
@{{expression}}
and
&{{expression}}
syntax,
respectively.
Main usages for this pretty advanced functionality are:
Evaluating Python expressions involving Robot Framework's variables
(
${{len('${var}') > 3}}
,
${{$var[0] if $var is not None else None}}
).
Creating values that are not Python base types
(
${{decimal.Decimal('0.11')}}
,
${{datetime.date(2019, 11, 5)}}
).
Creating values dynamically (
${{random.randint(0, 100)}}
,
${{datetime.date.today()}}
).
Constructing collections, especially nested collections (
${{[1, 2, 3, 4]}}
,
${{ {'id': 1, 'name': 'Example', 'children': [7, 9]} }}
).
Accessing constants and other useful attributes in Python modules
(
${{math.pi}}
,
${{platform.system()}}
).
This is somewhat similar functionality than the
extended variable syntax
discussed earlier. As the examples above illustrate, this syntax is even more
powerful as it provides access to Python built-ins like
len()
and modules
like
math
. In addition to being able to use variables like
${var}
in
the expressions (they are replaced before evaluation), variables are also
available using the special
$var
syntax during evaluation. The whole expression
syntax is explained in the
Evaluating expressions
appendix.
Tip
Instead of creating complicated expressions, it is often better
to move the logic into a
custom library
. That eases
maintenance, makes test data easier to understand and can also
enhance execution speed.
Note
The inline Python evaluation syntax is new in Robot Framework 3.2.
2.7 Creating user keywords
Keyword sections 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.7.1 User keyword syntax
Basic syntax
Settings in the Keyword section
2.7.2 User keyword name and documentation
2.7.3 User keyword tags
2.7.4 User keyword arguments
Positional arguments with user keywords
Default values with user keywords
Variable number of arguments with user keywords
Free named arguments with user keywords
Named-only arguments with user keywords
Argument conversion with user keywords
2.7.5 Embedding arguments into keyword name
Basic syntax
Embedded arguments matching wrong values
Resolving conflicts
Using custom regular expressions
Argument conversion with embedded arguments
Behavior-driven development example
2.7.6 User keyword return values
Using
RETURN
statement
Using
[Return]
setting
Using special keywords to return
2.7.7 User keyword setup and teardown
2.7.8 Private user keywords
2.7.9 Recursion
2.7.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 sections
which differ from Test Case sections 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.
*** Keywords ***
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
suite files
,
resource files
,
and
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 section
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
.
[Tags]
Sets
tags
for the keyword.
[Arguments]
Specifies
user keyword arguments
.
[Setup]
,
[Teardown]
Specify
user keyword setup and teardown
.
[Setup]
is new in
Robot Framework 7.0.
[Timeout]
Sets the possible
user keyword timeout
.
Timeouts
are discussed
in a section of their own.
[Return]
Specifies
user keyword return values
. Deprecated in Robot Framework 7.0,
the
RETURN
statement should be used instead.
Note
The format used above is recommended, but setting names are
case-insensitive and spaces are allowed between brackets and the name.
For example,
[ TAGS ]
:setting is valid.
2.7.2 User keyword name and documentation
The user keyword name is defined in the first column of the
Keyword section. 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. It supports same formatting,
splitting to multiple lines, and other features 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
tool can create
from
resource files
. Finally, the first logical row of the documentation,
until the first empty row, is shown as a keyword documentation in
test logs
.
*** Keywords ***
One line documentation
[
Documentation
]
One line documentation.
No Operation
Multiline documentation
[
Documentation
]
The first line creates the short doc.
...
...
This is the body of the documentation.
...
It is not shown in Libdoc outputs but only
...
the short doc is shown in logs.
No Operation
Short documentation in multiple lines
[
Documentation
]
If the short doc gets longer, it can span
...
multiple physical lines.
...
...
The body is separated from the short doc with
...
an empty line.
No Operation
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 keyword is used. For more information, see
the
Deprecating keywords
section.
Note
Prior to Robot Framework 3.1, the short documentation contained
only the first physical line of the keyword documentation.
2.7.4 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 with user keywords
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
be as descriptive as possible. It is recommended
to use lower-case letters in variable names, either as
${my_arg}
,
${my arg}
or
${myArg}
.
*** Keywords ***
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 with user keywords
When creating user keywords, positional arguments are sufficient in
most situations. It is, however, sometimes useful that keywords have
default values
for some or all of their arguments. Also user keywords
support default values, 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. The default value can contain a
variable
created on
test, suite or global scope
, but local variables of the keyword
executor cannot be used. Default value can
also be defined based on earlier arguments accepted by the keyword.
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.
*** Keywords ***
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
}
=
${
VARIABLE
}
[
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
}
Default Based On Earlier Argument
[
Arguments
] ${
a
} ${
b
}
=
${
a
} ${
c
}
=
${
a
}
and
${
b
}
Should Be Equal
${
a
} ${
b
}
Should Be Equal
${
c
} ${
a
}
and
${
b
}
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.
*** Test Cases ***
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 with user keywords
Sometimes even default values are not enough and there is a need
for a keyword accepting
variable number of arguments
. User keywords
support also this feature. All that is needed is having
list variable
such
as
@{varargs}
after possible positional arguments in the keyword signature.
This syntax can be combined with the previously described 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.
*** Keywords ***
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
}
END
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.
The keywords in the examples above could be used, for example, like this:
*** Test Cases ***
Varargs with user keywords
Any Number Of Arguments
Any Number Of Arguments
arg
Any Number Of Arguments
arg1
arg2
arg3
arg4
One Or More Arguments
required
One Or More Arguments
arg1
arg2
arg3
arg4
Required, Default, Varargs
required
Required, Default, Varargs
required
optional
Required, Default, Varargs
arg1
arg2
arg3
arg4
arg5
Again, Pythonistas probably notice that the variable number of
arguments syntax is very close to the one in Python.
Free named arguments with user keywords
User keywords can also accept
free named arguments
by having a
dictionary
variable
like
&{named}
as the absolutely last argument. When the keyword
is called, this variable will get all
named arguments
that do not match
any
positional argument
or
named-only argument
in the keyword
signature.
*** Keywords ***
Free Named Only
[
Arguments
] &{
named
}
Log Many
&{
named
}
Positional And Free Named
[
Arguments
] ${
required
} &{
extra
}
Log Many
${
required
} &{
extra
}
Run Program
[
Arguments
] @{
args
} &{
config
}
Run Process
program.py
@{
args
} &{
config
}
The last example above shows how to create a wrapper keyword that
accepts any positional or named argument and passes them forward.
See
free named argument examples
for a full example with same keyword.
Free named arguments support with user keywords works similarly as kwargs
work in Python. In the signature and also when passing arguments forward,
&{kwargs}
is pretty much the same as Python's
**kwargs
.
Named-only arguments with user keywords
User keywords support
named-only arguments
that are inspired by Python's
keyword-only arguments
.
This syntax is typically used by having normal arguments
after
variable number of arguments
(
@{varargs}
). If the keywords does not
use varargs, it is possible to use just
@{}
to denote that the subsequent
arguments are named-only:
*** Keywords ***
With Varargs
[
Arguments
] @{
varargs
} ${
named
}
Log Many
@{
varargs
} ${
named
}
Without Varargs
[
Arguments
] @{} ${
first
} ${
second
}
Log Many
${
first
} ${
second
}
Named-only arguments can be used together with
positional arguments
as
well as with
free named arguments
. When using free named arguments, they
must be last:
*** Keywords ***
With Positional
[
Arguments
] ${
positional
} @{} ${
named
}
Log Many
${
positional
} ${
named
}
With Free Named
[
Arguments
] @{
varargs
} ${
named only
} &{
free named
}
Log Many
@{
varargs
} ${
named only
} &{
free named
}
When passing named-only arguments to keywords, their order does not matter
other than they must follow possible positional arguments. The keywords above
could be used, for example, like this:
*** Test Cases ***
Example
With Varargs
named=value
With Varargs
positional
second positional
named=foobar
Without Varargs
first=1
second=2
Without Varargs
second=toka
first=eka
With Positional
foo
named=bar
With Positional
named=2
positional=1
With Free Named
positional
named only=value
x=1
y=2
With Free Named
foo=a
bar=b
named only=c
quux=d
Named-only arguments can have default values similarly as
normal user
keyword arguments
. A minor difference is that the order of arguments
with and without default values is not important.
*** Keywords ***
With Default
[
Arguments
] @{} ${
named
}
=default
Log Many
${
named
}
With And Without Defaults
[
Arguments
] @{} ${
optional
}
=default
${
mandatory
} ${
mandatory 2
} ${
optional 2
}
=default 2
${
mandatory 3
}
Log Many
${
optional
} ${
mandatory
} ${
mandatory 2
} ${
optional 2
} ${
mandatory 3
}
Argument conversion with user keywords
User keywords support automatic argument conversion based on explicitly specified
types. The type syntax
${name: type}
is the same, and the supported conversions
are the same, as when
creating variables
.
The basic usage with normal arguments is very simple. You only need to specify
the type like
${count: int}
and the used value is converted automatically.
If an argument has a default value like
${count: int}=1
, also the default
value will be converted. If conversion fails, calling the keyword fails with
an informative error message.
*** Test Cases ***
Move around
Move
3
Turn
LEFT
Move
2.3
log=True
Turn
right
Failing move
Move
bad
Failing turn
Turn
oops
*** Keywords ***
Move
[
Arguments
] ${
distance: float
} ${
log: bool
}
=False
IF
${
log
}
Log
Moving
${
distance
}
meters.
END
Turn
[
Arguments
] ${
direction: Literal["LEFT", "RIGHT"]
}
Log
Turning
${
direction
}
.
Tip
Using
Literal
, like in the above example, is a convenient way to
limit what values are accepted.
When using
variable number of arguments
, the type is specified like
@{numbers: int}
and is applied to all arguments. If arguments may have
different types, it is possible to use an union like
@{numbers: float | int}
.
With
free named arguments
the type is specified like
&{named: int}
and
it is applied to all argument values. Converting argument names is not supported.
*** Test Cases ***
Varargs
Send bytes
Hello!
Hyvä!
\x00\x00\x07
Free named
Log releases
rc 1=2025-05-08
rc 2=2025-05-19
rc 3=2025-05-21
final=2025-05-30
*** Keywords ***
Send bytes
[
Arguments
] @{
data: bytes
}
FOR
${
value
}
IN
@{
data
}
Log
${
value
}
formatter=repr
END
Log releases
[
Arguments
] &{
releases: date
}
FOR
${
version
} ${
date
}
IN
&{
releases
}
Log
RF 7.3
${
version
}
was released on
${
date.day
}
.
${
date.month
}
.
${
date.year
}
.
END
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
2.7.5 Embedding arguments into keyword name
The previous section explained how to pass arguments to keywords so
that they are listed separately after the keyword name. Robot
Framework has also another approach to pass arguments, embedding them
directly to the keyword name, used by the second test below:
*** Test Cases ***
Normal arguments
Select from list
cat
Embedded arguments
Select cat from list
As the example illustrates, embedding arguments to keyword names
can make the data easier to read and understand even for people without
any Robot Framework experience.
Basic syntax
The previous example showed how using a keyword
Select cat from list
is
more fluent than using
Select from list
so that
cat
is passed to
it as an argument. We obviously could implement
Select cat from list
as a normal keyword accepting no arguments, but then we needed to implement
various other keywords like
Select dog from list
for other animals.
Embedded arguments simplify this and we can instead implement just one
keyword with name
Select ${animal} from list
and use it with any
animal:
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
*** Keywords ***
Select
${
animal
}
from list
Open Page
Pet Selection
Select Item From List
animal_list
${
animal
}
As the above example shows, embedded arguments are specified simply by using
variables in keyword names. The arguments used in the name are naturally
available inside the keyword and they have different values depending on how
the keyword is called. In the above example,
${animal}
has value
cat
when
the keyword is used for the first time and
dog
when it is used for
the second time.
Starting from Robot Framework 6.1, it is possible to create user keywords
that accept both embedded and "normal" arguments:
*** Test Cases ***
Embedded and normal arguments
Number of cats should be
2
Number of dogs should be
count=3
*** Keywords ***
Number of
${
animals
}
should be
[
Arguments
] ${
count
}
Open Page
Pet Selection
Select Items From List
animal_list
${
animals
}
Number of Selected List Items Should Be
${
count
}
Other than the special name, keywords with embedded
arguments are created just like other user keywords. They are also used the same
way as other keywords except that spaces and underscores are not ignored in their
names when keywords are matched. They are, however, case-insensitive like
other keywords. For example, the
Select ${animal} from list
keyword could
be used like
select cow from list
, but not like
Select cow fromlist
.
Embedded arguments do not support default values or variable number of
arguments like normal arguments do. If such functionality is needed, normal
arguments should be used instead. Passing embedded arguments as variables
is possible, but that can reduce readability:
*** Variables ***
${
SELECT
}
cat
*** Test Cases ***
Embedded arguments with variable
Select
${
SELECT
}
from list
*** Keywords ***
Select
${
animal
}
from list
Open Page
Pet Selection
Select Item From List
animal_list
${
animal
}
Embedded arguments matching wrong values
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,
Select Los Angeles Lakers
in the following example matches
Select ${city} ${team}
so that
${city}
contains
Los
and
${team}
contains
Angeles Lakers
:
*** Test Cases ***
Example
Select Chicago Bulls
Select Los Angeles Lakers
*** Keywords ***
Select
${
city
}
${
team
}
Log
Selected
${
team
}
from
${
city
}
.
An easy solution to this problem is surrounding arguments with double quotes or
other characters not used in the actual values. This fixed example works so
that cities and teams match correctly:
*** Test Cases ***
Example
Select "Chicago" "Bulls"
Select "Los Angeles" "Lakers"
*** Keywords ***
Select "
${
city
}
" "
${
team
}
"
Log
Selected
${
team
}
from
${
city
}
.
This approach is not enough to resolve all conflicts, but it helps in common
cases and is generally recommended. Another benefit is that it makes arguments
stand out from rest of the keyword.
Prior to Robot Framework 7.1, embedded arguments starting the keyword name also
matched possible
given/when/then/and/but prefixes
typically used in Behavior
Driven Development (BDD). For example,
${name} goes home
matched
Given Janne goes home
so that
${name}
got value
Given Janne
.
Nowadays the prefix is ignored and
${name}
will be
Janne
as expected.
If older Robot Framework versions need to be supported, it is easiest to quote
the argument like in
"${name}" goes home
to get consistent behavior.
An alternative solution for limiting what values arguments match is
using custom regular expressions
.
Resolving conflicts
When using embedded arguments, it is pretty common that there are multiple
keyword implementations that match the keyword that is used. For example,
Execute "ls" with "lf"
in the example below matches both of the keywords.
It matching
Execute "${cmd}" with "${opts}"
is pretty obvious and what
we want, but it also matches
Execute "${cmd}"
so that
${cmd}
matches
ls" with "-lh
.
*** Settings ***
Library
Process
*** Test Cases ***
Automatic conflict resolution
Execute "ls"
Execute "ls" with "-lh"
*** Keywords ***
Execute "
${
cmd
}
"
Run Process
${
cmd
}
shell=True
Execute "
${
cmd
}
" with "
${
opts
}
"
Run Process
${
cmd
}
${
opts
}
shell=True
When this kind of conflicts occur, Robot Framework tries to automatically select
the best match and use that. In the above example,
Execute "${cmd}" with "${opts}"
is considered a better match than the more generic
Execute "${cmd}"
and
running the example thus succeeds without conflicts.
It is not always possible to find a single match that is better than others.
For example, the second test below fails because
Robot Framework
matches
both of the keywords equally well. This kind of conflicts need to be resolved
manually either by renaming keywords or by
using custom regular expressions
.
*** Test Cases ***
No conflict
Automation framework
Robot uprising
Unresolvable conflict
Robot Framework
*** Keywords ***
${
type
}
Framework
Should Be Equal
${
type
}
Automation
Robot
${
action
}
Should Be Equal
${
action
}
uprising
Keywords that accept only "normal" arguments or no arguments at all are
considered to match better than keywords accepting embedded arguments.
For example, if the following keyword is added to the above example,
Robot Framework
used by the latter test matches it and the test
succeeds:
*** Keywords ***
Robot Framework
No Operation
Before looking which match is best, Robot Framework checks are some of the matching
keywords implemented in the same file as the caller keyword. If there are such keywords,
they are given precedence over other keywords. Alternatively,
library search order
can be used to control the order in which Robot Framework looks for keywords in resources
and libraries.
Note
Automatically resolving conflicts if multiple keywords with embedded
arguments match is a new feature in Robot Framework 6.0. With older
versions custom regular expressions explained below can be used instead.
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 matches any string and tries to match as little as possible. This logic works
fairly well normally, but as discussed above, sometimes keywords
match wrong values
and sometimes there are
conflicts that cannot
be resolved
. A solution in these cases is specifying 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+}
.
If needed, custom patterns can be prefixed with
inline flags
such as
(?i)
for case-insensitivity.
Using custom regular expressions is illustrated by the following examples.
The first one shows how the earlier problem with
Select ${city} ${team}
not matching
Select Los Angeles Lakers
properly can be resolved without
quoting by implementing the keyword so that
${team}
can only contain non-whitespace
characters.
*** Test Cases ***
Do not match whitespace characters
Select Chicago Bulls
Select Los Angeles Lakers
Match numbers and characters from set
1 + 2 = 3
53 - 11 = 42
Match either date or literal 'today'
Deadline is 2022-09-21
Deadline is today
Case-insensitive match
Select dog
Select CAT
*** Keywords ***
Select
${
city
}
${
team:\S+
}
Log
Selected
${
team
}
from
${
city
}
.
${
number1:\d+
}
${
operator:[+-]
}
${
number2:\d+
}
=
${
expected:\d+
}
${
result
} =
Evaluate
${
number1
}
${
operator
}
${
number2
}
Should Be Equal As Integers
${
result
} ${
expected
}
Deadline is
${
deadline: date:\d{4
}
-\d{2}-\d{2}|today}
# The ': date' part of the above argument specifies the argument type.
# See the separate section about argument conversion for more information.
Log
Deadline is
${
deadline.day
}
.
${
deadline.month
}
.
${
deadline.year
}
.
Select
${
animal:(?i)cat|dog
}
[
Documentation
]
Inline flag `(?i)` makes the pattern case-insensitive.
Log
Selected
${
animal
}
!
Note
Support for inline flags is new in Robot Framework 7.2.
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. If the regular
expression syntax is invalid, creating the keyword fails with an error
visible in
test execution errors
.
Escaping special characters
Regular expressions use the backslash character (
\
) heavily both
to form special sequences (e.g.
\d
) and to escape characters that have
a special meaning in regexps (e.g.
\$
). Typically in Robot Framework data
backslash characters
need to be escaped
with another backslash, but
that is not required in this context. If there is a need to have a literal
backslash in the pattern, then the backslash must be escaped like
${path:c:\\temp\\.*}
.
Possible lone opening and closing curly braces in the pattern must be escaped
like
${open:\{}
and
${close:\}}
or otherwise Robot Framework is not able
to parse the variable syntax correctly. If there are matching braces like in
${digits:\d{2}}
, escaping is not needed.
Note
Prior to Robot Framework 3.2, it was mandatory to escape all
closing curly braces in the pattern like
${digits:\d{2\}}
.
This syntax is unfortunately not supported by Robot Framework 3.2
or newer and keywords using it must be updated when upgrading.
Note
Prior to Robot Framework 6.0, using literal backslashes in the pattern
required double escaping them like
${path:c:\\\\temp\\\\.*}
.
Patterns using literal backslashes need to be updated when upgrading.
Using variables with custom embedded argument regular expressions
When using embedded arguments with custom regular expressions, specifying
values using variables works only if variables match the whole embedded
argument, not if there is any additional content with the variable.
For example, the first test below succeeds because the variable
${DATE}
is used on its own, but the last test fails because
${YEAR}-${MONTH}-${DAY}
is not a single variable.
*** Variables ***
${
DATE
}
2011-06-27
${
YEAR
}
2011
${
MONTH
}
06
${
DAY
}
27
*** Test Cases ***
Succeeds
Deadline is
${
DATE
}
Succeeds without variables
Deadline is 2011-06-27
Fails
Deadline is
${
YEAR
}
-
${
MONTH
}
-
${
DAY
}
*** Keywords ***
Deadline is
${
deadline:\d{4
}
-\d{2}-\d{2}}
Should Be Equal
${
deadline
}
2011-06-27
Another limitation of using variables is that their actual values are not matched
against custom regular expressions. As the result keywords may be called with
values that their custom regexps would not allow. This behavior is deprecated
starting from Robot Framework 6.0 and values will be validated in the future.
For more information see issue
#4462
.
Argument conversion with embedded arguments
User keywords accepting embedded arguments support argument conversion with type
syntax
${name: type}
similarly as
normal user keywords
. If a
custom pattern
is needed, it can be separated with an additional colon like
${name: type:pattern}
.
*** Test Cases ***
Example
Buy 3 books
Deadline is 2025-05-30
*** Keywords ***
Buy
${
quantity: int
}
books
Should Be Equal
${
quantity
} ${
3
}
Deadline is
${
deadline: date:\d{4
}
-\d{2}-\d{2}}
Should Be Equal
${
deadline.year
} ${
2025
}
Should Be Equal
${
deadline.month
} ${
5
}
Should Be Equal
${
deadline.day
} ${
30
}
Because the type separator is a colon followed by a space (e.g.
${arg: int}
)
and the pattern separator is just a colon (e.g.
${arg:\d+}
), there typically
are no conflicts when using only a type or only a pattern. The only exception
is using a pattern starting with a space, but in that case the space can be
escaped like
${arg:\ abc}
or a type added like
${arg: str: abc}
.
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
Behavior-driven development example
A big benefit of having arguments as part of the keyword name is that it
makes it easier to use higher-level sentence-like keywords when using the
behavior-driven style
to write tests. As the example below shows, this
support is typically used in combination with the possibility to
omit Given, When and Then prefixes
in keyword definitions:
*** Test Cases ***
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
*** Keywords ***
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 the popular BDD tool
Cucumber
.
2.7.6 User keyword return values
Similarly as library keywords, also user keywords can return values.
When using Robot Framework 5.0 or newer, the recommended approach is
using the native
RETURN
statement. The old
[Return]
setting was deprecated in Robot Framework 7.0 and also
BuiltIn
keywords
Return From Keyword
and
Return From Keyword If
are considered
deprecated.
Regardless how values are returned, they can be
assigned to variables
in test cases and in other user keywords.
Using
RETURN
statement
The recommended approach to return values is using the
RETURN
statement.
It accepts optional return values and can be used with
IF
and
inline IF
structures. Its usage is easiest explained with examples:
*** Keywords ***
Return One Value
[
Arguments
] ${
arg
}
[
Documentation
]
Return a value unconditionally.
...
Notice that keywords after RETURN are not executed.
${
value
} =
Convert To Upper Case
${
arg
}
RETURN
${
value
}
Fail
Not executed
Return Three Values
[
Documentation
]
Return multiple values.
RETURN
a
b
c
Conditional Return
[
Arguments
] ${
arg
}
[
Documentation
]
Return conditionally.
Log
Before
IF
${
arg
}
== 1
Log
Returning!
RETURN
END
Log
After
Find Index
[
Arguments
] ${
test
} ${
items
}
[
Documentation
]
Advanced example involving FOR loop, inline IF and
@{
list
}
variable syntax.
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
items
}
IF
$item == $test
RETURN
${
index
}
END
RETURN
${
-1
}
If you want to test the above examples yourself, you can use them with these test cases:
*** Settings ***
Library
String
*** Test Cases ***
One return value
${
ret
} =
Return One Value
argument
Should Be Equal
${
ret
}
ARGUMENT
Multiple return values
${
a
} ${
b
} ${
c
} =
Return Three Values
Should Be Equal
${
a
}
,
${
b
}
,
${
c
}
a, b, c
Conditional return
Conditional Return
1
Conditional Return
2
Advanced
@{
list
} =
Create List
foo
bar
baz
${
index
} =
Find Index
bar
${
list
}
Should Be Equal
${
index
} ${
1
}
${
index
} =
Find Index
non existing
${
list
}
Should Be Equal
${
index
} ${
-1
}
Note
RETURN
syntax is case-sensitive similarly as
IF
and
FOR
.
Note
RETURN
is new in Robot Framework 5.0. Use approaches explained
below if you need to support older versions.
Using
[Return]
setting
The
[Return]
setting defines what the keyword should return after
it has been executed. Although it is recommended to have it at the end of keyword
where it logically belongs, its position does not affect how it is used.
An inherent limitation of the
[Return]
setting is that cannot be used
conditionally. Thus only the first two earlier
RETURN
statement examples
can be created using it.
*** Keywords ***
Return One Value
[
Arguments
] ${
arg
}
${
value
} =
Convert To Upper Case
${
arg
}
[
Return
] ${
value
}
Return Three Values
[
Return
]
a
b
c
Note
The
[Return]
setting was deprecated in Robot Framework 7.0
and the
RETURN
statement should be used instead. If there is a need
to support older Robot Framework versions that do not support
RETURN
,
it is possible to use the special keywords discussed in the next section.
Using special keywords to return
BuiltIn
keywords
Return From Keyword
and
Return From Keyword If
allow returning from a user keyword conditionally in the middle of the keyword.
Both of them also accept optional return values that are handled exactly like
with the
RETURN
statement and the
[Return]
setting discussed above.
The introduction of the
RETURN
statement makes these keywords redundant.
Examples below contain same keywords as earlier
RETURN
examples but these
ones are more verbose:
*** Keywords ***
Return One Value
[
Arguments
] ${
arg
}
${
value
} =
Convert To Upper Case
${
arg
}
Return From Keyword
${
value
}
Fail
Not executed
Return Three Values
Return From Keyword
a
b
c
Conditional Return
[
Arguments
] ${
arg
}
Log
Before
IF
${
arg
}
== 1
Log
Returning!
Return From Keyword
END
Log
After
Find Index
[
Arguments
] ${
test
} ${
items
}
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
items
}
Return From Keyword If
$item == $test
${
index
}
END
Return From Keyword
${
-1
}
Note
These keywords are effectively deprecated and the
RETURN
statement should be
used unless there is a need to support also older versions than Robot Framework
5.0. There is no visible deprecation warning when using these keywords yet, but
they will be loudly deprecated and eventually removed in the future.
2.7.7 User keyword setup and teardown
A user keyword can have a setup and a teardown similarly as
tests
.
They are specified using
[Setup]
and
[Teardown]
settings, respectively, directly to the keyword having them. Unlike with
tests, it is not possible to specify a common setup or teardown to all
keywords in a certain file.
A setup and a teardown are always a single keyword, but they can themselves be
user keywords executing multiple keywords internally. It is possible to specify
them as variables, and using a special
NONE
value (case-insensitive) is
the same as not having a setup or a teardown at all.
User keyword setup is not much different to the first keyword inside the created
user keyword. The only functional difference is that a setup can be specified as
a variable, but it can also be useful to be able to explicitly mark a keyword
to be a setup.
User keyword teardowns are, exactly as test teardowns, executed also if the user
keyword fails. They are thus very useful when needing to do something at the
end of the keyword regardless of its status. To ensure that all cleanup activities
are done, the
continue on failure
mode is enabled by default with user keyword
teardowns the same way as with test teardowns.
*** Keywords ***
Setup and teardown
[
Setup
]
Log
New in RF 7!
Do Something
[
Teardown
]
Log
Old feature.
Using variables
[
Setup
] ${
SETUP
}
Do Something
[
Teardown
] ${
TEARDOWN
}
Note
User keyword setups are new in Robot Framework 7.0.
2.7.8 Private user keywords
User keywords can be
tagged
with a special
robot:private
tag to indicate
that they should only be used in the file where they are created:
*** Keywords ***
Public Keyword
Private Keyword
Private Keyword
[
Tags
]
robot:private
No Operation
Using the
robot:private
tag does not outright prevent using the keyword
outside the file where it is created, but such usages will cause a warning.
If there is both a public and a private keyword with the same name,
the public one will be used but also this situation causes a warning.
Private keywords are included in spec files created by
Libdoc
but not in its
HTML output files.
Note
Private user keywords are new in Robot Framework 6.0.
2.7.9 Recursion
User keywords can call themselves either directly or indirectly. This kind of
recursive usage is fine as long as the recursion ends, typically based on some
condition, before the recursion limit is exceeded. The limit exists because
otherwise infinite recursion would crash the execution.
Robot Framework's recursion detection works so, that it checks is the current
recursion level close to the recursion limit of the underlying Python process.
If it is close enough, no more new started keywords or control structures are
allowed and execution fails.
Python's default recursion limit is 1000 stack frames, which in practice means that
it is possible to start approximately 140 keywords or control structures.
If that is not enough, Python's recursion limit can be raised using the
sys.setrecursionlimit()
function. As the documentation of the function explains,
this should be done with care, because a too-high level can lead to a crash.
Note
Prior to Robot Framework 7.2, the recursion limit was hard-coded to
100 started keywords or control structures.
2.8 Resource and variable files
User keywords and variables in
suite files
and
suite
initialization files
can only be used in files where they are
created, but
resource files
provide a mechanism for sharing them.
The high level syntax for creating resource files is exactly the same
as when creating suite files and
supported file formats
are the same
as well. The main difference is that resource files cannot have tests.
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 or YAML, which
also makes them somewhat more complicated than
Variable sections
.
2.8.1 Resource files
Taking resource files into use
Resource file structure
Documenting resource files
Example resource file
Resource files using reStructured text format
Resource files using JSON format
2.8.2 Variable files
Taking variable files into use
Getting variables directly from a module
Getting variables from a special function
Implementing variable file as a class
Variable file as YAML
Variable file as JSON
2.8.1 Resource files
Resource files are typically created using the plain text format, but also
reStructuredText format
and
JSON format
are supported.
Taking resource files into use
Resource files are imported using the
Resource
setting in the
Settings section so that the path to the resource file is given as an argument
to the setting. The recommended extension for resource files is
.resource
.
For backwards compatibility reasons also
.robot
,
.txt
and
.tsv
work, but using
.resource
may be mandated in the future.
If the resource file path is absolute, it is used directly. Otherwise,
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 Python's
module search path
.
Searching resource files from the module search path makes it possible to
bundle them into Python packages as
package data
and importing
them like
package/example.resource
.
The resource file path can contain variables, and it is recommended to use
them to make paths system-independent (for example,
${RESOURCES}/login.resource
or just
${RESOURCE_PATH}
).
Additionally, forward slashes (
/
) in the path
are automatically changed to backslashes (
\
) on Windows.
*** Settings ***
Resource
example.resource
Resource
../resources/login.resource
Resource
package/example.resource
Resource
${
RESOURCES
}
/common.resource
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.
Note
The
.resource
extension is new in Robot Framework 3.1.
Resource file structure
The higher-level structure of resource files is the same as that of
suite files otherwise, but they cannot contain tests or tasks.
Additionally, the Setting section in resource files can contain only imports
(
Library
,
Resource
,
Variables
),
Documentation
and
Keyword Tags
.
The Variable section and Keyword section are used exactly the same way
as in suite 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. The resource file itself can have
Documentation
in the Setting section similarly as
suites
.
Libdoc
and various editors use these documentations, and they
are naturally available for anyone opening resource files. The
first logical line of the documentation of a keyword, until the first
empty line, is logged when the keyword is run, but otherwise resource
file documentation is ignored during the test execution.
Example resource file
*** Settings ***
Documentation
An example resource file
Library
SeleniumLibrary
Resource
${
RESOURCES
}
/common.resource
*** Variables ***
${
HOST
}
localhost:7272
${
LOGIN URL
}
http://
${
HOST
}
/
${
WELCOME URL
}
http://
${
HOST
}
/welcome.html
${
BROWSER
}
Firefox
*** Keywords ***
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
}
Resource files using reStructured text format
The
reStructuredText format
that can be used with
suite files
works
also with resource files. Such resource files can use either
.rst
or
.rest
extension and they are otherwise imported exactly as
normal resource files:
*** Settings ***
Resource
example.rst
When parsing resource files using the reStructuredText format, Robot Framework
ignores all data outside code blocks containing Robot Framework data exactly
the same way as when parsing
reStructuredText suite files
.
For example, the following resource file imports
OperatingSystem
library,
defines
${MESSAGE}
variable and creates
My Keyword
keyword:
Resource file using reStructuredText
------------------------------------
This text is outside code blocks and thus ignored.
..
code
::
robotframework
*** Settings ***
Library
OperatingSystem
*** Variables ***
${
MESSAGE
}
Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
..
code
::
robotframework
# Both space and pipe separated formats are supported.
|
*** Keywords ***
| | |
|
My Keyword
| [
Arguments
] | ${
path
} |
| |
Directory Should Exist
| ${
path
} |
Resource files using JSON format
Resource files can be created using
JSON
the
same way as suite files
.
Such JSON resource files must use either the standard
.json
extension
or the custom
.rsrc
extension. They are otherwise imported exactly as
normal resource files:
*** Settings ***
Resource
example.rsrc
Resource files can be converted to JSON using
ResourceFile.to_json
and
recreated using
ResourceFile.from_json
:
from
robot.running
import
ResourceFile
# Create resource file based on data on the file system.
resource
=
ResourceFile
.
from_file_system
(
'example.resource'
)
# Save JSON data to a file.
resource
.
to_json
(
'example.rsrc'
)
# Recreate resource from JSON data.
resource
=
ResourceFile
.
from_json
(
'example.rsrc'
)
2.8.2 Variable files
Variable files contain
variables
that can be used in the test
data. Variables can also be created using
Variable sections
or
set from
the command line
, but variable files allow creating them dynamically
and also make it easy to create other variable values than strings.
Variable files are typically implemented as modules and there are
two different approaches for creating variables:
Getting variables directly from a module
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 its value. One limitation of this approach is that it does
not allow using arguments.
Getting variables from a special function
Variable files can have a special
get_variables
(or
getVariables
) method that returns variables as a mapping.
Because the method can take arguments this approach is very flexible.
Alternatively variable files can be implemented as
classes
that the framework will instantiate. Also in this case it is possible to create
variables as attributes or get them dynamically from the
get_variables
method. Variable files can also be created as
YAML
and
JSON
.
Taking variable files into use
Setting section
All test data files can import variable files using the
Variables
setting in the Setting section. Variable files are typically imported using
a path to the file 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 directories
in the
module search path
. The path can also contain variables,
and slashes are converted to backslashes on Windows.
Examples:
*** Settings ***
Variables
myvariables.py
Variables
../data/variables.py
Variables
${
RESOURCES
}
/common.yaml
Starting from Robot Framework 5.0, variable files implemented using Python
can also be imported using the module name
similarly as libraries
.
When using this approach, the module needs to be in the
module search path
.
Examples:
*** Settings ***
Variables
myvariables
Variables
rootmodule.Variables
If a
variable file accepts arguments
, they are specified after the path
or name of the variable file to import:
*** Settings ***
Variables
arguments.py
arg1
${
ARG2
}
Variables
arguments
argument
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 sections 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 or
module name similarly as when importing them using the
Variables
setting. Possible arguments are joined to the path with a colon (
:
):
--variablefile myvariables.py
--variablefile path/variables.py
--variablefile /absolute/path/common.py
--variablefile variablemodule
--variablefile arguments.py:arg1:arg2
--variablefile rootmodule.Variables:arg1:arg2
Variable files taken into use from the
command line are also searched from the
module search path
similarly as
variable files imported in the Setting section. Relative paths are considered
relative to the directory where execution is started from.
If a variable file is given as an absolute Windows path, the colon after the
drive letter is not considered a separator:
--variablefile C:\path\variables.py
It is also possible to use a semicolon
(
;
) as an argument separator. This is useful if variable file arguments
themselves contain colons, but requires surrounding the whole value with
quotes on UNIX-like operating systems:
--variablefile C:\path\variables.py;D:\data.xls
--variablefile "myvariables.py;argument:with:colons"
Variables in variable files taken use on the command line 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.
Getting variables directly from a module
Basic syntax
When variable files are taken into use, they are imported as Python
modules and all their module level attributes that do not start with
an underscore (
_
) are, by default, 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
]
MAPPING
=
{
"one"
:
1
,
"two"
:
2
,
"three"
:
3
}
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, then there are two lists, and the final value is a dictionary.
All these variables can be used as a
scalar variable
, lists and the
dictionary also a
list variable
like
@{STRINGS}
(in the dictionary's case
that variable would only contain keys), and the dictionary also as a
dictionary variable
like
&{MAPPING}
.
To make creating a list variable or a dictionary variable more explicit,
it is possible to prefix the variable name with
LIST__
or
DICT__
,
respectively:
from
collections
import
OrderedDict
LIST__ANIMALS
=
[
"cat"
,
"dog"
]
DICT__FINNISH
=
OrderedDict
([(
"cat"
,
"kissa"
),
(
"dog"
,
"koira"
)])
These prefixes will not be part of the final variable name, but they cause
Robot Framework to validate that the value actually is list-like or
dictionary-like. With dictionaries the actual stored value is also turned
into a special dictionary that is used also when
creating dictionaries
in the Variable section. Values of these dictionaries are accessible
as attributes like
${FINNISH.cat}
. These dictionaries are also ordered, but
preserving the source order requires also the original dictionary to be
ordered.
The variables in both the examples above could be created also using the
Variable section below.
*** Variables ***
${
VARIABLE
}
An example string
${
ANOTHER VARIABLE
}
This is pretty easy!
${
INTEGER
} ${
42
}
@{
STRINGS
}
one
two
kolme
four
@{
NUMBERS
} ${
1
} ${
INTEGER
} ${
3.14
}
&{
MAPPING
}
one=
${
1
}
two=
${
2
}
three=
${
3
}
@{
ANIMALS
}
cat
dog
&{
FINNISH
}
cat=kissa
dog=koira
Note
Variables are not replaced in strings got from variable files.
For example,
VAR = "an ${example}"
would create
variable
${VAR}
with a literal string value
an ${example}
regardless would variable
${example}
exist or not.
Using objects as values
Variables in variable files are not limited to having only strings or
other base types as values like Variable sections. Instead, their
variables can contain any objects. In the example below, the variable
${MAPPING}
contains 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 *
.
The third option to select what variables are actually created is using
a special
get_variables
function discussed below.
Getting variables from a special function
An alternative approach for getting variables is having a special
get_variables
function (also camelCase syntax
getVariables
is possible)
in a variable file. If such a function exists, Robot Framework calls it and
expects to receive variables as a Python dictionary with variable names as keys
and variable values as values. Created variables can
be used as scalars, lists, and dictionaries exactly like when
getting
variables directly from a module
, and it is possible to use
LIST__
and
DICT__
prefixes to make creating list and dictionary variables more explicit.
The example below is functionally identical to the first example related to
getting variables directly from a module
.
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
],
"MAPPING"
:
{
"one"
:
1
,
"two"
:
2
,
"three"
:
3
}}
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
, arguments are specified after the path
to the variable file, and in the command line they are separated from the
path with a colon or a semicolon.
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
Starting from Robot Framework 7.0, arguments to variable files support automatic
argument conversion as well as named argument syntax. For example, a variable
file with
get_variables(first: int = 0, second: str = '')
could be imported
like this:
*** Settings ***
Variables
example.py
42
# Converted to integer.
Variables
example.py
second=value
# Named argument syntax.
Implementing variable file as a class
It is possible to implement variables files also as a class.
Implementation
Because variable files are always imported using a file system path,
the class must have the same name as the module it is located in.
The framework will create an instance of the class using no arguments and
variables will be gotten from the instance. Similarly as with modules,
variables can be defined as attributes directly
in the instance or gotten from a special
get_variables
method.
When variables are defined directly in an instance, all attributes containing
callable values are ignored to avoid creating variables from possible methods
the instance has. If you would actually need callable variables, you need
to use other approaches to create variable files.
Examples
The first examples create variables from attributes.
It creates variables
${VARIABLE}
and
@{LIST}
from class
attributes and
${ANOTHER VARIABLE}
from an instance attribute.
class
StaticExample
:
variable
=
'value'
LIST__list
=
[
1
,
2
,
3
]
_not_variable
=
'starts with an underscore'
def
__init__
(
self
):
self
.
another_variable
=
'another value'
The second examples utilizes dynamic approach for getting variables. It
creates only one variable
${DYNAMIC VARIABLE}
.
class
DynamicExample
:
def
get_variables
(
self
,
*
args
):
return
{
'dynamic variable'
:
' '
.
join
(
args
)}
Variable file as YAML
Variable files can also be implemented as
YAML
files.
YAML is a data serialization language with a simple and human-friendly syntax
that is nevertheless easy for machines to parse.
The following example demonstrates a simple YAML file:
string
:
Hello, world!
integer
:
42
list
:
-
one
-
two
dict
:
one
:
yksi
two
:
kaksi
with spaces
:
kolme
YAML variable files can be used exactly like normal variable files
from the command line using
--variablefile
option, in the Settings
section using
Variables
setting, and dynamically using the
Import Variables
keyword. They are automatically recognized by their
extension that must be either
.yaml
or
.yml
.
If the above YAML file is imported, it will create exactly the same variables
as this Variable section:
*** Variables ***
${
STRING
}
Hello, world!
${
INTEGER
} ${
42
}
@{
LIST
}
one
two
&{
DICT
}
one=yksi
two=kaksi
with spaces=kolme
YAML files used as variable files must always be mappings on the top level.
As the above example demonstrates, keys and values in the mapping become
variable names and values, respectively. Variable values can be any data
types supported by YAML syntax. If names or values contain non-ASCII
characters, YAML variables files must be UTF-8 encoded.
Mappings used as values are automatically converted to special dictionaries
that are used also when
creating dictionaries
in the Variable section.
Most importantly, values of these dictionaries are accessible as attributes
like
${DICT.one}
, assuming their names are valid as Python attribute names.
If the name contains spaces or is otherwise not a valid attribute name, it is
always possible to access dictionary values using syntax like
${DICT}[with spaces]
syntax.
Note
Using YAML files with Robot Framework requires
PyYAML
module to be installed. You can typically
install it with
pip
like
pip install pyyaml
.
Variable file as JSON
Variable files can also be implemented as
JSON
files.
Similarly as YAML discussed in the previous section, JSON is a data
serialization format targeted both for humans and machines. It is based on
JavaScript syntax and it is not as human-friendly as YAML, but it still
relatively easy to understand and modify. The following example contains
exactly the same data as the earlier YAML example:
{
"string"
:
"Hello, world!"
,
"integer"
:
42
,
"list"
:
[
"one"
,
"two"
],
"dict"
:
{
"one"
:
"yksi"
,
"two"
:
"kaksi"
,
"with spaces"
:
"kolme"
}
}
JSON variable files are automatically recognized by their
.json
extension and they can be used exactly like YAML variable files. They
also have exactly same requirements for structure, encoding, and so on.
Unlike YAML, Python supports JSON out-of-the-box so no extra modules need
to be installed.
Note
Support for JSON variable files is new in Robot Framework 6.1.
2.9 Control structures
This section describes various structures that can be used to control the test
execution flow. These structures are familiar from most programming languages
and they allow conditional execution, repeatedly executing a block of keywords
and fine-grained error handling. For readability reasons these structures should
be used judiciously, and more complex use cases should be preferably
implemented in
test libraries
.
2.9.1
FOR
loops
Simple
FOR
loop
Old
FOR
loop syntax
Nesting
FOR
loops
Using several loop variables
FOR-IN-RANGE
loop
FOR-IN-ENUMERATE
loop
FOR-IN-ZIP
loop
Dictionary iteration
Loop variable conversion
Removing unnecessary keywords from outputs
Repeating single keyword
2.9.2
WHILE loops
Basic
WHILE
syntax
Limiting
WHILE
loop iterations
Nesting
WHILE
loops
Removing unnecessary keywords from outputs
2.9.3 Loop control using
BREAK
and
CONTINUE
2.9.4
IF/ELSE
syntax
Basic
IF
syntax
ELSE
branches
ELSE IF
branches
Inline
IF
Nested
IF
structures
Other ways to execute keywords conditionally
2.9.5
TRY/EXCEPT
syntax
Catching exceptions with
EXCEPT
Matching errors using patterns
Capturing error message
Using
ELSE
to execute keywords when there are no errors
Using
FINALLY
to execute keywords regardless are there errors or not
Other ways to handle errors
2.9.6
GROUP
syntax
GROUP
with templates
Programmatic usage
2.9.1
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 supported also by various other programming languages.
Simple
FOR
loop
In a normal
FOR
loop, one variable is assigned based on a list of values,
one value per iteration. The syntax starts with
FOR
(case-sensitive) as
a marker, then the loop variable, then a mandatory
IN
(case-sensitive) as
a separator, and finally the values to iterate. These values can contain
variables
, including
list variables
.
The keywords used in the
FOR
loop are on the following rows and the loop
ends with
END
(case-sensitive) on its own row. Keywords inside the loop
do not need to be indented, but that is highly recommended to make the syntax
easier to read.
*** Test Cases ***
Example
FOR
${
animal
}
IN
cat
dog
Log
${
animal
}
Log
2nd keyword
END
Log
Outside loop
Second Example
FOR
${
var
}
IN
one
two
${
3
}
four
${
five
}
...
kuusi
7
eight
nine
${
last
}
Log
${
var
}
END
The
FOR
loop in
Example
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 two rows
and the
loop is run altogether ten times.
It is often convenient to use
FOR
loops with
list variables
. This is
illustrated by the example below, where
@{ELEMENTS}
contains
an arbitrarily long list of elements and keyword
Start Element
is
used with all of them one by one.
*** Test Cases ***
Example
FOR
${
element
}
IN
@{
ELEMENTS
}
Start Element
${
element
}
END
Old
FOR
loop syntax
Prior to Robot Framework 3.1, the
FOR
loop syntax was different than nowadays.
The marker to start the loop was
:FOR
instead of
FOR
and loop contents needed
to be explicitly marked with a backslash instead of using the
END
marker to end
the loop. The first example above would look like this using the old syntax:
*** Test Cases ***
Example
:FOR ${
animal
} IN
cat
dog
\
Log
${
animal
}
\
Log
2nd keyword
Log
Outside loop
The old syntax was deprecated in Robot Framework 3.2 and the support for it was
removed altogether in Robot Framework 4.0.
Nesting
FOR
loops
Starting from Robot Framework 4.0, it is possible to use nested
FOR
loops
simply by adding a loop inside another loop:
*** Keywords ***
Handle Table
[
Arguments
] @{
table
}
FOR
${
row
}
IN
@{
table
}
FOR
${
cell
}
IN
@{
row
}
Handle Cell
${
cell
}
END
END
There can be multiple nesting levels and loops can also be combined with
other control structures:
*** Test Cases ***
Multiple nesting levels
FOR
${
root
}
IN
r1
r2
FOR
${
child
}
IN
c1
c2
c3
FOR
${
grandchild
}
IN
g1
g2
Log Many
${
root
} ${
child
} ${
grandchild
}
END
END
FOR
${
sibling
}
IN
s1
s2
s3
IF
'
${
sibling
}
' != 's2'
Log Many
${
root
} ${
sibling
}
END
END
END
Using several loop variables
It is possible to iterate over multiple values in one iteration by using
multiple loop variables between the
FOR
and
IN
markers. There can be
any number of loop variables, but the number of values must be evenly
dividable by the number of variables. Each iteration consumes as many
values as there are variables.
If there are lot of values to iterate, it is often convenient to organize
them below the loop variables, as in the first loop of the example below:
*** Test Cases ***
Multiple loop variables
FOR
${
index
} ${
english
} ${
finnish
}
IN
...
1
cat
kissa
...
2
dog
koira
...
3
horse
hevonen
Add Translation
${
english
} ${
finnish
} ${
index
}
END
FOR
${
name
} ${
id
}
IN
@{
EMPLOYERS
}
Create
${
name
} ${
id
}
END
FOR-IN-RANGE
loop
All
FOR
loops in the previous section iterated over a sequence. That is the most
common use case, but sometimes it is convenient to have a loop that is executed
a certain number of times. For this purpose Robot Framework has a special
FOR index IN RANGE limit
loop syntax that is derived from the similar Python
idiom using the
built-in range() function
.
Similarly as other
FOR
loops, the
FOR-IN-RANGE
loop starts with
FOR
that is followed by a loop variable. In this format
there can be only one loop variable and it contains the current loop
index. After the variable there must be
IN RANGE
marker (case-sensitive)
that is followed by loop limits.
In the simplest case, only the upper limit of the loop is
specified. In this case, loop indices 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 indices 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.
It is possible to use simple arithmetic such as addition and subtraction
with the range limits. This is especially useful when the limits are
specified with variables. Start, end and step are typically given as
integers, but using float values is possible as well.
*** Test Cases ***
Only upper limit
[
Documentation
]
Loops over values from 0 to 9.
FOR
${
index
}
IN RANGE
10
Log
${
index
}
END
Start and end
[
Documentation
]
Loops over values from 1 to 10.
FOR
${
index
}
IN RANGE
1
11
Log
${
index
}
END
Also step given
[
Documentation
]
Loops over values 5, 15, and 25.
FOR
${
index
}
IN RANGE
5
26
10
Log
${
index
}
END
Negative step
[
Documentation
]
Loops over values 13, 3, and -7.
FOR
${
index
}
IN RANGE
13
-13
-10
Log
${
index
}
END
Arithmetic
[
Documentation
]
Arithmetic with variable.
FOR
${
index
}
IN RANGE
${
var
}
+ 1
Log
${
index
}
END
Float parameters
[
Documentation
]
Loops over values 3.14, 4.34, and 5.54.
FOR
${
index
}
IN RANGE
3.14
6.09
1.2
Log
${
index
}
END
FOR-IN-ENUMERATE
loop
Sometimes it is useful to loop over a list and also keep track of your location
inside the list. Robot Framework has a special
FOR index ... IN ENUMERATE ...
syntax for this situation.
This syntax is derived from the
Python built-in enumerate() function
.
FOR-IN-ENUMERATE
loops syntax is just like the regular
FOR
loop syntax,
except that the separator between variables and values is
IN ENUMERATE
(case-sensitive). Typically they are used so that there is an additional index
variable before any other loop-variables. By default the index has a value
0
on the first iteration,
1
on the second, and so on.
For example, the following two test cases do the same thing:
*** Variables ***
@{
LIST
}
a
b
c
*** Test Cases ***
Manage index manually
${
index
} =
Set Variable
-1
FOR
${
item
}
IN
@{
LIST
}
${
index
} =
Evaluate
${
index
}
+ 1
My Keyword
${
index
} ${
item
}
END
FOR-IN-ENUMERATE
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
LIST
}
My Keyword
${
index
} ${
item
}
END
Starting from Robot Framework 4.0, it is possible to specify a custom start index
by using
start=<index>
syntax as the last item of the
FOR ... IN ENUMERATE ...
header:
*** Variables ***
@{
LIST
}
a
b
c
${
START
}
10
*** Test Cases ***
FOR-IN-ENUMERATE with start
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
LIST
}
start=1
My Keyword
${
index
} ${
item
}
END
Start as variable
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
LIST
}
start=
${
start
}
My Keyword
${
index
} ${
item
}
END
The
start=<index>
syntax must be explicitly used in the
FOR
header and it cannot
itself come from a variable. If the last actual item to enumerate would start with
start=
, it needs to be escaped like
start\=
.
Just like with regular
FOR
loops, you can loop over multiple values per loop
iteration as long as the number of values in your list is evenly divisible by
the number of loop-variables (excluding the index variable):
*** Test Cases ***
FOR-IN-ENUMERATE with two values per iteration
FOR
${
index
} ${
en
} ${
fi
}
IN ENUMERATE
...
cat
kissa
...
dog
koira
...
horse
hevonen
Log
"
${
en
}
" in English is "
${
fi
}
" in Finnish (index:
${
index
}
)
END
If you only use one loop variable with
FOR-IN-ENUMERATE
loops, that variable
will become a Python tuple containing the index and the iterated value:
*** Test Cases ***
FOR-IN-ENUMERATE with one loop variable
FOR
${
x
}
IN ENUMERATE
@{
LIST
}
Length Should Be
${
x
}
2
Log
Index is
${
x
}
[0] and item is
${
x
}
[1].
END
Note
FOR-IN-ENUMERATE
loops with only one loop variable is a new
feature in Robot Framework 3.2.
FOR-IN-ZIP
loop
Some tests build up several related lists, then loop over them together.
Robot Framework has a shortcut for this case:
FOR ... IN ZIP ...
, which
is derived from the
Python built-in zip() function
.
This may be easiest to show with an example:
*** Variables ***
@{
NUMBERS
} ${
1
} ${
2
} ${
5
}
@{
NAMES
}
one
two
five
*** Test Cases ***
Iterate over two lists manually
${
length
}=
Get Length
${
NUMBERS
}
FOR
${
index
}
IN RANGE
${
length
}
Log Many
${
NUMBERS
}
[
${
index
}
]
${
NAMES
}
[
${
index
}
]
END
FOR-IN-ZIP
FOR
${
number
} ${
name
}
IN ZIP
${
NUMBERS
} ${
NAMES
}
Log Many
${
number
} ${
name
}
END
As the example above illustrates,
FOR-IN-ZIP
loops require their own custom
separator
IN ZIP
(case-sensitive) between loop variables and values.
Values used with
FOR-IN-ZIP
loops must be lists or list-like objects.
Items to iterate over must always be given either as
scalar variables
like
${items}
or as
list variables
like
@{lists}
that yield the actual
iterated lists. The former approach is more common and it was already
demonstrated above. The latter approach works like this:
*** Variables ***
@{
NUMBERS
} ${
1
} ${
2
} ${
5
}
@{
NAMES
}
one
two
five
@{
LISTS
} ${
NUMBERS
} ${
NAMES
}
*** Test Cases ***
FOR-IN-ZIP with lists from variable
FOR
${
number
} ${
name
}
IN ZIP
@{
LISTS
}
Log Many
${
number
} ${
name
}
END
The number of lists to iterate over is not limited, but it must match
the number of loop variables. Alternatively, there can be just one loop
variable that then becomes a Python tuple getting items from all lists.
*** Variables ***
@{
ABC
}
a
b
c
@{
XYZ
}
x
y
z
@{
NUM
}
1
2
3
*** Test Cases ***
FOR-IN-ZIP with multiple lists
FOR
${
a
} ${
x
} ${
n
}
IN ZIP
${
ABC
} ${
XYZ
} ${
NUM
}
Log Many
${
a
} ${
x
} ${
n
}
END
FOR-IN-ZIP with one variable
FOR
${
items
}
IN ZIP
${
ABC
} ${
XYZ
} ${
NUM
}
Length Should Be
${
items
}
3
Log Many
${
items
}
[0]
${
items
}
[1]
${
items
}
[2]
END
Starting from Robot Framework 6.1, it is possible to configure what to do if
lengths of the iterated items differ. By default, the shortest item defines how
many iterations there are and values at the end of longer ones are ignored.
This can be changed by using the
mode
option that has three possible values:
STRICT
: Items must have equal lengths. If not, execution fails. This is
the same as using
strict=True
with Python's
zip
function.
SHORTEST
: Items in longer items are ignored. Infinite iterators are supported
in this mode as long as one of the items is exhausted. This is the default
behavior.
LONGEST
: The longest item defines how many iterations there are. Missing
values in shorter items are filled-in with value specified using the
fill
option or
None
if it is not used. This is the same as using Python's
zip_longest
function except that it has
fillvalue
argument instead of
fill
.
All these modes are illustrated by the following examples:
*** Variables ***
@{
CHARACTERS
}
a
b
c
d
f
@{
NUMBERS
}
1
2
3
*** Test Cases ***
STRICT mode
[
Documentation
]
This loop fails due to lists lengths being different.
FOR
${
c
} ${
n
}
IN ZIP
${
CHARACTERS
} ${
NUMBERS
}
mode=STRICT
Log
${
c
}
:
${
n
}
END
SHORTEST mode
[
Documentation
]
This loop executes three times.
FOR
${
c
} ${
n
}
IN ZIP
${
CHARACTERS
} ${
NUMBERS
}
mode=SHORTEST
Log
${
c
}
:
${
n
}
END
LONGEST mode
[
Documentation
]
This loop executes five times.
...
On last two rounds `
${
n
}
` has value `None`.
FOR
${
c
} ${
n
}
IN ZIP
${
CHARACTERS
} ${
NUMBERS
}
mode=LONGEST
Log
${
c
}
:
${
n
}
END
LONGEST mode with custom fill value
[
Documentation
]
This loop executes five times.
...
On last two rounds `
${
n
}
` has value `0`.
FOR
${
c
} ${
n
}
IN ZIP
${
CHARACTERS
} ${
NUMBERS
}
mode=LONGEST
fill=0
Log
${
c
}
:
${
n
}
END
Note
The behavior if list lengths differ will change in the future
so that the
STRICT
mode will be the default. If that is not desired,
the
SHORTEST
mode needs to be used explicitly.
Dictionary iteration
Normal
FOR
loops and
FOR-IN-ENUMERATE
loops support iterating over keys
and values in dictionaries. This syntax requires at least one of the loop
values to be a
dictionary variable
.
It is possible to use multiple dictionary variables and to give additional
items in
key=value
syntax. Items are iterated in the order they are defined
and if same key gets multiple values the last value will be used.
*** Variables ***
&{
DICT
}
a=1
b=2
c=3
*** Test Cases ***
Dictionary iteration with FOR loop
FOR
${
key
} ${
value
}
IN
&{
DICT
}
Log
Key is '
${
key
}
' and value is '
${
value
}
'.
END
Dictionary iteration with FOR-IN-ENUMERATE loop
FOR
${
index
} ${
key
} ${
value
}
IN ENUMERATE
&{
DICT
}
Log
On round
${
index
}
key is '
${
key
}
' and value is '
${
value
}
'.
END
Multiple dictionaries and extra items in 'key=value' syntax
&{
more
} =
Create Dictionary
e=5
f=6
FOR
${
key
} ${
value
}
IN
&{
DICT
}
d=4
&{
more
}
g=7
Log
Key is '
${
key
}
' and value is '
${
value
}
'.
END
Typically it is easiest to use the dictionary iteration syntax so that keys
and values get separate variables like in the above examples. With normal
FOR
loops it is also possible to use just a single variable that will become
a tuple containing the key and the value. If only one variable is used with
FOR-IN-ENUMERATE
loops, it becomes a tuple containing the index, the key and
the value. Two variables with
FOR-IN-ENUMERATE
loops means assigning the index
to the first variable and making the second variable a tuple containing the key
and the value.
*** Test Cases ***
One loop variable
FOR
${
item
}
IN
&{
DICT
}
Log
Key is '
${
item
}
[0]' and value is '
${
item
}
[1]'.
END
One loop variable with FOR-IN-ENUMERATE
FOR
${
item
}
IN ENUMERATE
&{
DICT
}
Log
On round
${
item
}
[0] key is '
${
item
}
[1]' and value is '
${
item
}
[2]'.
END
Two loop variables with FOR-IN-ENUMERATE
FOR
${
index
} ${
item
}
IN ENUMERATE
&{
DICT
}
Log
On round
${
index
}
key is '
${
item
}
[0]' and value is '
${
item
}
[1]'.
END
In addition to iterating over names and values in dictionaries, it is possible
to iterate over keys and then possibly fetch the value based on it. This syntax
requires using dictionaries as
list variables
:
*** Test Cases ***
Iterate over keys
FOR
${
key
}
IN
@{
DICT
}
Log
Key is '
${
key
}
' and value is '
${
DICT
}
[
${
key
}
]'.
END
Note
Iterating over keys and values in dictionaries is a new feature in
Robot Framework 3.2. With earlier version it is possible to iterate
over dictionary keys like the last example above demonstrates.
Loop variable conversion
Variable type conversion
works also with FOR loop variables. The desired type
can be added to any loop variable by using the familiar
${name: type}
syntax.
*** Test Cases ***
Variable conversion
FOR
${
value: bytes
}
IN
Hello!
Hyvä!
\x00\x00\x07
Log
${
value
}
formatter=repr
END
FOR
${
index
} ${
date: date
}
IN ENUMERATE
2023-06-15
2025-05-30
today
Log
${
date
}
formatter=repr
END
FOR
${
item: tuple[str, date]
}
IN ENUMERATE
2023-06-15
2025-05-30
today
Log
${
item
}
formatter=repr
END
Note
Variable type conversion is new in Robot Framework 7.3.
Removing unnecessary keywords from outputs
FOR
loops with multiple iterations often create lots of output and
considerably increase the size of the generated
output
and
log
files.
It is possible to
remove or flatten unnecessary keywords
using
--removekeywords
and
--flattenkeywords
command line options.
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.
*** Test Cases ***
Example
Repeat Keyword
5
Some Keyword
arg1
arg2
Repeat Keyword
42 times
My Keyword
Repeat Keyword
${
var
}
Another Keyword
argument
2.9.2
WHILE loops
WHILE
loops combine features of
FOR loops
and
IF/ELSE structures
.
They specify a condition and repeat the loop body as long as the condition
remains true. This can be utilised, for example, to repeat a nondeterministic sequence
until the desired outcome happens, or in some cases they can be used as an
alternative to
FOR loops
.
Note
WHILE
loops are new in Robot Framework 5.0.
Basic
WHILE
syntax
*** Test Cases ***
Example
VAR
${
rc
}
1
WHILE
${
rc
}
!= 0
${
rc
} =
Keyword that returns zero on success
END
The
WHILE
loop condition is evaluated in Python so that Python builtins like
len()
are available and modules are imported automatically to support usages
like
math.pi * math.pow(${radius}, 2) < 10
.
Normal variables like
${rc}
in the above example are replaced before evaluation, but
variables are also available in the evaluation namespace using the special
$rc
syntax.
The latter approach is handy when the string representation of the variable cannot be
used in the condition directly. For example, strings require quoting and multiline
strings and string themselves containing quotes cause additional problems. See the
Evaluating expressions
appendix for more information and examples related to
the evaluation syntax.
Starting from Robot Framework 6.1, the condition in a
WHILE
statement can be omitted.
This is interpreted as the condition always being true, which may be useful with the
limit
option described below.
Limiting
WHILE
loop iterations
With
WHILE
loops, there is always a possibility to achieve an infinite loop,
either by intention or by mistake. This happens when the loop condition never
becomes false. While infinite loops have some utility in application programming,
in automation an infinite loop is rarely a desired outcome. If such a loop occurs
with Robot Framework, the execution must be forcefully stopped and no log or report
can be created. For this reason,
WHILE
loops in Robot Framework have a default
limit of 10 000 iterations. If the limit is exceeded, the loop fails.
The limit can be set with the
limit
configuration parameter either as a maximum
iteration count or as a maximum time for the whole loop. When the limit is an
iteration count, it is possible to use just integers like
100
and to add
times
or
x
suffix after the value like
100 times
. When the limit is a timeout,
it is possible to use
time strings
like
10 s
or
1 hour 10 minutes
.
The limit can also be disabled altogether by using
NONE
(case-insensitive).
All these options are illustrated by the examples below.
*** Test Cases ***
Limit as iteration count
WHILE
True
limit=100
Log
This is run 100 times.
END
WHILE
True
limit=10 times
Log
This is run 10 times.
END
WHILE
True
limit=42x
Log
This is run 42 times.
END
Limit as time
WHILE
True
limit=10 seconds
Log
This is run 10 seconds.
END
No limit
WHILE
True
limit=NONE
Log
This runs forever.
END
Note
Support for using
times
and
x
suffixes with iteration counts
is new in Robot Framework 7.0.
Keywords in a loop are not forcefully stopped if the limit is exceeded. Instead
the loop is exited similarly as if the loop condition would have become false.
A major difference is that the loop status will be
FAIL
in this case.
Starting from Robot Framework 6.1, it is possible to use
on_limit
parameter to
configure the behaviour when the limit is exceeded. It supports two values
pass
and
fail
, case insensitively. If the value is
pass
, the execution will continue
normally when the limit is reached and the status of the
WHILE
loop will be
PASS
.
The value
fail
works similarly as the default behaviour, e.g. the loop and the
test will fail if the limit is exceeded.
*** Test Cases ***
Continue when iteration limit is reached
WHILE
True
limit=5
on_limit=pass
Log
Loop will be executed five times
END
Log
This will be executed normally.
Continue when time limit is reached
WHILE
True
limit=10s
on_limit=pass
Log
Loop will be executed for 10 seconds.
Sleep
0.5s
END
Log
This will be executed normally.
By default, the error message raised when the limit is reached is
WHILE loop was aborted because it did not finish within the limit of 0.5
seconds. Use the 'limit' argument to increase or remove the limit if
needed.
. Starting from Robot Framework 6.1, the error message can be changed
with the
on_limit_message
configuration parameter.
*** Test Cases ***
Limit as iteration count
WHILE
True
limit=0.5s
on_limit_message=Custom While loop error message
Log
This is run 0.5 seconds.
END
Note
on_limit_message
configuration parameter is new in Robot Framework 6.1.
Nesting
WHILE
loops
WHILE
loops can be nested and also combined with other control structures:
*** Test Cases ***
Nesting WHILE
VAR
${
x
}
10
WHILE
${
x
}
> 0
VAR
${
y
} ${
x
}
WHILE
${
y
}
> 0
${
y
} =
Evaluate
${
y
}
- 1
END
IF
${
x
}
> 5
${
x
} =
Evaluate
${
x
}
- 1
ELSE
${
x
} =
Evaluate
${
x
}
- 2
END
END
Removing unnecessary keywords from outputs
WHILE
loops with multiple iterations often create lots of output and
considerably increase the size of the generated
output
and
log
files.
It is possible to
remove or flatten unnecessary keywords
using
--removekeywords
and
--flattenkeywords
command line options.
2.9.3 Loop control using
BREAK
and
CONTINUE
Both
FOR
and
WHILE
loop execution can be controlled with
BREAK
and
CONTINUE
statements. The former exits the whole loop prematurely and the latter stops
executing the current loop iteration and continues to the next one. In practice
they have the same semantics as
break
and
continue
statements in Python, Java,
and many other programming languages.
Both
BREAK
and
CONTINUE
are typically used conditionally with
IF/ELSE
or
TRY/EXCEPT
structures, and especially the
inline IF
syntax is often
convenient with them. These statements must be used in the loop body,
possibly inside the aforementioned control structures, and using them in
keyword called in the loop body is invalid.
*** Test Cases ***
BREAK with FOR
${
text
} =
Set Variable
zero
FOR
${
var
}
IN
one
two
three
IF
'
${
var
}
' == 'two'
BREAK
${
text
} =
Set Variable
${
text
}
-
${
var
}
END
Should Be Equal
${
text
}
zero-one
CONTINUE with FOR
${
text
} =
Set Variable
zero
FOR
${
var
}
IN
one
two
three
IF
'
${
var
}
' == 'two'
CONTINUE
${
text
} =
Set Variable
${
text
}
-
${
var
}
END
Should Be Equal
${
text
}
zero-one-three
CONTINUE and BREAK with WHILE
WHILE
True
TRY
${
value
} =
Do Something
EXCEPT
CONTINUE
END
Do something with value
${
value
}
BREAK
END
Invalid BREAK usage
[
Documentation
]
BREAK and CONTINUE can only be used in the loop body,
...
not in keywords used in the loop.
FOR
${
var
}
IN
one
two
three
Invalid BREAK
END
*** Keywords ***
Invalid BREAK
[
Documentation
]
This keyword fails due to invalid syntax.
BREAK
Note
BREAK
and
CONTINUE
statements are new in Robot Framework 5.0 similarly
as
WHILE
. Earlier versions supported controlling
FOR
loops using
BuiltIn
keywords
Exit For Loop
,
Exit For Loop If
,
Continue For Loop
and
Continue For Loop If
. These
keywords still continue to work, but they will be deprecated and removed
in the future.
Note
Also the
RETURN
statement can be used to a exit loop. It only works
when loops are used inside a
user keyword
.
2.9.4
IF/ELSE
syntax
Sometimes there is a need to execute some keywords conditionally. Starting
from Robot Framework 4.0 there is a separate
IF/ELSE
syntax, but
there are also
other ways to execute keywords conditionally
. Notice that if
the logic gets complicated, it is typically better to move it into a
test library
.
Basic
IF
syntax
Robot Framework's native
IF
syntax starts with
IF
(case-sensitive) and
ends with
END
(case-sensitive). The
IF
marker requires exactly one value that is
the condition to evaluate. Keywords to execute if the condition is true are on their
own rows between the
IF
and
END
markers. Indenting keywords in the
IF
block is
highly recommended but not mandatory.
In the following example keywords
Some keyword
and
Another keyword
are executed if
${rc}
is greater than zero:
*** Test Cases ***
Example
IF
${
rc
}
> 0
Some keyword
Another keyword
END
The condition is evaluated in Python so that Python builtins like
len()
are available and modules are imported automatically to support usages like
platform.system() == 'Linux'
and
math.ceil(${x}) == 1
.
Normal variables like
${rc}
in the above example are replaced before evaluation, but
variables are also available in the evaluation namespace using the special
$rc
syntax.
The latter approach is handy when the string representation of the variable cannot be
used in the condition directly. For example, strings require quoting and multiline
strings and string themselves containing quotes cause additional problems. For more
information and examples related the evaluation syntax see the
Evaluating expressions
appendix.
ELSE
branches
Like most other languages supporting conditional execution, Robot Framework
IF
syntax also supports
ELSE
branches that are executed if the
IF
condition is
not true.
In this example
Some keyword
is executed if
${rc}
is greater than
zero and
Another keyword
is executed otherwise:
*** Test Cases ***
Example
IF
${
rc
}
> 0
Some keyword
ELSE
Another keyword
END
ELSE IF
branches
Robot Framework also supports
ELSE IF
branches that have their own condition
that is evaluated if the initial condition is not true. There can be any number
of
ELSE IF
branches and they are gone through in the order they are specified.
If one of the
ELSE IF
conditions is true, the block following it is executed
and remaining
ELSE IF
branches are ignored. An optional
ELSE
branch can follow
ELSE IF
branches and it is executed if all conditions are false.
In the following example different keyword is executed depending on is
${rc}
positive,
negative, zero, or something else like a string or
None
:
*** Test Cases ***
Example
IF
$rc > 0
Positive keyword
ELSE IF
$rc < 0
Negative keyword
ELSE IF
$rc == 0
Zero keyword
ELSE
Fail
Unexpected rc:
${
rc
}
END
Notice that this example uses the
${rc}
variable in the special
$rc
format to
avoid evaluation failures if it is not a number. See the aforementioned
Evaluating expressions
appendix for more information about this syntax.
Inline
IF
Normal
IF/ELSE
structure is a bit verbose if there is a need to execute only
a single statement. An alternative to it is using inline
IF
syntax where
the statement to execute follows the
IF
marker and condition directly and
no
END
marker is needed. For example, the following two keywords are
equivalent:
*** Keywords ***
Normal IF
IF
$condition1
Keyword
argument
END
IF
$condition2
RETURN
END
Inline IF
IF
$condition1
Keyword
argument
IF
$condition2
RETURN
The inline
IF
syntax supports also
ELSE
and
ELSE IF
branches:
*** Keywords ***
Inline IF/ELSE
IF
$condition
Keyword
argument
ELSE
Another Keyword
Inline IF/ELSE IF/ELSE
IF
$cond1
Keyword 1
ELSE IF
$cond2
Keyword 2
ELSE IF
$cond3
Keyword 3
ELSE
Keyword 4
As the latter example above demonstrates, inline
IF
with several
ELSE IF
and
ELSE
branches starts to get hard to understand. Long inline
IF
structures can be
split into multiple lines
using the common
...
continuation syntax, but using a normal
IF/ELSE
structure or moving the logic
into a
test library
is probably a better idea. Each inline
IF
branch can
contain only one statement. If more statements are needed, normal
IF/ELSE
structure needs to be used instead.
If there is a need for an assignment with inline
IF
, the variable or variables
to assign must be before the starting
IF
. Otherwise the logic is exactly
the same as when
assigning variables
based on keyword return values. If
assignment is used and no branch is run, the variable gets value
None
.
*** Keywords ***
Inline IF/ELSE with assignment
${
var
} =
IF
$condition
Keyword
argument
ELSE
Another Keyword
Inline IF/ELSE with assignment having multiple variables
${
host
} ${
port
} =
IF
$production
Get Production Config
ELSE
Get Testing Config
Note
Inline
IF
syntax is new in Robot Framework 5.0.
Nested
IF
structures
IF
structures can be nested with each others and with
FOR loops
.
This is illustrated by the following example using advanced features such
as
FOR-IN-ENUMERATE loop
,
named-only arguments with user keywords
and
inline Python evaluation
syntax (
${{len(${items})}}
):
*** Keywords ***
Log items
[
Arguments
] @{
items
} ${
log_values
}
=True
IF
not
${
items
}
Log to console
No items.
ELSE IF
len(
${
items
}
) == 1
IF
${
log_values
}
Log to console
One item:
${
items
}
[0]
ELSE
Log to console
One item.
END
ELSE
Log to console
${
{len(
${
items
}
)
}
} items.
IF
${
log_values
}
FOR
${
index
} ${
item
}
IN ENUMERATE
@{
items
}
start=1
Log to console
Item
${
index
}
:
${
item
}
END
END
END
*** Test Cases ***
No items
Log items
One item without logging value
Log items
xxx
log_values=False
Multiple items
Log items
a
b
c
Other ways to execute keywords conditionally
There are also other methods to execute keywords conditionally:
The name of the keyword used as a setup or a teardown with
suites
,
tests
and
keywords
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.
The new
IF/ELSE
syntax explained above is generally recommended, though.
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.9.5
TRY/EXCEPT
syntax
When a keyword fails, Robot Framework's default behavior is to stop the current
test and executes its possible
teardown
. There can, however, be needs to handle
these failures during execution as well. Robot Framework 5.0 introduces native
TRY/EXCEPT
syntax for this purpose, but there also
other ways to handle errors
.
Robot Framework's
TRY/EXCEPT
syntax is inspired by Python's
exception handling
syntax. It has same
TRY
,
EXCEPT
,
ELSE
and
FINALLY
branches as Python and
they also mostly work the same way. A difference is that Python uses lower case
try
,
except
, etc. but with Robot Framework all this kind of syntax must use
upper case letters. A bigger difference is that with Python exceptions are objects
and with Robot Framework you are dealing with error messages as strings.
Note
It is not possible to catch errors caused by invalid syntax or errors
that
stop the whole execution
.
Catching exceptions with
EXCEPT
The basic
TRY/EXCEPT
syntax can be used to handle failures based on
error messages:
*** Test Cases ***
First example
TRY
Some Keyword
EXCEPT
Error message
Error Handler Keyword
END
Keyword Outside
In the above example, if
Some Keyword
passes, the
EXCEPT
branch is not run
and execution continues after the
TRY/EXCEPT
structure. If the keyword fails
with a message
Error message
(case-sensitive), the
EXCEPT
branch is executed.
If the
EXCEPT
branch succeeds, execution continues after the
TRY/EXCEPT
structure. If it fails, the test fails and remaining keywords are not executed.
If
Some Keyword
fails with any other exception, that failure is not handled
and the test fails without executing remaining keywords.
There can be more than one
EXCEPT
branch. In that case they are matched one
by one and the first matching branch is executed. One
EXCEPT
can also have
multiple messages to match, and such a branch is executed if any of its messages
match. In all these cases messages can be specified using variables in addition
to literal strings.
*** Test Cases ***
Multiple EXCEPT branches
TRY
Some Keyword
EXCEPT
Error message
# Try matching this first.
Error Handler 1
EXCEPT
Another error
# Try this if above did not match.
Error Handler 2
EXCEPT
${
message
}
# Last match attempt, this time using a variable.
Error Handler 3
END
Multiple messages with one EXCEPT
TRY
Some Keyword
EXCEPT
Error message
Another error
${
message
}
# Match any of these.
Error handler
END
It is also possible to have an
EXCEPT
without messages, in which case it matches
any error. There can be only one such
EXCEPT
and it must follow possible
other
EXCEPT
branches:
*** Test Cases ***
Match any error
TRY
Some Keyword
EXCEPT
# Match any error.
Error Handler
END
Match any after testing more specific errors
TRY
Some Keyword
EXCEPT
Error message
# Try matching this first
Error Handler 1
EXCEPT
# Match any that did not match the above.
Error Handler 2
END
Matching errors using patterns
By default matching an error using
EXCEPT
requires an exact match. That can be
changed using a configuration option
type=
as an argument to the except clause.
Valid values for the option are
GLOB
,
REGEXP
or
START
(case-insensitive)
to make the match a
glob pattern match
, a
regular expression match
, or
to match only the beginning of the error, respectively. Using value
LITERAL
has the same effect as the default behavior. If an
EXCEPT
has multiple
messages, this option applies to all of them. The value of the option
can be defined with a variable as well.
*** Variables ***
${
MATCH TYPE
}
regexp
*** Test Cases ***
Glob pattern
TRY
Some Keyword
EXCEPT
ValueError: *
type=GLOB
Error Handler 1
EXCEPT
[Ee]rror ?? occurred
${
pattern
}
type=glob
Error Handler 2
END
Regular expression
TRY
Some Keyword
EXCEPT
ValueError: .*
type=
${
MATCH TYPE
}
Error Handler 1
EXCEPT
[Ee]rror \\d+ occurred
type=Regexp
# Backslash needs to be escaped.
Error Handler 2
END
Match start
TRY
Some Keyword
EXCEPT
ValueError:
${
beginning
}
type=start
Error Handler
END
Explicit exact match
TRY
Some Keyword
EXCEPT
ValueError: invalid literal for int() with base 10: 'ooops'
type=LITERAL
Error Handler
EXCEPT
Error 13 occurred
type=LITERAL
Error Handler 2
END
Note
Remember that the backslash character often used with regular expressions
is an
escape character
in Robot Framework data. It thus needs to be
escaped with another backslash when using it in regular expressions.
Capturing error message
When
matching errors using patterns
and when using
EXCEPT
without any
messages to match any error, it is often useful to know the actual error that
occurred. Robot Framework supports that by making it possible to capture
the error message into a variable by adding
AS ${var}
at the
end of the
EXCEPT
statement:
*** Test Cases ***
Capture error
TRY
Some Keyword
EXCEPT
ValueError: *
type=GLOB
AS
${
error
}
Error Handler 1
${
error
}
EXCEPT
[Ee]rror \\d+
(Invalid|Bad) usage
type=REGEXP
AS
${
error
}
Error Handler 2
${
error
}
EXCEPT
AS
${
error
}
Error Handler 3
${
error
}
END
Using
ELSE
to execute keywords when there are no errors
Optional
ELSE
branches make it possible to execute keywords if there is no error.
There can be only one
ELSE
branch and it is allowed only after one or more
EXCEPT
branches:
*** Test Cases ***
ELSE branch
TRY
Some Keyword
EXCEPT
X
Log
Error 'X' occurred!
EXCEPT
Y
Log
Error 'Y' occurred!
ELSE
Log
No error occurred!
END
Keyword Outside
In the above example, if
Some Keyword
passes, the
ELSE
branch is executed,
and if it fails with message
X
or
Y
, the appropriate
EXCEPT
branch run.
In all these cases execution continues after the whole
TRY/EXCEPT/ELSE
structure.
If
Some Keyword
fail any other way,
EXCEPT
and
ELSE
branches are not run
and the
TRY/EXCEPT/ELSE
structure fails.
To handle both the case when there is any error and when there is no error,
it is possible to use an
EXCEPT
without any message in combination with an
ELSE
:
*** Test Cases ***
Handle everything
TRY
Some Keyword
EXCEPT
AS
${
err
}
Log
Error occurred:
${
err
}
ELSE
Log
No error occurred!
END
Using
FINALLY
to execute keywords regardless are there errors or not
Optional
FINALLY
branches make it possible to execute keywords both when there
is an error and when there is not. They are thus suitable for cleaning up
after a keyword execution somewhat similarly as
teardowns
. There can be only one
FINALLY
branch and it must always be last. They can be used in combination with
EXCEPT
and
ELSE
branches and having also
TRY/FINALLY
structure is possible:
*** Test Cases ***
TRY/EXCEPT/ELSE/FINALLY
TRY
Some keyword
EXCEPT
Log
Error occurred!
ELSE
Log
No error occurred.
FINALLY
Log
Always executed.
END
TRY/FINALLY
Open Connection
TRY
Use Connection
FINALLY
Close Connection
END
Other ways to handle errors
There are also other methods to execute keywords conditionally:
The
BuiltIn
keyword
Run Keyword And Expect Error
executes a named
keyword and expects that it fails with a specified error message. It is basically
the same as using
TRY/EXCEPT
with a specified message. The syntax to specify
the error message is also identical except that this keyword uses glob pattern
matching, not exact match, by default. Using the native
TRY/EXCEPT
functionality
is generally recommended unless there is a need to support older Robot Framework
versions that do not support it.
The
BuiltIn
keyword
Run Keyword And Ignore Error
executes a named keyword
and returns its status as string
PASS
or
FAIL
along with possible return value
or error message. It is basically the same as using
TRY/EXCEPT/ELSE
so that
EXCEPT
catches all errors. Using the native syntax is recommended unless
old Robot Framework versions need to be supported.
The
BuiltIn
keyword
Run Keyword And Return Status
executes a named keyword
and returns its status as a Boolean true or false. It is a wrapper for the
aforementioned
Run Keyword And Ignore Error
. The native syntax is
nowadays recommended instead.
Test teardowns
and
keyword teardowns
can be used for cleaning up activities
similarly as
FINALLY
branches.
When keywords are implemented in Python based
libraries
, all Python's error
handling features are readily available. This is the recommended approach
especially if needed logic gets more complicated.
2.9.6
GROUP
syntax
The
GROUP
syntax allows grouping related keywords and control structures together:
*** Test Cases ***
Valid login
GROUP
Open browser to login page
Open Browser
${
LOGIN URL
}
Title Should Be
Login Page
END
GROUP
Submit credentials
Input Username
username_field
demo
Input Password
password_field
mode
Click Button
login_button
END
GROUP
Login should have succeeded
Title Should Be
Welcome Page
END
Anonymous group
GROUP
Log
Group name is optional.
END
Nesting
GROUP
GROUP
Nested group
Log
Groups can be nested.
END
IF
True
GROUP
Log
Groups can also be nested with other control structures.
END
END
END
As the above examples demonstrates, groups can have a name, but the name is
optional. Groups can also be nested freely with each others and with other
control structures.
User keywords
are in general recommended over the
GROUP
syntax, because
they are reusable and because they simplify tests or keywords where they are
used by hiding and encapsulating lower level details. In the log file user
keywords and groups look the same, though, except that instead of a
KEYWORD
label there is a
GROUP
label.
All groups within a test or a keyword share the same variable namespace.
This means that, unlike when using keywords, there is no need to use arguments
or return values for sharing values. This can be a benefit in simple cases,
but if there are lot of variables, the benefit can turn into a problem and
cause a huge mess.
Note
The
GROUP
syntax is new in Robot Framework 7.2.
GROUP
with templates
The
GROUP
syntax can be used for grouping iterations with
test templates
:
*** Settings ***
Library
String
Test Template
Upper case should be
*** Test Cases ***
Template example
GROUP
ASCII characters
a
A
z
Z
END
GROUP
Latin-1 characters
ä
Ä
ß
SS
END
GROUP
Numbers
1
1
9
9
END
*** Keywords ***
Upper case should be
[
Arguments
] ${
char
} ${
expected
}
${
actual
} =
Convert To Upper Case
${
char
}
Should Be Equal
${
actual
} ${
expected
}
Programmatic usage
One of the primary usages for groups is making it possible to create structured
tests and user keywords programmatically. For example, the following
pre-run modifier
adds a group with two keywords at the end of each modified
test. Groups can be added also by
listeners
that use the
listener API version 3
.
from
robot.api
import
SuiteVisitor
class
GroupAdder
(
SuiteVisitor
):
def
start_test
(
self
,
test
):
group
=
test
.
body
.
create_group
(
name
=
'Example'
)
group
.
body
.
create_keyword
(
name
=
'Log'
,
args
=
[
'Hello, world!'
])
group
.
body
.
create_keyword
(
name
=
'No Operation'
)
2.10 Advanced features
2.10.1 Handling keywords with same names
Keyword scopes
Specifying a keyword explicitly
Specifying explicit priority between libraries and resources
2.10.2 Timeouts
Test case timeout
User keyword timeout
2.10.3 Parallel execution of keywords
2.10.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:
Created as a user keyword in the currently executed
suite file
.
These keywords have the highest priority and they are always used, even
if there are other keywords with the same name elsewhere.
Created in a resource file and imported either directly or
indirectly from another resource file. This is the second-highest
priority.
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.
Created in a standard library. These keywords have the lowest
priority.
Specifying a keyword explicitly
Scopes do not help if keywords with same names exists in two different libraries
or in two different resource files. In addition to that, scopes do not help if
a keyword in library should be used instead of a keyword with the same name in
a resource file. In such cases, it is possible to use
the full keyword name
,
where the keyword name is prefixed with the name of a library or a resource
and a dot is used as a separator.
With library keywords, the full name means using format
LibraryName.Keyword Name
. For example, the keyword
Get File
from the
OperatingSystem
library can be used as
OperatingSystem.Get File
, even if there was another
Get File
keyword somewhere else. If the library is implemented in a nested module, the
full name must contain the full module name like
root.sub.Library.Keyword
.
If a
custom name
is given to a library when importing it, the specified
name must be used also in the full keyword name.
With user keywords in resource files the full name is constructed the same
way as with library keywords. The name of the resource is derived from
the basename of the resource file without the file extension. For example,
a keyword
Some Keyword
in a resource file
example.resource
can
be used like
example.Some Keyword
. Note that this syntax does not
work if several resource files have the same basename. In such cases, either
resource files or keywords must be renamed.
With user keywords in a
suite file
, the full name contains only the keyword
name without any prefix.
When comparing full keyword names, the library/resource part is case and
space-insensitive and the keyword part is case, space and underscore-insensitive.
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. 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.10.2 Timeouts
Sometimes keywords may take exceptionally long time 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, the test environment
or the 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.
Test case timeout
The test case timeout can be set either by using the
Test Timeout
setting in the Setting section or the
[Timeout]
setting with
individual test cases.
Test Timeout
defines a default timeout
for all the test cases in that suite, whereas
[Timeout]
applies
a timeout to a particular 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. It is also possible to use explicit
NONE
value for this purpose. The timeout is effectively ignored also if
its value is zero or negative.
Regardless of where the test timeout is defined, the value given to it
contains the duration of the timeout. The duration must be given in Robot
Framework's
time format
, that is, either directly in seconds like
10
or in a format like
1 minute 30 seconds
. Timeouts can also be specified
as
variables
making it possible to give them, for example, from the command
line.
If there is a timeout and it expires, the keyword that is currently running
is stopped and the test case fails. Keywords executed as part of
test
teardown
are not interrupted if a test timeout occurs, though, but the test
is nevertheless marked failed. If a keyword in teardown may hang, it can be
stopped by using
user keyword timeouts
.
*** Settings ***
Test Timeout
2 minutes
*** Test Cases ***
Default timeout
[
Documentation
]
Default timeout from Settings is used.
Some Keyword
argument
Override
[
Documentation
]
Override default, use 10 seconds timeout.
[
Timeout
]
10
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
]
Disabling timeout with NONE works too and is more explicit.
[
Timeout
]
NONE
Some Keyword
argument
User keyword timeout
Timeouts can be set for user keywords using the
[Timeout]
setting.
The syntax is exactly the same as with
test case timeout
, but user keyword
timeouts do not have any default value. If a user keyword timeout is specified
using a variable, the value can be given also as a keyword argument.
*** Keywords ***
Hardcoded
[
Arguments
] ${
arg
}
[
Timeout
]
1 minute 42 seconds
Some Keyword
${
arg
}
Configurable
[
Arguments
] ${
arg
} ${
timeout
}
[
Timeout
] ${
timeout
}
Some Keyword
${
arg
}
Run Keyword with Timeout
[
Arguments
] ${
keyword
} @{
args
} &{
kwargs
} ${
timeout
}
=1 minute
[
Documentation
]
Wrapper that runs another keyword with a configurable timeout.
[
Timeout
] ${
timeout
}
Run Keyword
${
keyword
} @{
args
} &{
kwargs
}
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.
Note
With earlier Robot Framework versions it was possible to specify
a custom error message to use if a timeout expires. This
functionality was deprecated in Robot Framework 3.0.1 and removed
in Robot Framework 3.2.
2.10.3 Parallel execution of keywords
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
Process
library keywords
Start Process
and
Wait For Process
for an example.
3 Executing test cases
3.1 Basic usage
3.2 Test execution
3.3 Task execution
3.4 Post-processing outputs
3.5 Configuring execution
3.6 Output files
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
Specifying test data to be executed
3.1.2 Using command line options
Using options
Short and long options
Setting option values
Disabling options accepting no values
Simple patterns
Tag patterns
ROBOT_OPTIONS
and
REBOT_OPTIONS
environment variables
3.1.3 Test results
Command line output
Generated output files
Return codes
Errors and warnings during execution
3.1.4 Argument files
Argument file syntax
Expanding environment variables
Using argument files
Reading argument files from standard input
3.1.5 Getting help and version information
3.1.6 Creating start-up scripts
Shell script example
Batch file example
Python example
3.1.7 Making
*.robot
files executable
3.1.8 Debugging problems
Using the Python debugger (pdb)
3.1.1 Starting test execution
Synopsis
robot [options] data
python -m robot [options] data
python path/to/robot/ [options] data
Execution is normally started using the
robot
command created as part of
installation
. Alternatively it is possible to execute the installed
robot
module using the selected Python interpreter. This is especially convenient
if Robot Framework has been installed under multiple Python versions.
Finally, if you know where the installed
robot
directory exists, it can
be executed using Python as well.
Regardless of execution approach, the path (or paths) to the test data to be
executed is given as an argument after the command. Additionally, different
command line options can be used to alter the test execution or generated
outputs in many ways.
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, by default, gets its name 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
robot
script
is used, but other execution approaches could be used similarly.
robot tests.robot
robot path/to/my_tests/
robot c:\robot\tests.robot
Note
When executing a
directory
, all files and directories starting with
a dot (
.
) or an underscore (
_
) are ignored and,
by default, only files with the
.robot
extension executed.
See the
Selecting files to parse
section for more details.
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
concatenating 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:
robot my_tests.robot your_tests.robot
robot --name Example path/to/tests/pattern_*.robot
Starting from Robot Framework 6.1, it is also possible to define a
test suite initialisation file
for the automatically created top-level
suite. The path to the init file is given similarly to the
test case files:
robot __init__.robot my_tests.robot other_tests.robot
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:
robot -L debug my_tests.robot
robot --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 names are case-insensitive and hyphen-insensitive,
which facilitates writing option names in an easy-to-read format.
For example,
--SuiteStatLevel
and
--suite-stat-level
are equivalent to, but easier to read than,
--suitestatlevel
.
Note
Long options being hyphen-insensitive is new in Robot Framework 6.1.
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.
Disabling options accepting no values
Options accepting no values can be disabled by using the same option again
with
no
prefix added or dropped. The last option has precedence regardless
of how many times options are used. For example,
--dryrun --dryrun --nodryrun
--nostatusrc --statusrc
would not activate the dry-run mode and would return
normal status rc.
Simple patterns
Many command line options take arguments as
simple patterns
. These
glob-like patterns
are matched according to the following rules:
*
matches any string, even an empty string.
?
matches any single character.
[abc]
matches one character in the bracket.
[!abc]
matches one character not in the bracket.
[a-z]
matches one character from the range in the bracket.
[!a-z]
matches one character not from the range in the bracket.
Unlike with glob patterns normally, path separator characters
/
and
\
and the newline character
\n
are matches by the above
wildcards.
Unless noted otherwise, pattern matching is case, space, and underscore insensitive.
Examples:
--test Example* # Matches tests with name starting 'Example'.
--test Example[1-2] # Matches tests 'Example1' and 'Example2'.
--include f?? # Matches tests with a tag that starts with 'f' is three characters long.
All matching in above examples is case, space and underscore insensitive.
For example, the second example would also match test named
example 1
.
If the matched text happens to contain some of the wildcard characters and
they need to be matched literally, it is possible to do that by using
the
[...]
syntax. The pattern
[*]
matches the literal
*
character,
[?]
matches
?
, and
[[]
matches
[
. Lone
[
and
]
do not need to
be escaped.
Note
Support for brackets like
[abc]
and
[!a-z]
is new in
Robot Framework 3.1.
Tag patterns
Most tag related options accept arguments as
tag patterns
. They support same
wildcards as
simple patterns
(e.g.
examp??
,
ex*le
), but they also support
AND
,
OR
and
NOT
operators explained below. These operators can be
used for combining two or more individual tags or patterns together.
AND
or
&
The whole pattern matches if all individual patterns match.
AND
and
&
are equivalent:
--include fooANDbar # Matches tests containing tags 'foo' and 'bar'.
--exclude xx&yy&zz # Matches tests containing tags 'xx', 'yy', and 'zz'.
OR
The whole pattern matches if any individual pattern matches:
--include fooORbar # Matches tests containing either tag 'foo' or tag 'bar'.
--exclude xxORyyORzz # Matches tests containing any of tags 'xx', 'yy', or 'zz'.
NOT
The whole pattern matches if the pattern on the left side matches but
the one on the right side does not. If used multiple times, none of
the patterns after the first
NOT
must not match:
--include fooNOTbar # Matches tests containing tag 'foo' but not tag 'bar'.
--exclude xxNOTyyNOTzz # Matches tests containing tag 'xx' but not tag 'yy' or tag 'zz'.
The pattern can also start with
NOT
in which case the pattern matches if the pattern after
NOT
does not match:
--include NOTfoo # Matches tests not containing tag 'foo'
--include NOTfooANDbar # Matches tests not containing tags 'foo' and 'bar'
The above operators can also be used together. The operator precedence,
from highest to lowest, is
AND
,
OR
and
NOT
:
--include xANDyORz # Matches tests containing either tags 'x' and 'y', or tag 'z'.
--include xORyNOTz # Matches tests containing either tag 'x' or 'y', but not tag 'z'.
--include xNOTyANDz # Matches tests containing tag 'x', but not tags 'y' and 'z'.
Although tag matching itself is case-insensitive, all operators are
case-sensitive and must be written with upper case letters. If tags themselves
happen to contain upper case
AND
,
OR
or
NOT
, they need to specified
using lower case letters to avoid accidental operator usage:
--include port # Matches tests containing tag 'port', case-insensitively
--include PORT # Matches tests containing tag 'P' or 'T', case-insensitively
--exclude handoverORportNOTnotification
ROBOT_OPTIONS
and
REBOT_OPTIONS
environment variables
Environment variables
ROBOT_OPTIONS
and
REBOT_OPTIONS
can be
used to specify default options for
test execution
and
result
post-processing
, respectively. The options and their values must be
defined as a space separated list and they are placed in front of any
explicit options on the command line. The main use case for these
environment variables is setting global default values for certain options to
avoid the need to repeat them every time tests are run or Rebot used.
export
ROBOT_OPTIONS
=
"--outputdir results --tagdoc 'mytag:Example doc with spaces'"
robot
tests.robot
export
REBOT_OPTIONS
=
"--reportbackground blue:red:yellow"
rebot
--name
example
output.xml
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 tests, 1 passed, 1 failed
==============================================================================
Output: /path/to/output.xml
Report: /path/to/report.html
Log: /path/to/log.html
There is also a notification on the console
whenever a top-level keyword in a test case ends. A green dot is used if
a keyword passes and a red F if it fails. These markers are written to the end
of line and they are overwritten by the test status when the test itself ends.
Writing the markers is disabled if console output is redirected to a file.
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 execution status to the
system running them using return codes. When the execution starts
successfully and no tests fail, the return code is zero.
All possible return codes are explained in the table below.
Possible return codes
RC
Explanation
0
All tests passed.
1-249
Returned number of tests failed.
250
250 or more failures.
251
Help or version information printed.
252
Invalid data or command line option.
253
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 the Bash shell the return code is in the
$?
variable, and in Windows it is in the
%ERRORLEVEL%
variable. If you use some external tool for running tests, consult its
documentation for how to get the return code.
The return code can be set to zero regardless the execution status by 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 execution can be determined.
Note
Same return codes are also used with
Rebot
.
Note
When
getting help and version information
, the
--nostatusrc
option has an effect only with Robot Framework 7.4 and newer.
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 and warnings are generated by Robot
Framework itself, but libraries can also log
errors and 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.robot' in table 'Setting' in element on row 2: Resource file 'resource.robot' does not exist
20090322 19:58:43.931
WARN
Keyword 'SomeLibrary.Example Keyword' is deprecated. Use keyword `Other Keyword` instead.
3.1.4 Argument files
Argument files allow placing all or some command line options and arguments
into an external file where they will be read. This avoids the problems with
characters that are problematic on the command line. If lot of options or
arguments are needed, argument files also prevent the command that is used on
the command line growing too long.
Argument files are taken into use with
--argumentfile (-A)
option
along with possible other command line options.
Note
Unlike other
long command line options
,
--argumentfile
cannot be given in shortened format like
--argumentf
.
Argument file syntax
Argument files can contain both command line options and paths to the executed data,
one option or a data source per line. Both short and long options are supported,
but the latter are recommended in this context because they are easier to understand.
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 NAME:Hello, world!
# This is a comment
path/to/my/tests
In the above example the separator between options and their values is a single
space. It is possible to use either an equal
sign (=) or any number of spaces. As an example, the following three lines are
identical:
--name An Example
--name=An Example
--name An Example
If argument files contain non-ASCII characters, they must be saved using
the UTF-8 encoding. Argument files can use any extension. Typically
.txt
works fine, but a custom extension like
.args
can be used to separate
argument files from normal text files.
Expanding environment variables
Starting from Robot Framework 7.4, it is possible to use environment variables
in argument files and get them replaced
before
files are processed otherwise.
For backwards compatibility reasons, this functionality is not enabled by default,
but it is easy to opt-in by starting an argument file with a line
# expandvars: true
.
The functionality may be enabled by default in the future, and it is possible
to opt-out already now by using
# expandvars: false
.
Environment variables can be used in format
$NAME
and
${NAME}
. In addition to
that, default values are supported like
${NAME=default}
. If a literal dollar sign
is needed, it can be escaped by doubling it like
$$not_var
:
# expandvars: true
--name $NAME
--doc ${NAME}v${VERSION}
--metadata Default:${META=default value}
--metadata Escape:$$100
Environment variables are not limited to option values. They can also contain
option names, both names and values, and using the comment character even enables
conditional options:
# expandvars: true
--${NAME} ${VALUE}
${NAME_AND_VALUE}
${COND1=} --metadata COND1:This is enabled by default. Set 'COND1' to '#' to disable.
${COND2=#} --metadata COND2:This is disabled by default. Set 'COND2' to '' to enable.
Environment variable names are case-sensitive, limited to ASCII letters, numbers
and underscores, and they cannot start with a number. Using a non-existing variable
or an invalid variable name causes an error.
Using argument files
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. When
an argument file is used with other arguments, its contents are placed into
the original list of arguments to the same place where the argument file
option was. This means that options in argument files can override options
before it, and its options can be overridden by options after it. It is possible
to use
--argumentfile
option multiple times or even recursively:
robot --argumentfile all_options_and_arguments.txt
robot --argumentfile defaults.args --name Example tests.robot
robot -A first.txt -A second.txt -A third.txt tests.robot
Reading argument files from standard input
Special argument file name
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 | robot --argumentfile STDIN
generate_arguments.sh | robot --name Example --argumentfile STDIN tests.robot
3.1.5 Getting help and version information
Both when executing tests and when post-processing outputs, it is possible
to get command line help with the option
--help (-h)
.
This help text provides version information, a short general introduction
and explanation of the available command line options.
It is also possible to get just the version information with
the option
--version
. This information also contains Python
version and the platform type:
$ robot --version
Robot Framework 7.4 (Python 3.14.0 on linux)
C:\>rebot --version
Rebot 7.3.1 (Python 3.13.7 on win32)
When help or version information is printed to the console, the execution
exits with a special
return code
251 by default. Starting from Robot
Framework 7.4, the return code can be changed to zero by using the
--nostatusrc
option like
robot --version --nostatusrc
.
3.1.6 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.
Shell script example
In this example, the same web tests in the
login
directory are executed
with different browsers and the results combined afterwards using
Rebot
.
The script also accepts command line options itself and simply forwards them
to the
robot
command using the handy
$*
variable:
#!/bin/bash
robot
--name
Firefox
--variable
BROWSER:Firefox
--output
out/fx.xml
--log
none
--report
none
$*
login
robot
--name
IE
--variable
BROWSER:IE
--output
out/ie.xml
--log
none
--report
none
$*
login
rebot
--name
Login
--outputdir
out
--output
login.xml
out/fx.xml
out/ie.xml
Batch file example
Implementing the above shell script example using batch files is not very
complicated either. Notice that arguments to batch files can be forwarded
to executed commands using
%*
:
@
echo
off
robot --name Firefox --variable BROWSER:Firefox --output out\fx.xml --log none --report none
%*
login
robot --name IE --variable BROWSER:IE --log none --output out\ie.xml --report none
%*
login
rebot --name Login --outputdir out --output login.xml out\fx.xml out\ie.xml
Note
Prior to Robot Framework 3.1
robot
and
rebot
commands were
implemented as batch files on Windows and using them in another
batch file required prefixing the whole command with
call
.
Python example
When start-up scripts gets more complicated, implementing them using shell
scripts or batch files is not that convenient. This is especially true if
both variants are needed and same logic needs to be implemented twice. In
such situations it is often better to switch to Python. It is possible to
execute Robot Framework from Python using the
subprocess module
, but
often using Robot Framework's own
programmatic API
is more convenient.
The easiest APIs to use are
robot.run_cli
and
robot.rebot_cli
that
accept same command line arguments than the
robot
and
rebot
commands.
The following example implements the same logic as the earlier shell script
and batch file examples. In Python arguments to the script itself are
available in
sys.argv
:
#!/usr/bin/env python
import
sys
from
robot
import
run_cli
,
rebot_cli
common
=
[
'--log'
,
'none'
,
'--report'
,
'none'
]
+
sys
.
argv
[
1
:]
+
[
'login'
]
run_cli
([
'--name'
,
'Firefox'
,
'--variable'
,
'BROWSER:Firefox'
,
'--output'
,
'out/fx.xml'
]
+
common
,
exit
=
False
)
run_cli
([
'--name'
,
'IE'
,
'--variable'
,
'BROWSER:IE'
,
'--output'
,
'out/ie.xml'
]
+
common
,
exit
=
False
)
rebot_cli
([
'--name'
,
'Login'
,
'--outputdir'
,
'out'
,
'out/fx.xml'
,
'out/ie.xml'
])
Note
exit=False
is needed because by default
run_cli
exits to
system with the correct
return code
.
rebot_cli
does that too,
but in the above example that is fine.
3.1.7 Making
*.robot
files executable
On UNIX-like operating systems it is possible to make
*.robot
files executable by giving them execution permission and adding a
shebang
like in this example:
#!/usr/bin/env robot
*** Test Cases ***
Example
Log to console
Executing!
If the above content would be in a file
example.robot
and that file
would be executable, it could be executed from the command line like below.
Starting from Robot Framework 3.2, individually executed files can have any
extension, or no extension at all, so the same would work also if the file
would be named just
example
.
./example.robot
This trick does not work when executing a directory but can be handy when
executing a single file. It is probably more often useful when
automating tasks
than when automating tests.
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 library keyword.
Logged tracebacks do not contain information about methods inside Robot
Framework itself. If you suspect an error is caused by a bug in the framework,
you can enable showing internal traces by setting environment variable
ROBOT_INTERNAL_TRACES
to any non-empty value.
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.
Using the Python debugger (pdb)
It is also possible to use the
pdb
module from the Python standard
library to set a break point and interactively debug a running test.
The typical way of invoking pdb by inserting:
import
pdb
;
pdb
.
set_trace
()
at the location you want to break into debugger will not work correctly
with Robot Framework, as the standard output stream is
redirected during keyword execution. Instead, you can use the following:
import
sys
,
pdb
;
pdb
.
Pdb
(
stdout
=
sys
.
__stdout__
)
.
set_trace
()
from within a python library or alternatively:
Evaluate
pdb.Pdb(stdout=sys.__stdout__).set_trace()
modules=sys, pdb
can be used directly in a test case.
3.2 Test execution
This section describes how the test suite structure created from the parsed
test data is executed, how test status is determined, and how to continue
executing a test case if there are failures, and how to stop the whole test
execution gracefully.
3.2.1 Execution flow
Executed suites and tests
Setups and teardowns
Execution order
3.2.2 Test and suite statuses
PASS
FAIL
SKIP
Migrating from criticality to SKIP
Suite status
3.2.3 Continuing on failure
Execution continues on teardowns automatically
All top-level keywords are executed when tests have templates
Special failures from keywords
Run Keyword And Continue On Failure
keyword
Enabling continue-on-failure using tags
Disabling continue-on-failure using tags
TRY/EXCEPT
BuiltIn keywords
3.2.4 Stopping test execution gracefully
Pressing
Ctrl-C
Using signals
Using keywords
Stopping when first test case fails
Stopping using
robot:exit-on-failure
tag
Stopping on parsing or execution error
Handling teardowns
3.2.1 Execution flow
Executed suites and tests
Test cases are always executed within a test suite. A test suite
created from a
suite 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 used on
test suite
,
test case
and
user keyword
levels.
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 contain are marked 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 test setup 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.
User keyword setup
User keyword setup is executed before the keyword body. If the setup fails,
the body is not executed. There is not much difference between the keyword
setup and the first keyword in the body.
Note
User keyword setups are new in Robot Framework 7.0.
User keyword teardown
User keyword teardown is run after the keyword is executed otherwise, regardless
the status. User keyword teardowns are executed fully even if some of their
keywords would 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.robot -> My Suite
02__another_suite.robot -> 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
--randomize
option.
3.2.2 Test and suite statuses
This section explains how tests can get
PASS
,
FAIL
or
SKIP
status and how the
suite status
is determined based on test statuses.
Note
The SKIP status is new in Robot Framework 4.0.
PASS
A test gets the PASS status if it is executed and none of the keywords it contains fails.
Prematurely passing tests
Normally all keywords are executed, but it is also possible to use
BuiltIn
keywords
Pass Execution
and
Pass Execution If
to stop
execution with the PASS status and not run the remaining keywords.
How
Pass Execution
and
Pass Execution If
behave
in different situations is explained below:
When used in any
setup or teardown
(suite, test or keyword), these
keywords pass that setup or teardown. Possible teardowns of the started
keywords are executed. Test execution or statuses are not affected otherwise.
When used in a test case outside setup or teardown, the keywords pass that
particular test case. Possible test and keyword teardowns are executed.
Possible
continuable failures
that occur before these keyword are used,
as well as failures in teardowns executed afterwards, will fail the execution.
It is mandatory to give an explanation message
why execution was interrupted, and it is also possible to
modify test case tags. For more details, and usage examples, see the
documentation of these keywords
.
Passing execution in the middle of a test, setup or teardown should be
used with care. In the worst case it leads to tests that skip all the
parts that could actually uncover problems in the tested application.
In cases where execution cannot continue do to external factors,
it is often safer to
skip
the test.
FAIL
The most common reason for a test to get the FAIL status is that one of the keywords
it contains fails. The keyword itself can fail by
raising an exception
or the
keyword can be called incorrectly. Other reasons for failures include syntax errors
and the test being empty.
If a
suite setup
fails, tests in that suite are marked failed without running them.
If a
suite teardown
fails, tests are marked failed retroactively.
SKIP
Starting from Robot Framework 4.0, tests can get also SKIP status in addition to
PASS and FAIL. There are many different ways to get this status.
Skipping before execution
The command line option
--skip
can be used to skip specified tests without
running them at all. It works based on
tags
and supports
tag patterns
like
examp??
and
tagANDanother
. If it is used multiple times, all tests matching any of
specified tags or tag patterns are skipped:
--skip require-network
--skip windowsANDversion9?
--skip python2.* --skip python3.[0-6]
Tests can also be skipped by tagging the test with the
robot:skip
reserved tag
.
This tag can also be set using a variable, which allows skipping test dynamically
during execution.
*** Variables ***
${
SKIP
}
robot:skip
*** Test Cases ***
Literal
[
Documentation
]
Unconditionally skipped.
[
Tags
]
robot:skip
Log
This is not executed
As variable
[
Documentation
]
Skipped unless
${
SKIP
}
is set to a different value.
[
Tags
] ${
SKIP
}
Log
This is not executed by default
The difference between
--skip
and
--exclude
is that with
the latter tests are
omitted from the execution altogether
and they will not
be shown in logs and reports. With the former they are included, but not actually
executed, and they will be visible in logs and reports.
Note
robot:skip
is new in Robot Framework 5.0.
Note
Support for using variables with tags used for skipping is new in
Robot Framework 7.2.
Skipping dynamically during execution
Tests can get the skip status during execution in various ways:
Using the
BuiltIn
keyword
Skip
anywhere in the test case, including setup or
teardown. Using
Skip
keyword has two effects: the test gets the SKIP status
and rest of the test is not executed. However, if the test has a teardown, it will be
run.
Using the
BuiltIn
keyword
Skip If
which takes a condition and skips the test
if the condition is true.
Library keywords
may also trigger skip behavior by using a special exceptions.
This is explained the
Skipping tests
section in the
Creating test libraries
chapter.
If
suite setup
is skipped using any of the above means, all tests in the suite
are skipped without executing them.
If
suite teardown
is skipped, all tests will be marked skipped retroactively.
Automatically skipping failed tests
The command line option
--skiponfailure
can be used to automatically mark
failed tests skipped. It works based on
tags
and supports
tag patterns
like
the
--skip
option discussed above:
--skiponfailure not-ready
--skiponfailure experimentalANDmobile
Starting from RF 5.0, the reserved tag
robot:skip-on-failure
can alternatively be used to
achieve the same effect as above:
*** Test Cases ***
Example
[
Tags
]
robot:skip-on-failure
Fail
this test will be marked as skipped instead of failed
The motivation for this functionality is allowing execution of tests that are not yet
ready or that are testing a functionality that is not yet ready. Instead of such tests
failing, they will be marked skipped and their tags can be used to separate them
from possible other skipped tests.
Migrating from criticality to SKIP
Earlier Robot Framework versions supported criticality concept that allowed marking
tests critical or non-critical. By default all tests were critical, but the
--critical
and
--noncritical
options could be used to configure that.
The difference between critical and non-critical tests was that non-critical tests
were not included when determining the final status for an executed test suite or
for the whole test run. In practice the test status was two dimensional having
PASS and FAIL in one axis and criticality on the other.
Non-critical failed tests were in many ways similar to the current skipped tests.
Because these features are similar and having both SKIP and criticality would
have created strange test statuses like non-critical SKIP, the criticality concept
was removed in Robot Framework 4.0 when the SKIP status was introduced. The problems
with criticality are explained in more detail in the
issue that proposed removing it
.
The main use case for the criticality concept was being able to run tests that
are not yet ready or that are testing a functionality that is not yet ready. This
use case is nowadays covered by the skip-on-failure functionality discussed in
the previous section.
To ease migrating from criticality to skipping, the old
--noncritical
option worked as an alias for the new
--skiponfailure
in Robot Framework 4.0
and also the old
--critical
option was preserved. Both old options
were deprecated and they were removed in Robot Framework 5.0.
Suite status
Suite status is determined solely based on statuses of the tests it contains:
If any test has failed, suite status is FAIL.
If there are no failures but at least one test has passed, suite status is PASS.
If all tests have been skipped or the are no tests at all, suite status is SKIP.
3.2.3 Continuing 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 a drawback that often
subsequent keywords would give more information about the state of the
system, though, and in some cases those subsequent keywords would actually
take care of the needed cleanup activities. Hence Robot Framework offers
several features to continue even if there are failures.
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 enabled in
suite, test and keyword
teardowns
. In practice this means that in teardowns all the
keywords in all levels are always executed.
If this behavior is not desired, the special
robot:stop-on-failure
and
robot:recursive-stop-on-failure
tags can be used to
disable it
.
All top-level keywords are executed when tests have templates
When using
test templates
, all the top-level keywords are executed to
make it sure that all the different combinations are covered. In this
usage continuing is limited to the top-level keywords, and inside them
the execution ends normally if there are non-continuable failures.
*** Test Cases ***
Continue with templates
[
Template
]
Should be Equal
this
fails
this
is run
If this behavior is not desired, the special
robot:stop-on-failure
and
robot:recursive-stop-on-failure
tags can be used to
disable it
.
Special failures from keywords
Library keywords
report failures using exceptions, and it is
possible to use special exceptions to tell Robot Framework that
execution can continue regardless the failure. How these exceptions
can be created is explained in the
Continuable failures
section in
the
Creating test libraries
section.
When a test ends and there have been continuable failures,
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 a continuable
failure. 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 discussed above.
*** Test Cases ***
Example
Run Keyword and Continue on Failure
Should be Equal
1
2
Log
This is executed but test fails in the end
TRY/EXCEPT
Robot Framework 5.0 introduced native
TRY/EXCEPT
syntax that can be used for
handling failures:
*** Test Cases ***
Example
TRY
Some Keyword
EXCEPT
Expected error message
Error Handler Keyword
END
For more details see the separate
TRY/EXCEPT syntax
section.
BuiltIn keywords
There are several
BuiltIn
keywords that can be used to execute other keywords
so that execution can continue after possible failures:
Run Keyword And Expect Error
executes a keyword and expects it to fail
with the specified error message. The aforementioned
TRY/EXCEPT
syntax is
nowadays generally recommended instead.
Run Keyword And Ignore Error
executes a keyword and silences possible
error. It returns the status along with possible keyword return value or
error message. The
TRY/EXCEPT
syntax generally works better in this case
as well.
Run Keyword And Warn On Failure
is a wrapper for
Run Keyword And Ignore Error
that automatically logs a warning
if the executed keyword fails.
Run Keyword And Return Status
executes a keyword and returns Boolean
True
or
False
depending on did it pass or fail.
3.2.4 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.
The tests that are automatically failed get
robot:exit
tag and
the generated report will include
NOT robot:exit
combined tag pattern
to easily see those tests that were not skipped. Note that the test in which
the exit happened does not get the
robot:exit
tag.
Note
Prior to Robot Framework 3.1, the special tag was named
robot-exit
.
Pressing
Ctrl-C
The execution is stopped when
Ctrl-C
is pressed in the console
where the tests are running. The execution is stopped immediately,
but reports and logs are still generated.
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.
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.
Stopping when first test case fails
If option
--exitonfailure (-X)
is used, the whole execution stops
immediately if any test fails.
Stopping using
robot:exit-on-failure
tag
If a failed test has a
special
robot:exit-on-failure
tag, the whole execution
stops immediately after that test.
Note
This functionality is new in Robot Framework 7.2.
Stopping on parsing or execution error
Robot Framework separates
failures
caused by failing keywords from
errors
caused by, for example, invalid settings or failed test library imports.
By default these errors are reported as
test execution errors
, but errors
themselves do not fail tests or affect execution otherwise. If
--exitonerror
option is used, however, all such errors are considered
fatal and execution stopped so that remaining tests are marked failed. With
parsing errors encountered before execution even starts, this means that no
tests are actually run.
Note
Also logging something with the
ERROR
log level
is considered
an error and stops the execution if the
--exitonerror
option
is used.
Handling teardowns
By default teardowns of the tests and suites that have been started are
executed even if the test execution is stopped using one of the methods
above. This allows clean-up activities to be run regardless how execution
ends.
It is also possible to skip teardowns when execution is stopped by using
--skipteardownonexit
option. This can be useful if, for example,
clean-up tasks take a lot of time.
3.3 Task execution
Robot Framework can be used also for other automation purposes than test
automation, and starting from Robot Framework 3.1 it is possible to
explicitly
create
and execute tasks. For most parts task execution
and test execution work the same way, and this section explains the
differences.
3.3.1 Generic automation mode
3.3.2 Task related command line options
3.3.1 Generic automation mode
When Robot Framework is used execute a file and it notices that the file
has tasks, not tests, it automatically sets itself into the generic automation
mode. This mode does not change the actual execution at all, but when
logs and reports are created, they use term
task
, not
test
. They have,
for example, headers like
Task Log
and
Task Statistics
instead of
Test Log
and
Test Statistics
.
The generic automation mode can also be enabled by using the
--rpa
option. In that case the executed files can have either tests or tasks.
Alternatively
--norpa
can be used to force the test automation
mode even if executed files contain tasks. If neither of these options are
used, it is an error to execute multiple files so that some have tests and
others have tasks.
The execution mode is stored in the generated
output file
and read by
Rebot
if outputs are post-processed. The mode can also
be set when
using Rebot
if necessary.
3.4 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, and using it
separately allows creating custom reports and logs as well as combining
and merging results.
3.4.1 Using Rebot
Synopsis
Specifying options and arguments
Return codes with Rebot
Controlling execution mode
3.4.2 Creating reports, logs and output files
3.4.3 Combining outputs
3.4.4 Merging outputs
Merging re-executed tests
Merging suites executed in pieces
3.4.5 JSON output files
3.4.1 Using Rebot
Synopsis
rebot [options] outputs
python -m robot.rebot [options] outputs
python path/to/robot/rebot.py [options] outputs
The most common way to use Rebot is using the
rebot
command.
Alternatively it is possible to execute the installed
robot.rebot
module or the
robot/rebot.py
file using the selected Python
interpreter.
Specifying options and arguments
The basic syntax for using Rebot is exactly the same as when
starting test execution
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.
Return codes with Rebot
Return codes from Rebot are exactly same as when
running tests
.
Controlling execution mode
Rebot notices have
tests
or
tasks
been run, and by default preserves the
execution mode. The mode affects logs and reports so that in the former case
they will use term
test
like
Test Log
and
Test Statistics
, and in
the latter case term
task
like
Task Log
and
Task Statistics
.
Rebot also supports using
--rpa
or
--norpa
options to set
the execution mode explicitly. This is necessary if multiple output files
are processed and they have conflicting modes.
3.4.2 Creating reports, logs and output files
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:
rebot output.xml
rebot path/to/output_file.xml
rebot --include smoke --name Smoke_Tests c:\results\output.xml
Another common usage is creating only the output file when running tests
(log and report generation can be disabled with
--log NONE
--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.
Rebot does not create XML output files by default, but it is possible to
create them by using the
--output (-o)
option. Log and report
are created by default, but they can be disabled by using value
NONE
(case-insensitive) if they are not needed:
rebot --include smoke --output smoke.xml --log none --report none original.xml
3.4.3 Combining outputs
An important feature in 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.4 Merging outputs
If same tests are re-executed or a single test suite executed in pieces,
combining results like discussed above creates an unnecessary top-level
test suite. In these cases it is typically better to merge results instead.
Merging is done by using
--merge (-R)
option which changes the way how
Rebot combines two or more output files. This option itself takes no
arguments and all other command line options can be used with it normally:
rebot --merge original.xml merged.xml
rebot --merge --name Example first.xml second.xml third.xml
When suites are merged, documentation, suite setup and suite teardown are got
from the last merged suite. Suite metadata from all merged suites is preserved
so that values in latter suites have precedence.
How merging tests works is explained in the following sections discussing
the two main merge use cases.
Note
Getting suite documentation and metadata from merged suites is new in
Robot Framework 6.0.
Merging re-executed tests
There is often a need to re-execute a subset of tests, for example, after
fixing a bug in the system under test or in the tests themselves. This can be
accomplished by
selecting test cases
by names (
--test
and
--suite
options), tags (
--include
and
--exclude
),
or by previous status (
--rerunfailed
or
--rerunfailedsuites
).
Combining re-execution results with the original results using the default
combining outputs
approach does not work too well. The main problem is
that you get separate test suites and possibly already fixed failures are
also shown. In this situation it is better to use
--merge (-R)
option to tell Rebot to merge the results instead. In practice this
means that tests from the latter test runs replace tests in the original.
An exception to this rule is that
skipped
tests in latter runs are ignored
and original tests preserved.
This usage is best illustrated by a practical example using
--rerunfailed
and
--merge
together:
robot --output original.xml tests # first execute all tests
robot --rerunfailed original.xml --output rerun.xml tests # then re-execute failing
rebot --merge original.xml rerun.xml # finally merge results
The message of the merged tests contains a note that results have been
replaced. The message also shows the old status and message of the test.
Merged results must always have same top-level test suite. Tests and suites
in merged outputs that are not found from the original output are added into
the resulting output. How this works in practice is discussed in the next
section.
Note
Ignoring skipped tests in latter runs is new in Robot Framework 4.1.
Merging suites executed in pieces
Another important use case for the
--merge
option is merging results
got when running a test suite in pieces using, for example,
--include
and
--exclude
options:
robot --include smoke --output smoke.xml tests # first run some tests
robot --exclude smoke --output others.xml tests # then run others
rebot --merge smoke.xml others.xml # finally merge results
When merging outputs like this, the resulting output contains all tests and
suites found from all given output files. If some test is found from multiple
outputs, latest results replace the earlier ones like explained in the previous
section. Also this merging strategy requires the top-level test suites to
be same in all outputs.
3.4.5 JSON output files
Rebot can create and process output files also in the
JSON
format.
Creating JSON output files is done using the normal
--output
option
so that the specified file has a
.json
extension:
rebot --output output.json output.xml
When reading output files, JSON files are automatically recognized by
the extension:
rebot output.json
rebot output1.json output2.json
When combining or merging results, it is possible to mix JSON and XML output files:
rebot output1.xml output2.json
rebot --merge original.xml rerun.json
The JSON output file structure is documented in the
result.json
schema file
.
Note
Support for JSON output files is new in Robot Framework 7.0.
Prior to Robot Framework 7.2 JSON output files contained only
information about the executed suite, but nowadays they contain
the same result data as
XML output files
.
3.5 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.5.1 Selecting files to parse
Executing individual files
Included and excluded files
Selecting files by name or path
Selecting files by extension
Using custom parsers
3.5.2 Selecting test cases
By test names
By suite names
By tag names
Re-executing failed test cases
Re-executing failed test suites
When no tests match selection
3.5.3 Setting metadata
Setting suite name
Setting suite documentation
Setting free suite metadata
Setting test tags
3.5.4 Configuring where to search libraries and other extensions
Locations automatically in module search path
PYTHONPATH
Using
--pythonpath
option
Configuring
sys.path
programmatically
3.5.5 Setting variables
3.5.6 Dry run
3.5.7 Randomizing execution order
3.5.8 Programmatic modification of test data
Example: Select every Xth test
Example: Exclude tests by name
Example: Disable setups and teardowns
3.5.9 Controlling console output
Console output type
Console width
Console colors
Console links
Console markers
3.5.10 Setting listeners
3.5.1 Selecting files to parse
Executing individual files
When executing individual files, Robot Framework tries to parse and run them
regardless the name or the file extension. What parser to use depends
on the extension:
.robot
files and files that are not recognized are parsed using
the normal
Robot Framework parser
.
.rst
and
.rest
files are parsed using the
reStructuredText parser
.
.rbt
and
.json
files are parsed using the
JSON parser
.
Files supported by
custom parsers
are parsed by a matching parser.
Examples:
robot example.robot # Standard Robot Framework parser.
robot example.tsv # Must be compatible with the standard parser.
robot example.rst # reStructuredText parser.
robot x.robot y.rst # Parse both files using an appropriate parser.
Included and excluded files
When executing a
directory
, files and directories are parsed using
the following rules:
All files and directories starting with a dot (
.
) or an underscore
(
_
) are ignored.
.robot
files are parsed using the normal
Robot Framework parser
.
.robot.rst
files are parsed using the
reStructuredText parser
.
.rbt
files are parsed using the
JSON parser
.
Files supported by
custom parsers
are parsed by a matching parser.
Other files are ignored unless parsing them has been enabled by using
the
--parseinclude
or
--extension
options discussed
in the subsequent sections.
Selecting files by name or path
When executing a directory, it is possible to parse only certain files based on
their name or path by using the
--parseinclude (-I)
option. This option
has slightly different semantics depending on the value it is used with:
If the value is just a file name like
example.robot
, files matching
the name in all directories will be parsed.
To match only a certain file in a certain directory, files can be given
as relative or absolute paths like
path/to/tests.robot
.
If the value is a path to a directory, all files inside that directory are parsed,
recursively.
Examples:
robot --parseinclude example.robot tests # Parse `example.robot` files anywhere under `tests`.
robot -I example_*.robot -I ???.robot tests # Parse files matching `example_*.robot` or `???.robot` under `tests`.
robot -I tests/example.robot tests # Parse only `tests/example.robot`.
robot --parseinclude tests/example tests # Parse files under `tests/example` directory, recursively.
Values used with
--parseinclude
are case-insensitive and support
glob patterns
like
example_*.robot
. There are, however,
two small differences compared to how patterns typically work with Robot Framework:
*
matches only a single path segment. For example,
path/*/tests.robot
matches
path/to/tests.robot
but not
path/to/nested/tests.robot
.
**
can be used to enable recursive matching. For example,
path/**/tests.robot
matches both
path/to/tests.robot
and
path/to/nested/tests.robot
.
If the pattern contains an extension, files with that extension are parsed
even if they by
default would not be
. What parser to use depends on
the used extension:
.rst
and
.rest
files are parsed using the
reStructuredText parser
.
.json
files are parsed using the
JSON parser
.
Other files are parsed using the normal
Robot Framework parser
.
Notice that when you use a pattern like
*.robot
and there exists a file that
matches the pattern in the execution directory, the shell may resolve
the pattern before Robot Framework is called and the value passed to
it is the file name, not the original pattern. In such cases you need
to quote or escape the pattern like
'*.robot'
or
\*.robot
.
Note
--parseinclude
is new in Robot Framework 6.1.
Selecting files by extension
In addition to using the
--parseinclude
option discussed in the
previous section, it is also possible to enable parsing files that are
not
parsed by default
by using the
--extension (-F)
option.
Matching extensions is case insensitive and the leading dot can be omitted.
If there is a need to parse more than one kind of files, it is possible to
use a colon
:
to separate extensions:
robot --extension rst path/to/tests # Parse only *.rst files.
robot -F robot:rst path/to/tests # Parse *.robot and *.rst files.
The above is equivalent to the following
--parseinclude
usage:
robot --parseinclude *.rst path/to/tests
robot -I *.robot -I *.rst path/to/tests
Because the
--parseinclude
option is more powerful and covers all
same use cases as the
--extension
option, the latter is likely to be
deprecated in the future. Users are recommended to use
--parseinclude
already now.
Using custom parsers
External parsers can parse files that Robot Framework does not recognize
otherwise. For more information about creating and using such parsers see
the
Parser interface
section.
3.5.2 Selecting test cases
Robot Framework offers several command line options for selecting
which test cases to execute. The same options work also when
executing
tasks
and when post-processing outputs with
Rebot
.
By test names
The easiest way to select only some tests to be run is using the
--test (-t)
option. As the name implies, it can be used for
selecting tests by their names. Given names are case, space and underscore
insensitive and they also support
simple patterns
. The option can be
used multiple times to match multiple tests:
--test Example # Match only tests with name 'Example'.
--test example* # Match tests starting with 'example'.
--test first --test second # Match tests with name 'first' or 'second'.
To pinpoint a test more precisely, it is possible to prefix the test name
with a suite name:
--test mysuite.mytest # Match test 'mytest' in suite 'mysuite'.
--test root.sub.test # Match test 'test' in suite 'sub' in suite 'root'.
--test *.sub.test # Match test 'test' in suite 'sub' anywhere.
Notice that when the given name includes a suite name, it must match the whole
suite name starting from the root suite. Using a wildcard as in the last example
above allows matching tests with a parent suite anywhere.
Using the
--test
option is convenient when only a few tests needs
to be selected. A common use case is running just the test that is currently
being worked on. If a bigger number of tests needs to be selected,
it is typically easier to select them
by suite names
or
by tag names
.
When
executing tasks
, it is possible to use the
--task
option
as an alias for
--test
.
By suite names
Tests can be selected also by suite names with the
--suite (-s)
option that selects all tests in matching suites. Similarly
as with
--test
, given names are case, space and underscore
insensitive and support
simple patterns
. To pinpoint a suite
more precisely, it is possible to prefix the name with the parent suite
name:
--suite Example # Match only suites with name 'Example'.
--suite example* # Match suites starting with 'example'.
--suite first --suite second # Match suites with name 'first' or 'second'.
--suite root.child # Match suite 'child' in root suite 'root'.
--suite *.parent.child # Match suite 'child' with parent 'parent' anywhere.
If the name contains a parent suite name, it must match the whole suite name
the same way as with
--test
. Using a wildcard as in the last example
above allows matching suites with a parent suite anywhere.
Note
Prior to Robot Framework 7.0,
--suite
with a parent suite
did not need to match the whole suite name. For example,
parent.child
would match suite
child
with parent
parent
anywhere. The name must
be prefixed with a wildcard if this behavior is desired nowadays.
If both
--suite
and
--test
options are used, only the
specified tests in specified suites are selected:
--suite mysuite --test mytest # Match test 'mytest' if its inside suite 'mysuite'.
Using the
--suite
option is more or less the same as executing
the appropriate suite file or directory directly. The main difference is
that if a file or directory is run directly, possible higher level
suite initialization files
are ignored:
# Root suite is 'Tests' and its possible initialization file is used.
robot --suite example path/to/tests
# Root suite is 'Example' and higher level initialization files are ignored.
robot path/to/tests/example.robot
Prior to Robot Framework 6.1, files not matching the
--suite
option
were not parsed at all for performance reasons. This optimization was not
possible anymore after suites got a new
Name
setting that can override
the default suite name that is got from the file or directory name. New
--parseinclude
option has been added to
explicitly select which
files are parsed
if this kind of parsing optimization is needed.
By tag names
It is possible to include and exclude test cases by
tag
names with the
--include (-i)
and
--exclude (-e)
options, respectively.
If the
--include
option is used, only test cases having a matching
tag are selected, and with the
--exclude
option 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. In that case a test is selected
if it has a tag that matches any included tags, and also has no tag
that matches any excluded tags.
In addition to specifying a tag to match fully, it is possible to use
tag patterns
where
*
and
?
are wildcards and
AND
,
OR
, and
NOT
operators can be used for
combining individual tags or patterns together:
--include feature-4?
--exclude bug*
--include fooANDbar
--exclude xxORyyORzz
--include fooNOTbar
Another way to exclude tests by tags is using the
robot:exclude
reserved tag
.
This tag can also be set using a variable, which allows excluding test
dynamically during execution.
*** Variables ***
${
EXCLUDE
}
robot:exclude
*** Test Cases ***
Literal
[
Documentation
]
Unconditionally excluded.
[
Tags
]
robot:exclude
Log
This is not executed
As variable
[
Documentation
]
Excluded unless
${
EXCLUDE
}
is set to a different value.
[
Tags
] ${
EXCLUDE
}
Log
This is not executed by default
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, often called smoke
tests, can be tagged with
smoke
and executed with
--include smoke
.
Unfinished test can be committed to version control with a tag such as
not_ready
and excluded from the test execution with
--exclude not_ready
.
Tests can be tagged with
sprint-<num>
, where
<num>
specifies the number of the current sprint, and
after executing all test cases, a separate report containing only
the tests for a certain sprint can be generated (for example,
rebot
--include sprint-42 output.xml
).
Options
--include
and
--exclude
can be used in combination
with
--suite
and
--test
discussed in the previous section.
In that case tests that are selected must match all selection criteria:
--suite example --include tag # Match test if it is in suite 'example' and has tag 'tag'.
--suite example --exclude tag # Match test if it is in suite 'example' and does not have tag 'tag'.
--test ex* --include tag # Match test if its name starts with 'ex' and it has tag 'tag'.
--test ex* --exclude tag # Match test if its name starts with 'ex' and it does not have tag 'tag'.
Note
robot:exclude
is new in Robot Framework 5.0.
Note
Using variables with
robot:exclude
is new in Robot Framework 7.2.
Using variables with tags matched against
--include
and
--exclude
is not supported.
Note
In Robot Framework 7.0
--include
and
--test
were cumulative
and selected tests needed to match only either of these options. That behavior
caused
backwards incompatibility problems
and it was reverted already in
Robot Framework 7.0.1.
Re-executing failed test cases
Command line option
--rerunfailed (-R)
can be used to select all failed
tests from an earlier
output file
for re-execution. This option is useful,
for example, if running all tests takes a lot of time and one wants to
iteratively fix failing test cases.
robot tests # first execute all tests
robot --rerunfailed output.xml tests # then re-execute failing
Behind the scenes this option selects the failed tests as they would have been
selected individually using the
--test
option. It is possible to further
fine-tune the list of selected tests by using
--test
,
--suite
,
--include
and
--exclude
options.
It is an error if the output contains no failed tests, but this behavior can be
changed by using the
--runemptysuite
option
discussed below
.
Using an output not originating from executing the same tests that are run
now causes undefined results. Using a special value
NONE
as the output is
same as not specifying this option at all.
Tip
Re-execution results and original results can be
merged together
using the
--merge
command line option.
Re-executing failed test suites
Command line option
--rerunfailedsuites (-S)
can be used to select all
failed suites from an earlier
output file
for re-execution. Like
--rerunfailed (-R)
, this option is useful when full test execution
takes a lot of time. Note that all tests from a failed test suite will be
re-executed, even passing ones. This option is useful when the tests in
a test suite depends on each other.
Behind the scenes this option selects the failed suites as they would have been
selected individually with the
--suite
option. It is possible to further
fine-tune the list of selected tests by using
--test
,
--suite
,
--include
and
--exclude
options.
When no tests match selection
By default when no tests match the selection criteria test execution fails
with an error like:
[ ERROR ] Suite 'Example' contains no tests matching tag 'xxx'.
Because no outputs are generated, this behavior can be problematic if tests
are executed and results processed automatically. Luckily a command line
option
--RunEmptySuite
(case-insensitive) 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.
Similar situation can occur also when processing output files with
Rebot
.
It is possible that no test match the used filtering criteria or that
the output file contained no tests to begin with. By default executing
Rebot fails in these cases, but it has a separate
--ProcessEmptySuite
option that can be used to alter the behavior.
In practice this option works the same way as
--RunEmptySuite
when
running tests.
Note
Using
--RunEmptySuite
with
--ReRunFailed
or
--ReRunFailedSuites
requires Robot Framework 5.0.1
or newer.
3.5.4 Configuring where to search libraries and other extensions
When Robot Framework imports a
test library
,
listener
, or some other
Python based extension, it uses the Python interpreter to import the module
containing the extension from the system. The list of locations where modules
are looked for is called
the module search path
, and its contents can be
configured using different approaches explained in this section.
Robot Framework uses Python's module search path also when importing
resource
and variable files
if the specified path does not match any file directly.
The module search path being set correctly so that libraries and other
extensions are found is a requirement for successful test execution. If
you need to customize it using approaches explained below, it is often
a good idea to create a custom
start-up script
.
Locations automatically in module search path
Python interpreters have their own standard library as well as a directory
where third party modules are installed automatically in the module search
path. This means that test libraries
packaged using Python's own packaging
system
are automatically installed so that they can be imported without
any additional configuration.
PYTHONPATH
Python reads additional locations to be added to
the module search path from
PYTHONPATH
environment variables.
If you want to specify more than one location in any of them, you
need to separate the locations with a colon on UNIX-like machines (e.g.
/opt/libs:$HOME/testlibs
) and with a semicolon on Windows (e.g.
D:\libs;%HOMEPATH%\testlibs
).
Environment variables can be configured permanently system wide or so that
they affect only a certain user. Alternatively they can be set temporarily
before running a command, something that works extremely well in custom
start-up scripts
.
Using
--pythonpath
option
Robot Framework has a separate command line option
--pythonpath (-P)
for adding locations to the module search path.
Multiple locations can be given by separating them with a colon (
:
) or
a semicolon (
;
) or by using this option multiple times. If the value
contains both colons and semicolons, it is split from semicolons. Paths
can also be
glob patterns
matching multiple paths, but they typically
need to be escaped when used on the console.
Examples:
--pythonpath libs
--pythonpath /opt/testlibs:mylibs.zip:yourlibs
--pythonpath /opt/testlibs --pythonpath mylibs.zip --pythonpath yourlibs
--pythonpath c:\temp;d:\resources
--pythonpath lib/\*.zip # '*' is escaped
Note
Both colon and semicolon work regardless the operating system.
Using semicolon is new in Robot Framework 5.0.
Configuring
sys.path
programmatically
Python interpreters store the module search path they use as a list of strings
in
sys.path
attribute. This list can be updated dynamically during execution, and changes
are taken into account next time when something is imported.
3.5.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.5.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
--dryrun
.
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.
It is possible to disable dry run validation of specific
user keywords
by adding a special
robot:no-dry-run
keyword tag
to them. This is useful
if a keyword fails in the dry run mode for some reason, but work fine when
executed normally.
Note
The dry run mode does not validate variables.
3.5.7 Randomizing execution order
The test execution order can be randomized using option
--randomize <what>[:<seed>]
, where
<what>
is one of the following:
tests
Test cases inside each test suite are executed in random order.
suites
All test suites are executed in a random order, but test cases inside
suites are run in the order they are defined.
all
Both test cases and test suites are executed in a random order.
none
Neither execution order of test nor suites is randomized.
This value can be used to override the earlier value set with
--randomize
.
It is possible to give a custom seed
to initialize the random generator. This is useful if you want to re-run tests
using the same order as earlier. The seed is given as part of the value for
--randomize
in format
<what>:<seed>
and it must be an integer.
If no seed is given, it is generated randomly. The executed top level test
suite automatically gets
metadata
named
Randomized
that tells both
what was randomized and what seed was used.
Examples:
robot --randomize tests my_test.robot
robot --randomize all:12345 path/to/tests
3.5.8 Programmatic modification of test data
If the provided built-in features to modify test data before execution
are not enough, Robot Framework makes it possible to do
custom modifications programmatically. This is accomplished by creating
a so called
pre-run modifier
and activating it using the
--prerunmodifier
option.
Pre-run modifiers should be implemented as visitors that can traverse through
the executable test suite structure and modify it as needed. The visitor
interface is explained as part of the
Robot Framework API documentation
, and it possible to modify executed
test suites
,
test cases
and
keywords
using it. The examples below ought to give an idea of
how pre-run modifiers can be used and how powerful this functionality is.
When a pre-run modifier is taken into use on the command line using the
--prerunmodifier
option, it can be specified either as a name of
the modifier class or a path to the modifier file. If the modifier is given
as a class name, the module containing the class must be in the
module search
path
, and if the module name is different than the class name, the given
name must include both like
module.ModifierClass
. If the modifier is given
as a path, the class name must be same as the file name. For most parts this
works exactly like when
importing a test library
.
If a modifier requires arguments, like the examples below do, they can be
specified after the modifier name or path using either a colon (
:
) or a
semicolon (
;
) as a separator. If both are used in the value, the one used
first is considered to be the actual separator. Starting from Robot Framework
4.0, arguments also support the
named argument syntax
as well as
argument
conversion
based on
type hints
and
default values
the same way
as keywords do.
If more than one pre-run modifier is needed, they can be specified by using
the
--prerunmodifier
option multiple times. If similar modifying
is needed before creating logs and reports,
programmatic modification of
results
can be enabled using the
--prerebotmodifier
option.
Pre-run modifiers are executed before other configuration affecting the
executed test suite and test cases. Most importantly, options related to
selecting test cases
are processed after modifiers, making it possible to
use options like
--include
also with possible dynamically added
tests.
Another way to modify tests is using the
listener version 3
interface.
Modifying the
data
argument passed to the
start_suite
listener method
when it is called for the first time has in practice the same effect as using
a pre-run modifier. The main difference is that
--include/--exclude
and other
such options do not have an effect to the added tests. The main benefit of using
listeners is that they allow making modifications dynamically based on what
happens during the execution.
Tip
Modifiers are taken into use from the command line exactly the same
way as
listeners
. See the
Registering listeners from command line
section for more information and examples.
Example: Select every Xth test
The first example shows how a pre-run modifier can remove tests from the
executed test suite structure. In this example only every Xth tests is
preserved, and the X is given from the command line along with an optional
start index.
"""Pre-run modifier that selects only every Xth test for execution.
Starts from the first test by default. Tests are selected per suite.
"""
from
robot.api
import
SuiteVisitor
class
SelectEveryXthTest
(
SuiteVisitor
):
def
__init__
(
self
,
x
:
int
,
start
:
int
=
0
):
self
.
x
=
x
self
.
start
=
start
def
start_suite
(
self
,
suite
):
"""Modify suite's tests to contain only every Xth."""
suite
.
tests
=
suite
.
tests
[
self
.
start
::
self
.
x
]
def
end_suite
(
self
,
suite
):
"""Remove suites that are empty after removing tests."""
suite
.
suites
=
[
s
for
s
in
suite
.
suites
if
s
.
test_count
>
0
]
def
visit_test
(
self
,
test
):
"""Avoid visiting tests and their keywords to save a little time."""
pass
If the above pre-run modifier is in a file
SelectEveryXthTest.py
and
the file is in the
module search path
, it could be used like this:
# Specify the modifier as a path. Run every second test.
robot --prerunmodifier path/to/SelectEveryXthTest.py:2 tests.robot
# Specify the modifier as a name. Run every third test, starting from the second.
robot --prerunmodifier SelectEveryXthTest:3:1 tests.robot
Example: Exclude tests by name
Also the second example removes tests, this time based on a given name pattern.
In practice it works like a negative version of the built-in
--test
option.
"""Pre-run modifier that excludes tests by their name.
Tests to exclude are specified by using a pattern that is both case and space
insensitive and supports '*' (match anything) and '?' (match single character)
as wildcards.
"""
from
robot.api
import
SuiteVisitor
from
robot.utils
import
Matcher
class
ExcludeTests
(
SuiteVisitor
):
def
__init__
(
self
,
pattern
):
self
.
matcher
=
Matcher
(
pattern
)
def
start_suite
(
self
,
suite
):
"""Remove tests that match the given pattern."""
suite
.
tests
=
[
t
for
t
in
suite
.
tests
if
not
self
.
_is_excluded
(
t
)]
def
_is_excluded
(
self
,
test
):
return
self
.
matcher
.
match
(
test
.
name
)
or
self
.
matcher
.
match
(
test
.
longname
)
def
end_suite
(
self
,
suite
):
"""Remove suites that are empty after removing tests."""
suite
.
suites
=
[
s
for
s
in
suite
.
suites
if
s
.
test_count
>
0
]
def
visit_test
(
self
,
test
):
"""Avoid visiting tests and their keywords to save a little time."""
pass
Assuming the above modifier is in a file named
ExcludeTests.py
, it
could be used like this:
# Exclude test named 'Example'.
robot --prerunmodifier path/to/ExcludeTests.py:Example tests.robot
# Exclude all tests ending with 'something'.
robot --prerunmodifier path/to/ExcludeTests.py:*something tests.robot
Example: Disable setups and teardowns
Sometimes when debugging tests it can be useful to disable setups or teardowns.
This can be accomplished by editing the test data, but pre-run modifiers make
it easy to do that temporarily for a single run:
"""Pre-run modifiers for disabling suite and test setups and teardowns."""
from
robot.api
import
SuiteVisitor
class
SuiteSetup
(
SuiteVisitor
):
def
start_suite
(
self
,
suite
):
suite
.
setup
=
None
class
SuiteTeardown
(
SuiteVisitor
):
def
start_suite
(
self
,
suite
):
suite
.
teardown
=
None
class
TestSetup
(
SuiteVisitor
):
def
start_test
(
self
,
test
):
test
.
setup
=
None
class
TestTeardown
(
SuiteVisitor
):
def
start_test
(
self
,
test
):
test
.
teardown
=
None
Assuming that the above modifiers are all in a file named
disable.py
and this file is in the
module search path
, setups and teardowns could be
disabled, for example, as follows:
# Disable suite teardowns.
robot --prerunmodifier disable.SuiteTeardown tests.robot
# Disable both test setups and teardowns by using '--prerunmodifier' twice.
robot --prerunmodifier disable.TestSetup --prerunmodifier disable.TestTeardown tests.robot
Note
Prior to Robot Framework 4.0
setup
and
teardown
were accessed via
the intermediate
keywords
attribute and, for example, suite setup
was disabled like
suite.keywords.setup = None
.
3.5.9 Controlling console output
There are various command line options to control how test execution is
reported on the console.
Console output type
The overall console output type is set with the
--console
option.
It supports the following case-insensitive values:
verbose
Every test suite and test case is reported individually. This is
the default.
dotted
Only show
.
for passed test,
F
for failed tests,
s
for skipped
tests and
x
for tests which are skipped because
test execution exit
. Failed tests are listed separately
after execution. This output type makes it easy to see are there any
failures during execution even if there would be a lot of tests.
quiet
No output except for
errors and warnings
.
none
No output whatsoever. Useful when creating a custom output using,
for example,
listeners
.
Separate convenience options
--dotted (-.)
and
--quiet
are shortcuts for
--console dotted
and
--console quiet
, respectively.
Examples:
robot --console quiet tests.robot
robot --dotted tests.robot
Console width
The width of the test execution output in the console can be set using
the option
--consolewidth (-W)
. The default width is 78 characters.
Tip
On many UNIX-like machines you can use handy
$COLUMNS
environment variable like
--consolewidth $COLUMNS
.
Console colors
The
--consolecolors (-C)
option is used to control whether
colors should be used in the console output. Colors are implemented
using
ANSI escape codes
with a backup mechanism for older Windows
versions that do not support ANSI codes.
This option supports the following case-insensitive values:
auto
Colors are enabled when outputs are written into the console, but not
when they are redirected into a file or elsewhere. This is the default.
on
Colors are used also when outputs are redirected. Does not work on Windows.
ansi
Same as
on
but forces ANSI codes to be used unconditionally on Windows.
off
Colors are disabled.
Note
Using ANSI codes on Windows by default is new in Robot Framework 7.1.
Console links
Result file paths written to the console at the end of the execution are, by default,
hyperlinks. This behavior can be controlled with the
--consolelinks
option
that accepts the following case-insensitive values:
auto
Paths are converted to links when
console colors
are enabled. This is the default.
off
Links are unconditionally disabled.
The hyperlink support depends also on the console that is used, but nowadays
the
support is pretty good
. The commonly used
Windows Console
does not
support links, though, but the newer
Windows Terminal
does.
Note
Hyperlink support is new in Robot Framework 7.1.
Console markers
Special markers
.
(success) and
F
(failure) are shown on the console when using the
verbose output
and top level keywords in test cases end. The markers allow following
the test execution in high level, and they are erased when test cases end.
It is possible to configure when markers
are used with
--consolemarkers (-K)
option. It supports the following
case-insensitive values:
auto
Markers are enabled when the standard output is written into the console,
but not when it is redirected into a file or elsewhere. This is the default.
on
Markers are always used.
off
Markers are disabled.
3.5.10 Setting listeners
Listeners
can be used to monitor the test execution. When they are taken into
use from the command line, they are specified using the
--listener
command line option. The value can either be a path to a listener or
a listener name. See the
Listener interface
section for more details
about importing listeners and using them in general.
3.6 Output files
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.6.1 Different output files
Output directory
Output file
Log file
Report file
XUnit compatible result file
Debug file
Timestamping output files
Setting titles
Setting background colors
3.6.2 Log levels
Available log levels
Setting log level
Visible log level
3.6.3 Splitting logs
3.6.4 Configuring statistics
Configuring displayed suite statistics
Including and excluding tag statistics
Generating combined tag statistics
Creating links from tag names
Adding documentation to tags
3.6.5 Removing and flattening keywords
Removing keywords
Flattening keywords
Flattening keyword during execution time
3.6.6 Automatically expanding keywords
3.6.7 Setting start and end time of execution
3.6.8 Limiting error message length in reports
3.6.9 Programmatic modification of results
3.6.10 System log
3.6.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 execution results in machine readable XML or JSON
format.
Log
,
report
and
xUnit
files are typically generated based on them,
and they can also be combined and otherwise post-processed with
Rebot
.
Various external tools also process output files to be able to show detailed
execution information.
Tip
Generating
report
and
xUnit
files as part of test execution
does not require processing output files after execution. Disabling
log
generation when running tests can thus save memory.
The command line option
--output (-o)
determines the path where
the output file is created. The path is relative to the
output directory
and the default value is
output.xml
when executing tests.
When
post-processing outputs
with Rebot, new output files are not created
unless the
--output
option is explicitly used.
It is possible to disable the output file by using a special value
NONE
with the
--output
option. If no outputs are needed, they should
all be explicitly disabled using
--output NONE --report NONE --log NONE
.
XML output format
Output files are created using XML by default. The XML output format is
documented in the
result.xsd
schema file
.
JSON output format
Robot Framework supports also JSON outputs and this format is used automatically
if the output file extension is
.json
. The JSON output format is
documented in the
result.json
schema file
.
Note
JSON output files are supported during execution starting from
Robot Framework 7.2.
Rebot
can create them based on XML output
files already with Robot Framework 7.0.
Legacy XML format
There were some
backwards incompatible changes
to the XML output file format in
Robot Framework 7.0. To make it possible to use new Robot Framework versions
with external tools that are not yet updated to support the new format, there is
a
--legacyoutput
option that produces output files that are compatible
with Robot Framework 6.x and earlier. Robot Framework itself can process output
files both in the old and in the new formats.
We hope that external tools are updated soon, but we plan to support this
option at least until Robot Framework 8.0. If you encounter tools that are
not compatible, please inform the tool developers about changes.
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
.
An example of beginning of a log file
An example of a log file with keyword details visible
An example of a log file with skipped and passed tests
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 tests pass and bright red if any test fails.
Background can also be yellow, which means that all tests were
skipped
.
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
.
An example report file of successful test execution
An example report file of failed test execution
XUnit compatible result file
XUnit result files contain the test execution summary in
xUnit
compatible
XML format. These files can thus be used as an input for external tools that
understand xUnit reports. For example,
Jenkins
continuous integration server
supports generating statistics based on xUnit compatible
results.
XUnit output files are not created unless the command line option
--xunit (-x)
is used explicitly. This option requires a path to
the generated xUnit file, relatively to the
output directory
, as a value.
XUnit output files were changed pretty heavily in Robot Framework 5.0.
They nowadays contain separate
<testsuite>
elements for each suite,
<testsuite>
elements have
timestamp
attribute, and
suite documentation
and
metadata
is stored as
<property>
elements.
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
fileviewer.py
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 generated by Robot Framework itself 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 output files like
output-20080604-163225.xml
and
mylog-20080604-163225.html
:
robot --timestampoutputs --log mylog.html --report NONE tests.robot
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.
Example:
robot --logtitle "Smoke Test Log" --reporttitle "Smoke Test Report" --include smoke my_tests/
Note
Prior to Robot Framework 3.1, underscores in the given titles were
converted to spaces. Nowadays spaces need to be escaped or quoted
like in the example above.
Setting background colors
By default the
report file
has red background if there are failures,
green background if there are passed tests and possibly some skipped ones,
and a yellow background if all tests are skipped or no tests have been run.
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 blue:red:orange
--reportbackground #00E:#E00
If you specify two colors, the first one will be used instead of the
default green (pass) color and the second instead of the default red (fail).
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 two have same semantics as earlier
and the last one replaces the default yellow (skip) color.
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, red and yellow colors are
specified using hexadecimal values
#9e9
,
#f66
and
#fed84f
,
respectively.
3.6.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.
ERROR
Used for displaying errors. Errors are shown in
the console and in
the Test Execution Errors section in log files
, but they
do not affect test case statuses. If the
--exitonerror option is enabled
,
errors stop the whole execution, though,
WARN
Used for displaying warnings. Warnings are shown in
the console and in
the Test Execution Errors section in log files
, but they
do not affect test case statuses.
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.
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
.
Visible log level
If the log file contains messages at
DEBUG
or
TRACE
levels, a visible log level drop down is shown
in the upper right corner. This allows users to remove messages below chosen
level from the view. This can be useful especially when running test at
TRACE
level.
An example log showing the visible log level drop down
By default the drop down will be set at the lowest level in the log file, so
that all messages are shown. The default visible log level can be changed using
--loglevel
option by giving the default after the normal log level
separated by a colon:
--loglevel DEBUG:INFO
In the above example, tests are run using level
DEBUG
, but
the default visible level in the log file is
INFO
.
3.6.3 Splitting logs
Normally the log file is just a single HTML file. When the amount of the test
cases increases, the size of the file can grow so large that opening it into
a browser is inconvenient or even impossible. Hence, 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.
The JavaScript files are saved to the same directory where the
log file
itself is saved. It is the common
output directory
by default, but
it can be changed with the
--log
command line option.
Note
When copying the log files, you need to copy also all the
log-*.js
files or some information will be missing.
3.6.4 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. By 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. The combined tags are specified using
tag patterns
where
*
and
?
are supported as wildcards and
AND
,
OR
and
NOT
operators can be used for combining
individual tags or patterns together.
The following examples illustrate creating combined tag statistics using
different patterns, and the figure below shows a snippet of the resulting
Statistics by Tag
table:
--tagstatcombine owner-*
--tagstatcombine smokeANDmytag
--tagstatcombine smokeNOTowner-janne*
Examples of combined tag statistics
As the above example illustrates, the name of the added combined statistic
is, by default, just the given pattern. If this is not good enough, it
is possible to give a custom name after the pattern by separating them
with a colon (
:
):
--tagstatcombine "prio1ORprio2:High priority tests"
Note
Prior to Robot Framework 3.1, underscores in the custom name were
converted to spaces. Nowadays spaces need to be escaped or quoted
like in the example above.
Creating links from tag names
You can add external links to the
Statistics by Tag
table by
using the command line option
--tagstatlink
. Arguments to this
option are given in the format
tag:link:name
, where
tag
specifies the tags to assign the link to,
link
is the link to
be created, and
name
is the name to give to the link.
tag
may be a single tag, but more commonly a
simple pattern
where
*
matches anything and
?
matches any single
character. When
tag
is a pattern, the matches to wildcards may
be used in
link
and
title
with the syntax
%N
,
where "N" is the index of the match starting from 1.
The following examples illustrate the usage of this option, and the
figure below shows a snippet of the resulting
Statistics by
Tag
table when example test data is executed with these options:
--tagstatlink mytag:http://www.google.com:Google
--tagstatlink example-bug-*:http://example.com
--tagstatlink owner-*:mailto:%1@domain.com?subject=Acceptance_Tests:Send_Mail
Examples of links from tag names
3.6.5 Removing and flattening keywords
Most of the content of
output files
comes from keywords and their
log messages. When creating higher level reports, log files are not necessarily
needed at all, and in that case keywords and their messages just take space
unnecessarily. Log files themselves can also grow overly large, especially if
they contain
FOR loops
or other constructs that repeat certain keywords
multiple times.
In these situations, command line options
--removekeywords
and
--flattenkeywords
can be used to dispose or flatten unnecessary keywords.
They can be used both when
executing test cases
and when
post-processing
outputs
. When used during execution, they only affect the log file, not
the XML output file. With
rebot
they affect both logs and possibly
generated new output XML files.
Removing keywords
The
--removekeywords
option removes keywords and their messages
altogether. It has the following modes of operation, and it can be used
multiple times to enable multiple modes. Keywords that contain
errors
or warnings
are not removed except when using the
ALL
mode.
ALL
Remove data from all keywords unconditionally.
PASSED
Remove keyword data from passed test cases. In most cases, log files
created using this option contain enough information to investigate
possible failures.
FOR
Remove all passed iterations from
FOR loops
except the last one.
WHILE
Remove all passed iterations from
WHILE loops
except the last one.
WUKS
Remove all failing keywords inside
BuiltIn
keyword
Wait Until Keyword Succeeds
except the last one.
NAME:<pattern>
Remove data from all keywords matching the given pattern regardless the
keyword status. The pattern is matched against the full name of the keyword,
prefixed with the possible library or resource file name like
MyLibrary.Keyword Name
. The pattern is case, space, and underscore
insensitive, and it supports
simple patterns
with
*
,
?
and
[]
as wildcards.
TAG:<pattern>
Remove data from keywords with tags that match the given pattern. Tags are
case and space insensitive and they can be specified using
tag patterns
where
*
,
?
and
[]
are supported as wildcards and
AND
,
OR
and
NOT
operators can be used for combining individual tags or patterns together.
Can be used both with
library keyword tags
and
user keyword tags
.
Examples:
rebot --removekeywords all --output removed.xml output.xml
robot --removekeywords passed --removekeywords for tests.robot
robot --removekeywords name:HugeKeyword --removekeywords name:resource.* tests.robot
robot --removekeywords tag:huge tests.robot
Removing keywords is done after parsing the
output file
and generating
an internal model based on it. Thus it does not reduce memory usage as much
as
flattening keywords
.
Flattening keywords
The
--flattenkeywords
option flattens matching keywords. In practice
this means that matching keywords get all log messages from their child
keywords, recursively, and child keywords are discarded otherwise. Flattening
supports the following modes:
FOR
Flatten
FOR loops
fully.
WHILE
Flatten
WHILE loops
fully.
ITERATION
Flatten individual
FOR
and
WHILE
loop iterations.
FORITEM
Deprecated alias for
ITERATION
.
NAME:<pattern>
Flatten keywords matching the given pattern. Pattern matching rules are
same as when
removing keywords
using the
NAME:<pattern>
mode.
TAG:<pattern>
Flatten keywords with tags matching the given pattern. Pattern matching
rules are same as when
removing keywords
using the
TAG:<pattern>
mode.
Examples:
robot --flattenkeywords name:HugeKeyword --flattenkeywords name:resource.* tests.robot
rebot --flattenkeywords foritem --output flattened.xml original.xml
Flattening keywords is done already when the
output file
is parsed
initially. This can save a significant amount of memory especially with
deeply nested keyword structures.
Flattening keyword during execution time
Starting from Robot Framework 6.1, it is possible to enable the keyword flattening during
the execution time. This can be done only on an user keyword level by defining the
reserved tag
robot:flatten
as a
keyword tag
. Using this tag will work similarly as the command line
option described in the previous chapter, e.g. all content except for log messages is removed
from under the keyword having the tag. One important difference is that in this case, the removed
content is not written to the output file at all, and thus cannot be accessed at later time.
*** Keywords ***
Example
[
Tags
]
robot:flatten
Log
Keywords and the loop are removed, but logged messages are preserved.
FOR
${
i
}
IN RANGE
1
101
Log
Iteration
${
i
}
/100.
END
3.6.6 Automatically expanding keywords
Keywords that have passed are closed in the log file by default. Thus information
they contain is not visible unless you expand them. If certain keywords have
important information that should be visible when the log file is opened, you can
use the
--expandkeywords
option to set keywords automatically expanded
in log file similar to failed keywords. Expanding supports the following modes:
NAME:<pattern>
Expand keywords matching the given pattern. Pattern matching rules are
same as when
removing keywords
using the
NAME:<pattern>
mode.
TAG:<pattern>
Expand keywords with tags matching the given pattern. Pattern matching
rules are same as when
removing keywords
using the
TAG:<pattern>
mode.
If you need to expand keywords matching different names or patterns, you can
use the
--expandkeywords
multiple times.
Examples:
robot --expandkeywords name:SeleniumLibrary.CapturePageScreenshot tests.robot
rebot --expandkeywords tag:example --expandkeywords tag:another output.xml
Note
The
--expandkeywords
option is new in Robot Framework 3.2.
3.6.7 Setting start and end time of execution
When
combining outputs
using Rebot, 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.
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
3.6.8 Limiting error message length in reports
If a test case fails and has a long error message, the message shown in
reports
is automatically cut from the middle to keep reports easier to
read. By default messages longer than 40 lines are cut, but that can be
configured by using the
--maxerrorlines
command line option.
The minimum value for this option is 10, and it is also possible to use
a special value
NONE
to show the full message.
Full error messages are always visible in
log files
as messages of
the failed keywords.
Note
The
--maxerrorlines
option is new in Robot Framework 3.1.
3.6.9 Programmatic modification of results
If the provided built-in features to modify results are not enough,
Robot Framework makes it possible to do custom modifications
programmatically. This is accomplished by creating a model modifier and
activating it using the
--prerebotmodifier
option.
This functionality works nearly exactly like
programmatic modification of
test data
that can be enabled with the
--prerunmodifier
option.
The obvious difference is that this time modifiers operate with the
result model
, not the
running model
. For example, the following modifier
marks all passed tests that have taken more time than allowed as failed:
from
robot.api
import
SuiteVisitor
class
ExecutionTimeChecker
(
SuiteVisitor
):
def
__init__
(
self
,
max_seconds
:
float
):
self
.
max_milliseconds
=
max_seconds
*
1000
def
visit_test
(
self
,
test
):
if
test
.
status
==
'PASS'
and
test
.
elapsedtime
>
self
.
max_milliseconds
:
test
.
status
=
'FAIL'
test
.
message
=
'Test execution took too long.'
If the above modifier would be in file
ExecutionTimeChecker.py
, it
could be used, for example, like this:
# Specify modifier as a path when running tests. Maximum time is 42 seconds.
robot --prerebotmodifier path/to/ExecutionTimeChecker.py:42 tests.robot
# Specify modifier as a name when using Rebot. Maximum time is 3.14 seconds.
# ExecutionTimeChecker.py must be in the module search path.
rebot --prerebotmodifier ExecutionTimeChecker:3.14 output.xml
If more than one model modifier is needed, they can be specified by using
the
--prerebotmodifier
option multiple times. When executing tests,
it is possible to use
--prerunmodifier
and
--prerebotmodifier
options together.
3.6.10 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
robot
--name
Syslog_example
path/to/tests
4 Extending Robot Framework
4.1 Creating test libraries
4.2 Remote library interface
4.3 Listener interface
4.4 Parser interface
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. 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 Python 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.
Different test library APIs
Robot Framework has three different test library APIs.
Static API
The simplest approach is having a module or a class
with functions/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.
4.1.2 Creating test library class or module
Test libraries can be implemented as Python modules or classes.
Library name
As discussed under the
Using test libraries
section, libraries can
be
imported by name or path
:
*** Settings ***
Library
MyLibrary
Library
module.LibraryClass
Library
path/AnotherLibrary.py
When a library is imported by a name, the library module must be in the
module search path
and the name can either refer to a library module
or to a library class. When a name refers directly to a library class,
the name must be in format like
modulename.ClassName
. Paths to libraries
always refer to modules.
Even when a library import refers to a module, either by a name or by a path,
a class in the module, not the module itself, is used as a library in these cases:
If the module contains a class that has the same name as the module.
The class can be either implemented in the module or imported into it.
This makes it possible to import libraries using simple names like
MyLibrary
instead of specifying both the module and the class like
module.MyLibrary
or
MyLibrary.MyLibrary
. When importing a library by a path, it is not even
possible to directly refer to a library class and automatically using a class
from the imported module is the only option.
If the module contains exactly one class decorated with the
@library decorator
.
In this case the class needs to be implemented in the module, not imported to it.
This approach has all the same benefits as the earlier one, but it also allows
the class name to differ from the module name.
Using the
@library decorator
for this purpose is new in Robot Framework 7.2.
Tip
If the library name is really long, it is often a good idea to give
it a
simpler alias
at the import time.
Providing arguments to libraries
All test libraries implemented as classes can take arguments. These
arguments are specified after the library name when the library is imported,
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.
The number of arguments needed by the library is the same
as the number of arguments accepted by the library's
__init__
method.
The default values, argument conversion, and other such features work
the same way as with
keyword arguments
. 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.
*** Settings ***
Library
MyLibrary
10.0.0.1
8080
Library
AnotherLib
${
ENVIRONMENT
}
Example implementations for the libraries used in the above example:
from
example
import
Connection
class
MyLibrary
:
def
__init__
(
self
,
host
,
port
=
80
):
self
.
connection
=
Connection
(
host
,
port
)
def
send_message
(
self
,
message
):
self
.
connection
.
send
(
message
)
class
AnotherLib
:
def
__init__
(
self
,
environment
):
self
.
environment
=
environment
def
do_something
(
self
):
if
self
.
environment
==
'test'
:
do_something_in_test_environment
()
else
:
do_something_in_other_environments
()
If a library is imported multiple times with different arguments within a single
suite, it needs to be given a
custom name
or otherwise latter imports are ignored:
*** Settings ***
Library
MyLibrary
10.0.0.1
8080
AS
RemoteLibrary
Library
MyLibrary
127.0.0.1
AS
LocalLibrary
*** Test Cases ***
Example
RemoteLibrary.Send Message
Hello!
LocalLibrary.Send Message
Hi!
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
A new instance is created for every test case. A possible suite setup
and suite teardown share yet another instance.
Prior to Robot Framework 3.2 this value was
TEST CASE
, but nowadays
TEST
is recommended. Because all unrecognized values are considered
same as
TEST
, both values work with all versions. For the same reason
it is possible to also use value
TASK
if the library is targeted for
RPA
usage more than testing.
TEST
is also the default value if the
ROBOT_LIBRARY_SCOPE
attribute is not set.
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.
Prior to Robot Framework 3.2 this value was
TEST SUITE
. That value still
works, but
SUITE
is recommended with libraries targeting Robot Framework
3.2 and newer.
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.
Note
If a library is imported multiple times with different
arguments
,
a new instance is created every time regardless the scope.
When the
SUITE
or
GLOBAL
scopes are used with 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 opened browsers.
Example library using the
SUITE
scope:
class
ExampleLibrary
:
ROBOT_LIBRARY_SCOPE
=
'SUITE'
def
__init__
(
self
):
self
.
_counter
=
0
def
count
(
self
):
self
.
_counter
+=
1
print
(
self
.
_counter
)
def
clear_count
(
self
):
self
.
_counter
=
0
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
also writes this information into the keyword
documentations it generates.
Version information is read from attribute
ROBOT_LIBRARY_VERSION
, similarly as
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.
An example module using
__version__
:
__version__
=
'0.1'
def
keyword
():
pass
Documentation format
Library documentation tool
Libdoc
supports documentation in multiple formats. If you want to use something
else than Robot Framework's own
documentation formatting
, you can specify
the format in the source code using
ROBOT_LIBRARY_DOC_FORMAT
attribute
similarly as
scope
and
version
are set with their own
ROBOT_LIBRARY_*
attributes.
The possible case-insensitive values for documentation format are
ROBOT
(default),
HTML
,
TEXT
(plain text),
and
reST
(
reStructuredText
). Using the
reST
format requires
the
docutils
module to be installed when documentation is generated.
Setting the documentation format is illustrated by the following example that
uses reStructuredText format.
See
Documenting libraries
section and
Libdoc
chapter for more information
about documenting test libraries in general.
"""A library for *documentation format* demonstration purposes.
This documentation is created using reStructuredText__. Here is a link
to the only \`Keyword\`.
__ http://docutils.sourceforge.net
"""
ROBOT_LIBRARY_DOC_FORMAT
=
'reST'
def
keyword
():
"""**Nothing** to see here. Not even in the table below.
======= ===== =====
Table here has
nothing to see.
======= ===== =====
"""
pass
Library acting as listener
Listener interface
allows external listeners to get notifications about
test execution. They are called, for example, when suites, tests, and keywords
start and end. Sometimes getting such notifications is also useful for test
libraries, and they can register a custom listener by using
ROBOT_LIBRARY_LISTENER
attribute. The value of this attribute
should be an instance of the listener to use, possibly the library itself.
For more information and examples see
Libraries as listeners
section.
@library
decorator
An easy way to configure libraries implemented as classes is using
the
robot.api.deco.library
class decorator. It allows configuring library's
scope
,
version
,
custom argument converters
,
documentation format
and
listener
with optional arguments
scope
,
version
,
converter
,
doc_format
and
listener
, respectively. When these arguments are used, they
set the matching
ROBOT_LIBRARY_SCOPE
,
ROBOT_LIBRARY_VERSION
,
ROBOT_LIBRARY_CONVERTERS
,
ROBOT_LIBRARY_DOC_FORMAT
and
ROBOT_LIBRARY_LISTENER
attributes automatically:
from
robot.api.deco
import
library
from
example
import
Listener
@library
(
scope
=
'GLOBAL'
,
version
=
'3.2b1'
,
doc_format
=
'reST'
,
listener
=
Listener
())
class
Example
:
...
The
@library
decorator also disables the
automatic keyword discovery
by setting the
ROBOT_AUTO_KEYWORDS
argument to
False
by default. This
means that it is mandatory to decorate methods with the
@keyword decorator
to expose them as keywords. If only that behavior is desired and no further
configuration is needed, the decorator can also be used without parenthesis
like:
from
robot.api.deco
import
library
@library
class
Example
:
...
If needed, the automatic keyword discovery can be enabled by using the
auto_keywords
argument:
from
robot.api.deco
import
library
@library
(
scope
=
'GLOBAL'
,
auto_keywords
=
True
)
class
Example
:
...
The
@library
decorator only sets class attributes
ROBOT_LIBRARY_SCOPE
,
ROBOT_LIBRARY_VERSION
,
ROBOT_LIBRARY_CONVERTERS
,
ROBOT_LIBRARY_DOC_FORMAT
and
ROBOT_LIBRARY_LISTENER
if the respective arguments
scope
,
version
,
converters
,
doc_format
and
listener
are used. The
ROBOT_AUTO_KEYWORDS
attribute is set always and its presence can be used as an indication that
the
@library
decorator has been used. When attributes are set, they
override possible existing class attributes.
When a class is decorated with the
@library
decorator, it is used as a library
even when a
library import refers only to a module containing it
. This is done
regardless does the class name match the module name or not.
Note
The
@library
decorator is new in Robot Framework 3.2,
the
converters
argument is new in Robot Framework 5.0, and
specifying that a class in an imported module should be used as
a library is new in Robot Framework 7.2.
4.1.3 Creating keywords
What methods are considered keywords
When the static library API is used, Robot Framework uses introspection
to find out what keywords the library class or module implements.
By default it excludes methods and functions starting with an underscore.
All the methods and functions that are not ignored are considered keywords.
For example, the library below implements a single keyword
My Keyword
.
class
MyLibrary
:
def
my_keyword
(
self
,
arg
):
return
self
.
_helper_method
(
arg
)
def
_helper_method
(
self
,
arg
):
return
arg
.
upper
()
Limiting public methods becoming keywords
Automatically considering all public methods and functions keywords typically
works well, but there are cases where it is not desired. There are also
situations where keywords are created when not expected. For example, when
implementing a library as class, it can be a surprise that also methods
in possible base classes are considered keywords. When implementing a library
as a module, functions imported into the module namespace becoming keywords
is probably even a bigger surprise.
This section explains how to prevent methods and functions becoming keywords.
Class based libraries
When a library is implemented as a class, it is possible to tell
Robot Framework not to automatically expose methods as keywords by setting
the
ROBOT_AUTO_KEYWORDS
attribute to the class with a false value:
class
Example
:
ROBOT_AUTO_KEYWORDS
=
False
When the
ROBOT_AUTO_KEYWORDS
attribute is set like this, only methods that
have explicitly been decorated with the
@keyword decorator
or otherwise
have the
robot_name
attribute become keywords. The
@keyword
decorator
can also be used for setting a
custom name
,
tags
and
argument types
to the keyword.
Although the
ROBOT_AUTO_KEYWORDS
attribute can be set to the class
explicitly, it is more convenient to use the
@library decorator
that sets it to
False
by default:
from
robot.api.deco
import
keyword
,
library
@library
class
Example
:
@keyword
def
this_is_keyword
(
self
):
pass
@keyword
(
'This is keyword with custom name'
)
def
xxx
(
self
):
pass
def
this_is_not_keyword
(
self
):
pass
Note
Both limiting what methods become keywords using the
ROBOT_AUTO_KEYWORDS
attribute and the
@library
decorator are
new in Robot Framework 3.2.
Another way to explicitly specify what keywords a library implements is using
the
dynamic
or the
hybrid
library API.
Module based libraries
When implementing a library as a module, all functions in the module namespace
become keywords. This is true also with imported functions, and that can cause
nasty surprises. For example, if the module below would be used as a library,
it would contain a keyword
Example Keyword
, as expected, but also
a keyword
Current Thread
.
from
threading
import
current_thread
def
example_keyword
():
thread_name
=
current_thread
()
.
name
print
(
f
"Running in thread '
{
thread_name
}
'."
)
A simple way to avoid imported functions becoming keywords is to only
import modules (e.g.
import threading
) and to use functions via the module
(e.g
threading.current_thread()
). Alternatively functions could be
given an alias starting with an underscore at the import time (e.g.
from threading import current_thread as _current_thread
).
A more explicit way to limit what functions become keywords is using
the module level
__all__
attribute that
Python itself uses for similar
purposes
. If it is used, only the listed functions can be keywords.
For example, the library below implements only one keyword
Example Keyword
:
from
threading
import
current_thread
__all__
=
[
'example_keyword'
]
def
example_keyword
():
thread_name
=
current_thread
()
.
name
print
(
f
"Running in thread '
{
thread_name
}
'."
)
def
this_is_not_keyword
():
pass
If the library is big, maintaining the
__all__
attribute when keywords are
added, removed or renamed can be a somewhat big task. Another way to explicitly
mark what functions are keywords is using the
ROBOT_AUTO_KEYWORDS
attribute
similarly as it can be used with
class based libraries
. When this attribute
is set to a false value, only functions explicitly decorated with the
@keyword decorator
become keywords. For example, also this library
implements only one keyword
Example Keyword
:
from
threading
import
current_thread
from
robot.api.deco
import
keyword
ROBOT_AUTO_KEYWORDS
=
False
@keyword
def
example_keyword
():
thread_name
=
current_thread
()
.
name
print
(
f
"Running in thread '
{
thread_name
}
'."
)
def
this_is_not_keyword
():
pass
Note
Limiting what functions become keywords using
ROBOT_AUTO_KEYWORDS
is a new feature in Robot Framework 3.2.
Using
@not_keyword
decorator
Functions in modules and methods in classes can be explicitly marked as
"not keywords" by using the
@not_keyword
decorator. When a library is
implemented as a module, this decorator can also be used to avoid imported
functions becoming keywords.
from
threading
import
current_thread
from
robot.api.deco
import
not_keyword
not_keyword
(
current_thread
)
# Don't expose `current_thread` as a keyword.
def
example_keyword
():
thread_name
=
current_thread
()
.
name
print
(
f
"Running in thread '
{
thread_name
}
'."
)
@not_keyword
def
this_is_not_keyword
():
pass
Using the
@not_keyword
decorator is pretty much the opposite way to avoid
functions or methods becoming keywords compared to disabling the automatic
keyword discovery with the
@library
decorator or by setting the
ROBOT_AUTO_KEYWORDS
to a false value. Which one to use depends on the context.
Note
The
@not_keyword
decorator is new in Robot Framework 3.2.
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 library implemented as a module in the
MyLibrary.py
file:
def
hello
(
name
):
print
(
f
"Hello,
{
name
}
!"
)
def
do_nothing
():
pass
The example below illustrates how the example library above can be
used. If you want to try this yourself, make sure that the library is
in the
module search path
.
*** Settings ***
Library
MyLibrary
*** Test Cases ***
My Test
Do Nothing
Hello
world
Setting custom name
It is possible to expose a different name for a keyword instead of the
default keyword name which maps to the method name. This can be accomplished
by setting the
robot_name
attribute on the method to the desired custom name:
def
login
(
username
,
password
):
...
login
.
robot_name
=
'Login via user panel'
*** Test Cases ***
My Test
Login Via User Panel
${
username
} ${
password
}
Instead of explicitly setting the
robot_name
attribute like in the above
example, it is typically easiest to use the
@keyword decorator
:
from
robot.api.deco
import
keyword
@keyword
(
'Login via user panel'
)
def
login
(
username
,
password
):
...
Using this decorator without an argument will have no effect on the exposed
keyword name, but will still set the
robot_name
attribute. This allows
marking methods to expose as keywords
without actually changing keyword
names. Methods that have the
robot_name
attribute also create keywords even if the method name itself would start with
an underscore.
Setting a custom keyword name can also enable library keywords to accept
arguments using the
embedded arguments
syntax.
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 the simplest situation is when a keyword needs an
exact number of arguments. In this case, the method
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 keywords taking different numbers of arguments:
def
no_arguments
():
print
(
"Keyword got no arguments."
)
def
one_argument
(
arg
):
print
(
f
"Keyword got one argument '
{
arg
}
'."
)
def
three_arguments
(
a1
,
a2
,
a3
):
print
(
f
"Keyword got three arguments '
{
a1
}
', '
{
a2
}
' and '
{
a3
}
'."
)
Default values to keywords
It is often useful that some of the arguments that a keyword uses have
default values.
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
(
f
"Got argument '
{
arg
}
'."
)
def
multiple_defaults
(
arg1
,
arg2
=
'default 1'
,
arg3
=
'default 2'
):
print
(
f
"Got arguments '
{
arg1
}
', '
{
arg2
}
' and '
{
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.
*** Test Cases ***
Defaults
One Default
One Default
argument
Multiple Defaults
required arg
Multiple Defaults
required arg
optional
Multiple Defaults
required arg
optional 1
optional 2
Variable number of arguments (
*varargs
)
Robot Framework supports also keywords that take any number of
arguments.
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
(
f
"Required:
{
required
}
\n
Others:"
)
for
arg
in
others
:
print
(
arg
)
def
also_defaults
(
req
,
def1
=
"default 1"
,
def2
=
"default 2"
,
*
rest
):
print
(
req
,
def1
,
def2
,
rest
)
*** Test Cases ***
Varargs
Any Arguments
Any Arguments
argument
Any Arguments
arg 1
arg 2
arg 3
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
Free keyword arguments (
**kwargs
)
Robot Framework supports
Python's **kwargs syntax
.
How to use use keywords that accept
free keyword arguments
,
also known as
free named arguments
, is
discussed under the Creating test
cases section
. In this section we take a look at how to create such keywords.
If you are already familiar how kwargs work with Python, understanding how
they work with Robot Framework test libraries is rather simple. The example
below shows the basic functionality:
def
example_keyword
(
**
stuff
):
for
name
,
value
in
stuff
.
items
():
print
(
name
,
value
)
*** Test Cases ***
Keyword Arguments
Example Keyword
hello=world
# Logs 'hello world'.
Example Keyword
foo=1
bar=42
# Logs 'foo 1' and 'bar 42'.
Basically, all arguments at the end of the keyword call that use the
named argument syntax
name=value
, and that do not match any
other arguments, are passed to the keyword as kwargs. To avoid using a literal
value like
foo=quux
as a free keyword argument, it must be
escaped
like
foo\=quux
.
The following example illustrates how normal arguments, varargs, and kwargs
work together:
def
various_args
(
arg
=
None
,
*
varargs
,
**
kwargs
):
if
arg
is
not
None
:
print
(
'arg:'
,
arg
)
for
value
in
varargs
:
print
(
'vararg:'
,
value
)
for
name
,
value
in
sorted
(
kwargs
.
items
()):
print
(
'kwarg:'
,
name
,
value
)
*** Test Cases ***
Positional
Various Args
hello
world
# Logs 'arg: hello' and 'vararg: world'.
Named
Various Args
arg=value
# Logs 'arg: value'.
Kwargs
Various Args
a=1
b=2
c=3
# Logs 'kwarg: a 1', 'kwarg: b 2' and 'kwarg: c 3'.
Various Args
c=3
a=1
b=2
# Same as above. Order does not matter.
Positional and kwargs
Various Args
1
2
kw=3
# Logs 'arg: 1', 'vararg: 2' and 'kwarg: kw 3'.
Named and kwargs
Various Args
arg=value
hello=world
# Logs 'arg: value' and 'kwarg: hello world'.
Various Args
hello=world
arg=value
# Same as above. Order does not matter.
For a real world example of using a signature exactly like in the above
example, see
Run Process
and
Start Keyword
keywords in the
Process
library.
Keyword-only arguments
Starting from Robot Framework 3.1, it is possible to use
named-only arguments
with different keywords. This support
is provided by Python's
keyword-only arguments
. Keyword-only arguments
are specified after possible
*varargs
or after a dedicated
*
marker when
*varargs
are not needed. Possible
**kwargs
are specified after keyword-only
arguments.
Example:
def
sort_words
(
*
words
,
case_sensitive
=
False
):
key
=
str
.
lower
if
case_sensitive
else
None
return
sorted
(
words
,
key
=
key
)
def
strip_spaces
(
word
,
*
,
left
=
True
,
right
=
True
):
if
left
:
word
=
word
.
lstrip
()
if
right
:
word
=
word
.
rstrip
()
return
word
*** Test Cases ***
Example
Sort Words
Foo
bar
baZ
Sort Words
Foo
bar
baZ
case_sensitive=True
Strip Spaces
${
word
}
left=False
Positional-only arguments
Python supports so called
positional-only arguments
that make it possible to
specify that an argument can only be given as a
positional argument
, not as
a
named argument
like
name=value
. Positional-only arguments are specified
before normal arguments and a special
/
marker must be used after them:
def
keyword
(
posonly
,
/
,
normal
):
print
(
f
"Got positional-only argument
{
posonly
}
and normal argument
{
normal
}
."
)
The above keyword could be used like this:
*** Test Cases ***
Example
# Positional-only and normal argument used as positional arguments.
Keyword
foo
bar
# Normal argument can also be named.
Keyword
foo
normal=bar
If a positional-only argument is used with a value that contains an equal sign
like
example=usage
, it is not considered to mean
named argument syntax
even if the part before the
=
would match the argument name. This rule
only applies if the positional-only argument is used in its correct position
without other arguments using the name argument syntax before it, though.
*** Test Cases ***
Example
# Positional-only argument gets literal value `posonly=foo` in this case.
Keyword
posonly=foo
normal=bar
# This fails.
Keyword
normal=bar
posonly=foo
Positional-only arguments are fully supported starting from Robot Framework 4.0.
Using them as positional arguments works also with earlier versions,
but using them as named arguments causes an error on Python side.
Argument conversion
Arguments defined in Robot Framework test data are, by default,
passed to keywords as Unicode strings. There are, however, several ways
to use non-string values as well:
Variables
can contain any kind of objects as values, and variables used
as arguments are passed to keywords as-is.
Keywords can themselves
convert arguments they accept
to other types.
It is possible to specify argument types explicitly using
function annotations
or the
@keyword decorator
. In these cases
Robot Framework converts arguments automatically.
Automatic conversion is also done based on
keyword default values
.
Libraries can register
custom argument converters
.
Automatic argument conversion based on function annotations, types specified
using the
@keyword
decorator, and argument default values are all new
features in Robot Framework 3.1. The
Supported conversions
section
specifies which argument conversion are supported in these cases.
Prior to Robot Framework 4.0, automatic conversion was done only if the given
argument was a string. Nowadays it is done regardless the argument type.
Manual argument conversion
If no type information is specified to Robot Framework, all arguments not
passed as
variables
are given to keywords as Unicode strings. This includes
cases like this:
*** Test Cases ***
Example
Example Keyword
42
False
It is always possible to convert arguments passed as strings insider keywords.
In simple cases this means using
int()
or
float()
to convert arguments
to numbers, but other kind of conversion is possible as well. When working
with Boolean values, care must be taken because all non-empty strings,
including string
False
, are considered true by Python. Robot Framework's own
robot.utils.is_truthy()
utility handles this nicely as it considers strings
like
FALSE
,
NO
and
NONE
(case-insensitively) to be false:
from
robot.utils
import
is_truthy
def
example_keyword
(
count
,
case_insensitive
):
count
=
int
(
count
)
if
is_truthy
(
case_insensitive
):
...
Keywords can also use Robot Framework's argument conversion functionality via
the
robot.api.TypeInfo
class and its
convert
method. This can be useful
if the needed conversion logic is more complicated or the are needs for better
error reporting than what simply using, for example,
int()
provides.
from
robot.api
import
TypeInfo
def
example_keyword
(
count
,
case_insensitive
):
count
=
TypeInfo
.
from_type
(
int
)
.
convert
(
count
)
if
TypeInfo
.
from_type
(
bool
)
.
convert
(
case_insensitive
):
...
Tip
It is generally recommended to specify types using type hints or otherwise
and let Robot Framework handle argument conversion automatically. Manual
argument conversion should only be needed in special cases.
Note
robot.api.TypeInfo
is new in Robot Framework 7.0.
Specifying argument types using function annotations
Starting from Robot Framework 3.1, arguments passed to keywords are automatically
converted if argument type information is available and the type is recognized.
The most natural way to specify types is using Python
function annotations
.
For example, the keyword in the previous example could be implemented as
follows and arguments would be converted automatically:
def
example_keyword
(
count
:
int
,
case_insensitive
:
bool
=
True
):
if
case_insensitive
:
...
See the
Supported conversions
section below for a list of types that
are automatically converted and what values these types accept. It is
an error if an argument having one of the supported types is given
a value that cannot be converted. Annotating only some of the arguments
is fine.
Annotating arguments with other than the supported types is not an error,
and it is also possible to use annotations for other than typing
purposes. In those cases no conversion is done, but annotations are
nevertheless shown in the documentation generated by
Libdoc
.
Keywords can also have a return type annotation specified using the
->
notation at the end of the signature like
def example() -> int:
.
This information is not used for anything during execution, but starting from
Robot Framework 7.0 it is shown by
Libdoc
for documentation purposes.
Specifying argument types using
@keyword
decorator
An alternative way to specify explicit argument types is using the
@keyword decorator
. Starting from Robot Framework 3.1,
it accepts an optional
types
argument that can be used to specify argument
types either as a dictionary mapping argument names to types or as a list
mapping arguments to types based on position. These approaches are shown
below implementing the same keyword as in earlier examples:
from
robot.api.deco
import
keyword
@keyword
(
types
=
{
'count'
:
int
,
'case_insensitive'
:
bool
})
def
example_keyword
(
count
,
case_insensitive
=
True
):
if
case_insensitive
:
...
@keyword
(
types
=
[
int
,
bool
])
def
example_keyword
(
count
,
case_insensitive
=
True
):
if
case_insensitive
:
...
Regardless of the approach that is used, it is not necessarily to specify
types for all arguments. When specifying types as a list, it is possible
to use
None
to mark that a certain argument does not have type information
and arguments at the end can be omitted altogether. For example, both of these
keywords specify the type only for the second argument:
@keyword
(
types
=
{
'second'
:
float
})
def
example1
(
first
,
second
,
third
):
...
@keyword
(
types
=
[
None
,
float
])
def
example2
(
first
,
second
,
third
):
...
Starting from Robot Framework 7.0, it is possible to specify the keyword return
type by using key
'return'
with an appropriate type in the type dictionary.
This information is not used for anything during execution, but it is shown by
Libdoc
for documentation purposes.
If any types are specified using the
@keyword
decorator, type information
got from
annotations
is ignored with that keyword. Setting
types
to
None
like
@keyword(types=None)
disables type conversion altogether so that also
type information got from
default values
is ignored.
Implicit argument types based on default values
If type information is not got explicitly using annotations or the
@keyword
decorator, Robot Framework 3.1 and newer tries to get it based on possible
argument default value. In this example
count
and
case_insensitive
get
types
int
and
bool
, respectively:
def
example_keyword
(
count
=-
1
,
case_insensitive
=
True
):
if
case_insensitive
:
...
When type information is got implicitly based on the default values,
argument conversion itself is not as strict as when the information is
got explicitly:
Conversion may be attempted also to other "similar" types. For example,
if converting to an integer fails, float conversion is attempted.
Conversion failures are not errors, keywords get the original value in
these cases instead.
If an argument has an explicit type and a default value, conversion is first
attempted based on the explicit type. If that fails, then conversion is attempted
based on the default value. In this special case conversion based on the default
value is strict and a conversion failure causes an error.
If argument conversion based on default values is not desired, the whole
argument conversion can be disabled with the
@keyword decorator
like
@keyword(types=None)
.
Note
Prior to Robot Framework 4.0 conversion was done based on the default
value only if the argument did not have an explict type.
Supported conversions
The table below lists the types that Robot Framework 3.1 and newer convert
arguments to. These characteristics apply to all conversions:
Type can be explicitly specified using
function annotations
or
the
@keyword decorator
.
If not explicitly specified, type can be got implicitly from
argument
default values
.
Conversion is done regardless of the type of the given argument. If the
argument type is incompatible with the expected type, conversion fails.
Conversion failures cause an error if the type has been specified explicitly.
If the type is got based on a default value, the given argument is used as-is.
Note
If an argument has both a type hint and a default value, conversion is
first attempted based on the type hint and then, if that fails, based on
the default value type. This behavior is likely to change in the future
so that conversion based on the default value is done
only
if the argument
does not have a type hint. That will change conversion behavior in cases
like
arg: list = None
where
None
conversion will not be attempted
anymore. Library creators are strongly recommended to specify the default
value type explicitly like
arg: list | None = None
already now.
The type to use can be specified either using concrete types (e.g.
list
),
by using abstract base classes (ABC) (e.g.
Sequence
), or by using sub
classes of these types (e.g.
MutableSequence
). Also types in in the
typing
module that map to the supported concrete types or ABCs (e.g.
List
) are
supported. In all these cases the argument is converted to the concrete type.
In addition to using the actual types (e.g.
int
), it is possible to specify
the type using type names as a string (e.g.
'int'
) and some types also have
aliases (e.g.
'integer'
). Matching types to names and aliases is
case-insensitive.
The Accepts column specifies which given argument types are converted.
If the given argument already has the expected type, no conversion is done.
Other types cause conversion failures.
Supported argument conversions
Type
ABC
Aliases
Accepts
Explanation
Examples
bool
boolean
str
,
int
,
float
,
None
Strings
TRUE
,
YES
,
ON
and
1
are converted to
True
,
the empty string as well as
FALSE
,
NO
,
OFF
and
0
are converted to
False
, and the string
NONE
is converted
to
None
. Other strings and other accepted values are
passed as-is, allowing keywords to handle them specially if
needed. All string comparisons are case-insensitive.
True and false strings can be
localized
. See the
Translations
appendix for supported translations.
TRUE
(converted to
True
)
off
(converted to
False
)
example
(used as-is)
int
Integral
integer,
long
str
,
float
Conversion is done using the
int
built-in function. Floats
are accepted only if they can be represented as integers
exactly. For example,
1.0
is accepted and
1.1
is not.
If converting a string to an integer fails and the type
is got implicitly based on a default value, conversion to
float is attempted as well.
Starting from Robot Framework 4.1, it is possible to use
hexadecimal, octal and binary numbers by prefixing values with
0x
,
0o
and
0b
, respectively.
Starting from Robot Framework 4.1, spaces and underscores can
be used as visual separators for digit grouping purposes.
Starting from Robot Framework 7.0, strings representing floats
are accepted as long as their decimal part is zero. This
includes using the scientific notation like
1e100
.
42
-1
10 000 000
1e100
0xFF
0o777
0b1010
0xBAD_C0FFEE
${1}
${1.0}
float
Real
double
str
,
Real
Conversion is done using the
float
built-in.
Starting from Robot Framework 4.1, spaces and underscores can
be used as visual separators for digit grouping purposes.
3.14
2.9979e8
10 000.000 01
10_000.000_01
Decimal
str
,
int
,
float
Conversion is done using the
Decimal
class.
Decimal
is
recommended over
float
when decimal numbers need to be
represented exactly.
Starting from Robot Framework 4.1, spaces and underscores can
be used as visual separators for digit grouping purposes.
3.14
10 000.000 01
10_000.000_01
str
string,
unicode
Anything
All arguments are converted to Unicode strings.
Most values are converted simply by using
str(value)
.
An exception is that bytes are mapped directly to Unicode
code points with same ordinals. This means that, for example,
b"hyv\xe4"
becomes
"hyvä"
. Another exception is that
Secret
objects are explicitly rejected.
New in Robot Framework 4.0. Converting bytes specially and
rejecting
Secret
objects are new in Robot Framework 7.4.
bytes
str
,
bytearray
Strings are converted to bytes so that each Unicode code point
below 256 is directly mapped to a matching byte. Higher code
points are not allowed.
Integers and sequences of integers are converted to matching
bytes directly. They must be in range 0-255.
Support for integers and sequences of integers is new in
Robot Framework 7.4.
Strings:
good
hyvä
(converted to
hyv\xe4
)
\x00
(converted to the null byte)
Integers and sequences of integers:
0
(converted to the null byte)
[82, 70, 33]
(converted to
RF!
)
bytearray
str
,
bytes
Same conversion as with
bytes
, but the result is a
bytearray
.
datetime
str
,
int
,
float
String timestamps are expected to be in
ISO 8601
like
format
YYYY-MM-DD hh:mm:ss.mmmmmm
, where any non-digit
character can be used as a separator or separators can be
omitted altogether. Additionally, only the date part is
mandatory, all possibly missing time components are considered
to be zeros.
Special values
NOW
and
TODAY
(case-insensitive) can be
used to get the current local
datetime
. This is new in
Robot Framework 7.3.
Integers and floats are considered to represent seconds since
the
Unix epoch
.
2022-02-09T16:39:43.632269
20220209 16:39
2022-02-09
now
(current local date and time)
TODAY
(same as above)
${1644417583.632269}
(Epoch time)
date
str
Same timestamp conversion as with
datetime
, but
all time components are expected to be omitted or to be zeros.
Special values
NOW
and
TODAY
(case-insensitive) can be
used to get the current local
date
. This is new in Robot
Framework 7.3.
2018-09-12
20180912
today
(current local date)
NOW
(same as above)
timedelta
str
,
int
,
float
Strings are expected to represent a time interval in one of
the time formats Robot Framework supports:
time as number
,
time as time string
or
time as "timer" string
. Integers
and floats are considered to be seconds.
42
(42 seconds)
1 minute 2 seconds
01:02
(same as above)
Path
PathLike
str
Strings are converted to
pathlib.Path
objects.
On Windows
/
is converted to
\
automatically.
New in Robot Framework 6.0.
/tmp/absolute/path
relative/path/to/file.ext
name.txt
Enum
str
The specified type must be an enumeration (a subclass of
Enum
or
Flag
) and given arguments must match its member names.
Matching member names is case, space, underscore and hyphen
insensitive, but exact matches have precedence over normalized
matches. Ignoring hyphens is new in Robot Framework 7.0.
Enumeration documentation and members are shown in
documentation generated by
Libdoc
automatically.
class
Direction
(
Enum
):
"""Move direction."""
NORTH
=
auto
()
NORTH_WEST
=
auto
()
def
kw
(
arg
:
Direction
):
...
NORTH
(Direction.NORTH)
north west
(Direction.NORTH_WEST)
IntEnum
str
,
int
The specified type must be an integer based enumeration (a
subclass of
IntEnum
or
IntFlag
) and given arguments must
match its member names or values.
Matching member names works the same way as with
Enum
.
Values can be given as integers and as strings that can be
converted to integers.
Enumeration documentation and members are shown in
documentation generated by
Libdoc
automatically.
New in Robot Framework 4.1.
class
PowerState
(
IntEnum
):
"""Turn system ON or OFF."""
OFF
=
0
ON
=
1
def
kw
(
arg
:
PowerState
):
...
OFF
(PowerState.OFF)
1
(PowerState.ON)
Literal
Depends on
usage
Only specified values are accepted. Values can be strings,
integers, bytes, Booleans, enums and
None
, and used arguments
are converted using the value type specific conversion logic.
Strings are case, space, underscore and hyphen insensitive,
but exact matches have precedence over normalized matches.
Literal
provides similar functionality as
Enum
, but does
not support custom documentation.
New in Robot Framework 7.0.
def
kw
(
arg
:
Literal
[
'ON'
,
'OFF'
]):
...
OFF
on
None
str
String
NONE
(case-insensitive) and the empty string are
converted to the Python
None
object. Other values cause
an error.
Converting the empty string is new in Robot Framework 7.4.
None
Any
Anything
Any value is accepted. No conversion is done.
New in Robot Framework 6.1.
object
Anything
Any value is accepted. No conversion is done.
New in Robot Framework 7.4.
list
str
,
Sequence
Converts strings and sequences to
list
.
Strings must be Python list or tuple literals. They are
converted using the
ast.literal_eval
function and possible
tuples converted further to lists.
They can contain any values
ast.literal_eval
supports,
including lists and other collections.
If the argument is a list, it is used without conversion.
Tuples and other sequences are converted to lists.
Support for tuple literals is new in Robot Framework 7.4.
['one', 'two']
[('one', 1), ('two', 2)]
tuple
str
,
Sequence
Same as
list
, but the result is
tuple
.
Prior to Robot Framework 7.4, only tuple literals were
supported.
('one', 'two')
Sequence
str
,
Sequence
Same as
list
, but any sequence is accepted without
conversion.
If the used type is
MutableSequence
, immutable values are
converted to lists.
[1, 2, 3]
(result is
list
)
(1, 2, 3)
(result is
tuple
)
set
Set
str
,
Collection
Same as
list
, but also collection objects and set literals
are supported and the result is
set
.
Prior to Robot Framework 7.4, only set literals were supported.
{1, 2, 3, 42}
set()
(an empty set)
frozenset
str
,
Collection
Same as
set
, but the result is a
frozenset
.
{1, 2, 3, 42}
frozenset()
(an empty set)
dict
dictionary
str
,
Mapping
Converts strings and mappings to
dict
.
Strings must be Python dictionary literals. They are converted
to
dict
using the
ast.literal_eval
function.
They can contain any values
ast.literal_eval
supports,
including dictionaries and other collections.
{'a': 1, 'b': 2}
{'key': 1, 'nested': {'key': 2}}
Mapping
map
str
,
Mapping
Same as
dict
, but the original mapping type is preserved.
If type is
MutableMapping
, immutable values are converted
to
dict
.
TypedDict
str
,
Mapping
Same as
dict
, but dictionary items are also converted
to the specified types and items not included in the type
spec are not allowed.
New in Robot Framework 6.0. Normal
dict
conversion was
used earlier.
class
Config
(
TypedDict
):
width
:
int
enabled
:
bool
{'width': 1600, 'enabled': True}
Secret
Secret
Using the
Secret type
as a type hint ensures that only
secret variables
are accepted as arguments.
New in Robot Framework 7.4.
from
robot.api.types
import
Secret
def
login
(
token
:
Secret
):
do_something
(
token
.
value
)
Note
Starting from Robot Framework 5.0, types that have a converted are
automatically shown in
Libdoc
outputs.
Note
Prior to Robot Framework 4.0, most types supported converting string
NONE
(case-insensitively) to Python
None
. That support has been removed and
None
conversion is only done if an argument has
None
as an
explicit type or as a default value.
Specifying multiple possible types
It is possible to specify that an argument has multiple possible types. In this
situation argument conversion is attempted based on each type, from left to right,
and the value of the first succeeding conversion is used. If none of these conversions
succeeds, the whole conversion fails.
Union syntax
When using function annotations, the natural syntax to specify that an argument
has multiple possible types is using a
Union
:
from
typing
import
Union
def
example
(
length
:
Union
[
int
,
float
],
padding
:
Union
[
int
,
str
,
None
]
=
None
):
...
When using Python 3.10 or newer, it is possible to use the
native union syntax
like
int | float
instead:
def
example
(
length
:
int
|
float
,
padding
:
int
|
str
|
None
=
None
):
...
Robot Framework 7.0 enhanced the support for the union syntax so that also
"stringly typed" unions like
"int | float"
work. This syntax works also
with older Python versions:
def
example
(
length
:
"int | float"
,
padding
:
"int | str | None"
=
None
):
...
Using tuples
An alternative is specifying types as a tuple. It is not recommended with annotations,
because that syntax is not supported by other tools, but it works well with
the
@keyword
decorator:
from
robot.api.deco
import
keyword
@keyword
(
types
=
{
'length'
:
(
int
,
float
),
'padding'
:
(
int
,
str
,
None
)})
def
example
(
length
,
padding
=
None
):
...
With the above examples the
length
argument would first be converted to an
integer and if that fails then to a float. The
padding
would be first
converted to an integer, then to a string, and finally to
None
.
When argument matches one of the types
If the given argument has one of the accepted types, then no conversion is done
and the argument is used as-is. For example, if the
length
argument typed
like
length: int | float
is used with a floating point number
1.5
, it is not
converted to an integer. Notice that using non-string values like floats as an
argument requires using variables as these examples giving different values to
the
length
argument demonstrate:
*** Test Cases ***
Conversion
Example
10
# Argument is a string. Converted to an integer.
Example
1.5
# Argument is a string. Converted to a float.
Example
${
10
}
# Argument is an integer. Accepted as-is.
Example
${
1.5
}
# Argument is a float. Accepted as-is.
If one of the accepted types is string like in
padding: int | str | None
,
then no conversion is done if the given argument is a string. As the following
examples giving different values to the
padding
argument demonstrate, also in
these cases passing other types is possible using variables:
*** Test Cases ***
Conversion
Example
1
big
# Argument is a string. Accepted as-is.
Example
1
10
# Argument is a string. Accepted as-is.
Example
1
${
10
}
# Argument is an integer. Accepted as-is.
Example
1
${
None
}
# Argument is `None`. Accepted as-is.
Example
1
${
1.5
}
# Argument is a float. Converted to an integer.
If the given argument does not have any of the accepted types, conversion is
attempted in the order types are specified.
Note
The order of types changes the conversion result in cases where the used
value does not match any of the types, but conversion to multiple types
would succeed.
For example, if typing is
float | int
and the used value is string
42
,
the result will be float
42.0
instead of integer
42
. The reason is
that a string does not match either of the types and
float
conversion
is attempted first. If the order is changed to
int | float
, the result
will be an integer.
String
3.14
would be converted to a float regardless the order, because
int
conversion does not succeed. The order does not affect usages where
the value is already an integer or a float either, because there is no
need for conversion in such cases.
Handling
Any
and
object
If
Any
or
object
is used as a type hint on its own like
arg: Any
or
arg: object
,
any value is accepted without conversion. How they work when used in an union differs,
though.
If
Any
is used in a union like
arg: int | Any
, any value is accepted without
conversion. This allows using
Any
as an escape hatch that disables argument conversion
altogether.
On the other hand, if
object
is used in an union like
arg: int | object
,
conversion is attempted to types before
object
. This allows attempting conversion
to certain type or types, but getting the original value if conversions fail.
Note
Although this subtle difference in behavior may be useful, it is also
somewhat confusing and the plan is to change it in Robot Framework 8.0
so that
Any
behaves like
object
. See the issue
#5571
for more
information and comment the issue if you do not think the planned change
is a good idea.
Handling unrecognized types
If types that are not recognized by Robot Framework are used in an union, they are
handled like this:
If a used value matches any of the types, including unrecognized types, the value
is used as-is without conversion.
Otherwise conversion is attempted to recognized types from left to right.
If any conversion succeeds, the converted value is returned.
If no conversion succeeds, the original value is returned.
For example, with the following keyword string
"7"
would be converted to an integer,
but string
"something"
would be used as-is:
def
example
(
argument
:
int
|
Unrecognized
):
...
Starting from Robot Framework 6.1, the above logic works also if an unrecognized
type is listed before a recognized type like
Unrecognized | int
.
Also in this case
int
conversion is attempted, and the argument id passed as-is
if it fails. With earlier Robot Framework versions,
int
conversion would not be
attempted at all.
Parameterized types
With generics also the parameterized syntax like
list[int]
or
dict[str, int]
works. When this syntax is used, the given value is first converted to the base
type and then individual items are converted to the nested types. Conversion
with different generic types works according to these rules:
With lists there can be only one type like
list[float]
. All list items are
converted to that type.
With tuples there can be any number of types like
tuple[int, int]
and
tuple[str, int, bool]
. Tuples used as arguments are expected to have
exactly that amount of items and they are converted to matching types.
To create a homogeneous tuple, it is possible to use exactly one type and
ellipsis like
tuple[int, ...]
. In this case tuple can have any number
of items, including zero, and they are all converted to the specified type.
With dictionaries there must be exactly two types like
dict[str, int]
.
Dictionary keys are converted using the first type and values using the second.
With sets there can be exactly one type like
set[float]
. Conversion logic
is the same as with lists.
Using the native
list[int]
syntax requires
Python 3.9
or newer. If there
is a need to support also earlier Python versions, it is possible to either use
matching types from the
typing
module like
List[int]
or use the "stringly typed"
syntax like
'list[int]'
.
Note
Support for converting nested types with generics is new in
Robot Framework 6.0. Same syntax works also with earlier versions,
but arguments are only converted to the base type and nested type
information is ignored.
Note
Support for "stringly typed" parameterized generics is new in
Robot Framework 7.0.
Secret type
Robot Framework has a custom
robot.api.types.Secret
type that
encapsulates values so that they are not shown in log files. If the
Secret
type is used as an argument type, only
Secret
objects are accepted and trying
to use, for example, literal strings fails. The encapsulated value is available
in the
value
attribute so keywords can access it easily:
from
example
import
SUT
from
robot.api.types
import
Secret
def
login_to_sut
(
user
:
str
,
token
:
Secret
):
SUT
.
login
(
user
,
token
.
value
)
The
Secret variables
section explains how to create
Secret
objects
in the data, on the command line, and elsewhere. In the data that involves
using
variable type conversion
and, for example,
environment variables
:
*** Variables ***
${
USER
}
robot
${
TOKEN: Secret
} %{
ROBOT_TOKEN
}
*** Test Cases ***
Example
Login to SUT
${
USER
} ${
TOKEN
}
Keywords can also accept
Secret
objects in addition to strings by using
the union syntax like
str | Secret
:
from
example
import
SUT
from
robot.api
import
logger
from
robot.api.types
import
Secret
def
input_password
(
password
:
str
|
Secret
):
logger
.
debug
(
f
"Typing password:
{
password
}
"
)
if
isinstance
(
password
,
Secret
):
password
=
password
.
value
SUT
.
input_password
(
password
)
In this kind of cases it is important to not log or otherwise disclose actual
secret values. The string representation of
Secret
objects is always
<secret>
and thus logging
f"Typing password: {password}"
in the above
example is safe, but logging it at the end of the example would not be.
The
repr()
of
Secret
objects is
Secret(value=<secret>)
so the real
value is not shown in that string representation either.
Using the
Secret
type in complex type hints works similarly as with other types.
The following example is similar to the example above, but uses a
TypedDict
with a
Secret
item:
from
typing
import
TypedDict
from
robot.api.types
import
Secret
class
Credential
(
TypedDict
):
user
:
str
token
:
Secret
def
login_to_sut
(
credentials
:
Credential
):
SUT
.
login
(
credentials
[
"user"
],
credentials
[
"token"
]
.
value
)
*** Variables ***
${
TOKEN: Secret
} %{
ROBOT_TOKEN
}
&{
CREDENTIALS
}
user=robot
token=
${
TOKEN
}
*** Test Cases ***
Example
Login to SUT
${
CREDENTIALS
}
Warning
Secret objects do not hide or encrypt their values. The real values
are thus available for all code that can access these objects directly
or indirectly via Robot Framework APIs.
Warning
Actual secret values that keywords pass forward may be logged or
otherwise disclosed by external modules or tools using them.
Note
The
Secret
type is new in Robot Framework 7.4.
Custom argument converters
In addition to doing argument conversion automatically as explained in the
previous sections, Robot Framework supports custom argument conversion. This
functionality has two main use cases:
Overriding the standard argument converters provided by the framework.
Adding argument conversion for custom types and for other types not supported
out-of-the-box.
Argument converters are functions or other callables that get arguments used
in data and convert them to desired format before arguments are passed to
keywords. Converters are registered for libraries by setting
ROBOT_LIBRARY_CONVERTERS
attribute (case-sensitive) to a dictionary mapping
desired types to converts. When implementing a library as a module, this
attribute must be set on the module level, and with class based libraries
it must be a class attribute. With libraries implemented as classes, it is
also possible to use the
converters
argument with the
@library decorator
.
Both of these approaches are illustrated by examples in the following sections.
Note
Custom argument converters are new in Robot Framework 5.0.
Overriding default converters
Let's assume we wanted to create a keyword that accepts
date
objects for
users in Finland where the commonly used date format is
dd.mm.yyyy
.
The usage could look something like this:
*** Test Cases ***
Example
Keyword
25.1.2022
Automatic argument conversion
supports dates, but it expects them
to be in
yyyy-mm-dd
format so it will not work. A solution is creating
a custom converter and registering it to handle
date
conversion:
from
datetime
import
date
# Converter function.
def
parse_fi_date
(
value
):
day
,
month
,
year
=
value
.
split
(
'.'
)
return
date
(
int
(
year
),
int
(
month
),
int
(
day
))
# Register converter function for the specified type.
ROBOT_LIBRARY_CONVERTERS
=
{
date
:
parse_fi_date
}
# Keyword using custom converter. Converter is resolved based on argument type.
def
keyword
(
arg
:
date
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
Conversion errors
If we try using the above keyword with invalid argument like
invalid
, it
fails with this error:
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: not enough values to unpack (expected 3, got 1)
This error is not too informative and does not tell anything about the expected
format. Robot Framework cannot provide more information automatically, but
the converter itself can be enhanced to validate the input. If the input is
invalid, the converter should raise a
ValueError
with an appropriate message.
In this particular case there would be several ways to validate the input, but
using
regular expressions
makes it possible to validate both that the input
has dots (
.
) in correct places and that date parts contain correct amount
of digits:
from
datetime
import
date
import
re
def
parse_fi_date
(
value
):
# Validate input using regular expression and raise ValueError if not valid.
match
=
re
.
match
(
r
'(\d{1,2})\.(\d{1,2})\.(\d
{4}
)$'
,
value
)
if
not
match
:
raise
ValueError
(
f
"Expected date in format 'dd.mm.yyyy', got '
{
value
}
'."
)
day
,
month
,
year
=
match
.
groups
()
return
date
(
int
(
year
),
int
(
month
),
int
(
day
))
ROBOT_LIBRARY_CONVERTERS
=
{
date
:
parse_fi_date
}
def
keyword
(
arg
:
date
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
With the above converter code, using the keyword with argument
invalid
fails
with a lot more helpful error message:
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: Expected date in format 'dd.mm.yyyy', got 'invalid'.
Restricting value types
By default Robot Framework tries to use converters with all given arguments
regardless their type. This means that if the earlier example keyword would
be used with a variable containing something else than a string, conversion
code would fail in the
re.match
call. For example, trying to use it with
argument
${42}
would fail like this:
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date: TypeError: expected string or bytes-like object
This error situation could naturally handled in the converter code by checking
the value type, but if the converter only accepts certain types, it is typically
easier to just restrict the value to that type. Doing it requires only adding
appropriate type hint to the converter:
def
parse_fi_date
(
value
:
str
):
...
Notice that this type hint
is not
used for converting the value before calling
the converter, it is used for strictly restricting which types can be used.
With the above addition calling the keyword with
${42}
would fail like this:
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date.
If the converter can accept multiple types, it is possible to specify types
as a
Union
. For example, if we wanted to enhance our keyword to accept also
integers so that they would be considered seconds since the
Unix epoch
,
we could change the converter like this:
from
datetime
import
date
import
re
from
typing
import
Union
# Accept both strings and integers.
def
parse_fi_date
(
value
:
Union
[
str
,
int
]):
# Integers are converted separately.
if
isinstance
(
value
,
int
):
return
date
.
fromtimestamp
(
value
)
match
=
re
.
match
(
r
'(\d{1,2})\.(\d{1,2})\.(\d
{4}
)$'
,
value
)
if
not
match
:
raise
ValueError
(
f
"Expected date in format 'dd.mm.yyyy', got '
{
value
}
'."
)
day
,
month
,
year
=
match
.
groups
()
return
date
(
int
(
year
),
int
(
month
),
int
(
day
))
ROBOT_LIBRARY_CONVERTERS
=
{
date
:
parse_fi_date
}
def
keyword
(
arg
:
date
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
Converting custom types
A problem with the earlier example is that
date
objects could only be given
in
dd.mm.yyyy
format. It would not work if there was a need to
support dates in different formats like in this example:
*** Test Cases ***
Example
Finnish
25.1.2022
US
1/25/2022
ISO 8601
2022-01-22
A solution to this problem is creating custom types instead of overriding
the default
date
conversion:
from
datetime
import
date
import
re
from
typing
import
Union
from
robot.api.deco
import
keyword
,
library
# Custom type. Extends an existing type but that is not required.
class
FiDate
(
date
):
# Converter function implemented as a classmethod. It could be a normal
# function as well, but this way all code is in the same class.
@classmethod
def
from_string
(
cls
,
value
:
str
):
match
=
re
.
match
(
r
'(\d{1,2})\.(\d{1,2})\.(\d
{4}
)$'
,
value
)
if
not
match
:
raise
ValueError
(
f
"Expected date in format 'dd.mm.yyyy', got '
{
value
}
'."
)
day
,
month
,
year
=
match
.
groups
()
return
cls
(
int
(
year
),
int
(
month
),
int
(
day
))
# Another custom type.
class
UsDate
(
date
):
@classmethod
def
from_string
(
cls
,
value
:
str
):
match
=
re
.
match
(
r
'(\d{1,2})/(\d{1,2})/(\d
{4}
)$'
,
value
)
if
not
match
:
raise
ValueError
(
f
"Expected date in format 'mm/dd/yyyy', got '
{
value
}
'."
)
month
,
day
,
year
=
match
.
groups
()
return
cls
(
int
(
year
),
int
(
month
),
int
(
day
))
# Register converters using '@library' decorator.
@library
(
converters
=
{
FiDate
:
FiDate
.
from_string
,
UsDate
:
UsDate
.
from_string
})
class
Library
:
# Uses custom converter supporting 'dd.mm.yyyy' format.
@keyword
def
finnish
(
self
,
arg
:
FiDate
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
# Uses custom converter supporting 'mm/dd/yyyy' format.
@keyword
def
us
(
self
,
arg
:
UsDate
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
# Uses IS0-8601 compatible default conversion.
@keyword
def
iso_8601
(
self
,
arg
:
date
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
# Accepts date in different formats.
@keyword
def
any
(
self
,
arg
:
Union
[
FiDate
,
UsDate
,
date
]):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
Strict type validation
Converters are not used at all if the argument is of the specified type to
begin with. It is thus easy to enable strict type validation with a custom
converter that does not accept any value. For example, the
Example
keyword accepts only
StrictType
instances:
class
StrictType
:
pass
def
strict_converter
(
arg
):
raise
TypeError
(
f
'Only StrictType instances accepted, got
{
type
(
arg
)
.
__name__
}
.'
)
ROBOT_LIBRARY_CONVERTERS
=
{
StrictType
:
strict_converter
}
def
example
(
argument
:
StrictType
):
assert
isinstance
(
argument
,
StrictType
)
As a convenience, Robot Framework allows setting converter to
None
to get
the same effect. For example, this code behaves exactly the same way as
the code above:
class
StrictType
:
pass
ROBOT_LIBRARY_CONVERTERS
=
{
StrictType
:
None
}
def
example
(
argument
:
StrictType
):
assert
isinstance
(
argument
,
StrictType
)
Note
Using
None
as a strict converter is new in Robot Framework 6.0.
An explicit converter function needs to be used with earlier versions.
Accessing the test library from converter
Starting from Robot Framework 6.1, it is possible to access the library
instance from a converter function. This allows defining dynamic type conversions
that depend on the library state. For example, if the library can be configured to
test particular locale, you might use the library state to determine how a date
should be parsed like this:
from
datetime
import
date
import
re
def
parse_date
(
value
,
library
):
# Validate input using regular expression and raise ValueError if not valid.
# Use locale based from library state to determine parsing format.
if
library
.
locale
==
'en_US'
:
match
=
re
.
match
(
r
'(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<year>\d
{4}
)$'
,
value
)
format
=
'mm/dd/yyyy'
else
:
match
=
re
.
match
(
r
'(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d
{4}
)$'
,
value
)
format
=
'dd.mm.yyyy'
if
not
match
:
raise
ValueError
(
f
"Expected date in format '
{
format
}
', got '
{
value
}
'."
)
return
date
(
int
(
match
.
group
(
'year'
)),
int
(
match
.
group
(
'month'
)),
int
(
match
.
group
(
'day'
)))
ROBOT_LIBRARY_CONVERTERS
=
{
date
:
parse_date
}
def
keyword
(
arg
:
date
):
print
(
f
'year:
{
arg
.
year
}
, month:
{
arg
.
month
}
, day:
{
arg
.
day
}
'
)
The
library
argument to converter function is optional, i.e. if the converter function
only accepts one argument, the
library
argument is omitted. Similar result can be achieved
by making the converter function accept only variadic arguments, e.g.
def parse_date(*varargs)
.
Converter documentation
Information about converters is added to outputs produced by
Libdoc
automatically. This information includes the name of the type, accepted values
(if specified using type hints) and documentation. Type information is
automatically linked to all keywords using these types.
Used documentation is got from the converter function by default. If it does
not have any documentation, documentation is got from the type. Both of these
approaches to add documentation to converters in the previous example thus
produce the same result:
class
FiDate
(
date
):
@classmethod
def
from_string
(
cls
,
value
:
str
):
"""Date in ``dd.mm.yyyy`` format."""
...
class
UsDate
(
date
):
"""Date in ``mm/dd/yyyy`` format."""
@classmethod
def
from_string
(
cls
,
value
:
str
):
...
Adding documentation is in general recommended to provide users more
information about conversion. It is especially important to document
converter functions registered for existing types, because their own
documentation is likely not very useful in this context.
@keyword
decorator
Although Robot Framework gets lot of information about keywords automatically,
such as their names and arguments, there are sometimes needs to configure this
information further. This is typically easiest done by using the
robot.api.deco.keyword
decorator. It has several useful usages that are
explained thoroughly elsewhere and only listened here as a reference:
Exposing methods and functions as keywords when the
automatic keyword
discovery
has been disabled by using the
@library decorator
or
otherwise.
Setting a
custom name
to a keyword. This is especially useful when using
the
embedded argument syntax
.
Setting
keyword tags
.
Setting
type information
to enable automatic argument type conversion.
Supports also disabling the argument conversion altogether.
Marking methods to expose as keywords
when using the
dynamic library API
or the
hybrid library API
.
@not_keyword
decorator
The
robot.api.deco.not_keyword
decorator can be used for
disabling functions or methods becoming keywords
.
Using custom decorators
When implementing keywords, it is sometimes useful to modify them with
Python decorators
. However, decorators often modify function signatures
and can thus confuse Robot Framework's introspection when determining which
arguments keywords accept. This is especially problematic when creating
library documentation with
Libdoc
and when using external tools like
RIDE
.
The easiest way to avoid this problem is decorating the
decorator itself using
functools.wraps
. Other solutions include using
external modules like
decorator
and
wrapt
that allow creating fully
signature-preserving decorators.
Note
Support for "unwrapping" decorators decorated with
functools.wraps
is a new feature in Robot Framework 3.2.
Embedding arguments into keyword names
Library keywords can also accept
embedded arguments
the same way as
user keywords
. This section mainly covers the Python syntax to use to
create such keywords, the embedded arguments syntax itself is covered in
detail as part of
user keyword documentation
.
Library keywords with embedded arguments need to have a
custom name
that
is typically set using the
@keyword decorator
. Values matching embedded
arguments are passed to the function or method implementing the keyword as
positional arguments. If the function or method accepts more arguments, they
can be passed to the keyword as normal positional or named arguments.
Argument names do not need to match the embedded argument names, but that
is generally a good convention.
Keywords accepting embedded arguments:
from
robot.api.deco
import
keyword
@keyword
(
'Select $
{animal}
from list'
)
def
select_animal_from_list
(
animal
):
...
@keyword
(
'Number of $
{animals}
should be'
)
def
number_of_animals_should_be
(
animals
,
count
):
...
Tests using the above keywords:
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
Embedded and normal arguments
Number of cats should be
2
Number of dogs should be
count=3
If type information is specified, automatic
argument conversion
works also
with embedded arguments:
@keyword
(
'Add $
{quantity}
copies of $
{item}
to cart'
)
def
add_copies_to_cart
(
quantity
:
int
,
item
:
str
):
...
Note
Embedding type information to keyword names like
Add ${quantity: int} copies of ${item: str} to cart
similarly
as with
user keywords
is not supported
with library keywords.
Note
Support for mixing embedded arguments and normal arguments is new
in Robot Framework 7.0.
Asynchronous keywords
Starting from Robot Framework 6.1, it is possible to run native asynchronous
functions (created by
async def
) just like normal functions:
import
asyncio
from
robot.api.deco
import
keyword
@keyword
async
def
this_keyword_waits
():
await
asyncio
.
sleep
(
5
)
You can get the reference of the loop using
asyncio.get_running_loop()
or
asyncio.get_event_loop()
. Be careful when modifying how the loop runs, it is
a global resource. For example, never call
loop.close()
because it will make it
impossible to run any further coroutines. If you have any function or resource that
requires the event loop, even though
await
is not used explicitly, you have to define
your function as async to have the event loop available.
More examples of functionality:
import
asyncio
from
robot.api.deco
import
keyword
async
def
task_async
():
await
asyncio
.
sleep
(
5
)
@keyword
async
def
examples
():
tasks
=
[
task_async
()
for
_
in
range
(
10
)]
results
=
await
asyncio
.
gather
(
*
tasks
)
background_task
=
asyncio
.
create_task
(
task_async
())
await
background_task
# If running with Python 3.10 or higher
async
with
asyncio
.
TaskGroup
()
as
tg
:
task1
=
tg
.
create_task
(
task_async
())
task2
=
tg
.
create_task
(
task_async
())
Note
Robot Framework waits for the function to complete. If you want to have a task that runs
for a long time, use, for example,
asyncio.create_task()
. It is your responsibility to
manage the task and save a reference to avoid it being garbage collected. If the event loop
closes and a task is still pending, a message will be printed to the console.
Note
If execution of keyword cannot continue for some reason, for example a signal stop,
Robot Framework will cancel the async task and any of its children. Other async tasks will
continue running normally.
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
.
Normal execution failures and errors can be reported using the standard exceptions
such as
AssertionError
,
ValueError
and
RuntimeError
. There are, however, some
special cases explained in the subsequent sections where special exceptions are needed.
Error messages
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
.
It is possible to avoid adding the
exception type as a prefix to failure message also with non generic exceptions.
This is done by adding a special
ROBOT_SUPPRESS_NAME
attribute with
value
True
to your exception.
Python:
class
MyError
(
RuntimeError
):
ROBOT_SUPPRESS_NAME
=
True
In all cases, it is important for the users that the exception message is as
informative as possible.
HTML in error messages
It is also possible to have HTML formatted
error messages by starting the message with text
*HTML*
:
raise
AssertionError
(
"*HTML* <a href='robotframework.org'>Robot Framework</a> rulez!!"
)
This method can be used both when raising an exception in a library, like
in the example above, and
when users provide an error message in the test data
.
Cutting long messages automatically
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.
Tracebacks
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
.
Exceptions provided by Robot Framework
Robot Framework provides some exceptions that libraries can use for reporting
failures and other events. These exceptions are exposed via the
robot.api
package and contain the following:
Failure
Report failed validation. There is no practical difference in using this exception
compared to using the standard
AssertionError
. The main benefit of using this
exception is that its name is consistent with other provided exceptions.
Error
Report error in execution. Failures related to the system not behaving as expected
should typically be reported using the
Failure
exception or the standard
AssertionError
. This exception can be used, for example, if the keyword is used
incorrectly. There is no practical difference, other than consistent naming with
other provided exceptions, compared to using this exception and the standard
RuntimeError
.
ContinuableFailure
Report failed validation but allow continuing execution.
See the
Continuable failures
section below for more information.
SkipExecution
Mark the executed test or task
skipped
.
See the
Skipping tests
section below for more information.
FatalError
Report error that stops the whole execution.
See the
Stopping test execution
section below for more information.
Note
All these exceptions are new in Robot Framework 4.0. Other features than
skipping tests, which is also new in Robot Framework 4.0, are available
by other means in earlier versions.
Continuable failures
It is possible to
continue test execution even when there are failures
.
The easiest way to do that is using the
provided
robot.api.ContinuableFailure
exception:
from
robot.api
import
ContinuableFailure
def
example_keyword
():
if
something_is_wrong
():
raise
ContinuableFailure
(
'Something is wrong but execution can continue.'
)
...
An alternative is creating a custom exception that has a special
ROBOT_CONTINUE_ON_FAILURE
attribute set to a
True
value.
This is demonstrated by the example below.
class
MyContinuableError
(
RuntimeError
):
ROBOT_CONTINUE_ON_FAILURE
=
True
Skipping tests
It is possible to
skip
tests with a library keyword. The easiest way to
do that is using the
provided
robot.api.SkipExecution
exception:
from
robot.api
import
SkipExecution
def
example_keyword
():
if
test_should_be_skipped
():
raise
SkipExecution
(
'Cannot proceed, skipping test.'
)
...
An alternative is creating a custom exception that has a special
ROBOT_SKIP_EXECUTION
attribute set to a
True
value.
This is demonstrated by the example below.
class
MySkippingError
(
RuntimeError
):
ROBOT_SKIP_EXECUTION
=
True
Stopping test execution
It is possible to fail a test case so that
the whole test execution is
stopped
. The easiest way to accomplish this is using the
provided
robot.api.FatalError
exception:
from
robot.api
import
FatalError
def
example_keyword
():
if
system_is_not_running
():
raise
FatalError
(
'System is not running!'
)
...
In addition to using the
robot.api.FatalError
exception, it is possible create
a custom exception that has a special
ROBOT_EXIT_ON_FAILURE
attribute set to
a
True
value. This is illustrated by the example below.
class
MyFatalError
(
RuntimeError
):
ROBOT_EXIT_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
.
In this formant
*LEVEL*
must be in the beginning of a line and
LEVEL
must be one of the available concrete log levels
TRACE
,
DEBUG
,
INFO
,
WARN
or
ERROR
, or a pseudo log level
HTML
or
CONSOLE
.
The pseudo levels can be used for
logging HTML
and
logging to console
,
respectively.
Errors and warnings
Messages with
ERROR
or
WARN
level are automatically written to the
console and a separate
Test Execution Errors section
in the log
files. This makes these messages more visible than others 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, for example, one badly placed
</table>
tag can ruin
the log file quite badly.
When using the
public logging API
, various logging methods
have optional
html
attribute that can be set to
True
to enable logging in HTML format.
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.
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.
It is, however, even easier to get accurate timestamps using the
programmatic logging APIs
. A big benefit of adding timestamps explicitly
is that this approach works also with the
remote library interface
.
import
time
def
example_keyword
():
timestamp
=
int
(
time
.
time
()
*
1000
)
print
(
f
'*INFO:
{
timestamp
}
* Message with timestamp'
)
Logging to console
Libraries have several options for writing messages to the console.
As already discussed, warnings and 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.
Starting from Robot Framework 6.1, libraries can use a pseudo log level
CONSOLE
for logging messages
both
to the log file and to the console:
def
my_keyword
(
arg
):
print
(
'*CONSOLE* Message both to log and to console.'
)
These messages will be logged to the log file using the
INFO
level similarly
as with the
HTML
pseudo log level. When using this approach, messages
are logged to the console only after the keyword execution ends.
Another option is writing messages to
sys.__stdout__
or
sys.__stderr__
.
When using this approach, messages are written to the console immediately
and are not written to the log file at all:
import
sys
def
my_keyword
(
arg
):
print
(
'Message only to console.'
,
file
=
sys
.
__stdout__
)
The final option is using the
public logging API
. Also in with this approach
messages are written to the console immediately:
from
robot.api
import
logger
def
log_to_console
(
arg
):
logger
.
console
(
'Message only to console.'
)
def
log_to_console_and_log_file
(
arg
):
logger
.
info
(
'Message both to log and to console.'
,
also_console
=
True
)
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
or
ERROR
level can
be used to make messages more visible and
HTML
is useful if any
kind of formatting is needed. Level
CONSOLE
can be used when the
message needs to shown both in console and in the log file.
The following examples clarify how logging with different levels
works.
print
(
'Hello from a library.'
)
print
(
'*WARN* Warning from a library.'
)
print
(
'*ERROR* Something unexpected happen that may indicate a problem in the test.'
)
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
(
'*CONSOLE* This logs into console and log file.'
)
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
ERROR
Something unexpected happen that may indicate a problem in the test.
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 logs into console and log file.
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.
Public logging API
Robot Framework has a 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
.
The public logging API
is thoroughly documented
as part of the API
documentation at
https://robot-framework.readthedocs.org
. Below is
a simple usage example:
from
robot.api
import
logger
def
my_keyword
(
arg
):
logger
.
debug
(
f
"Got argument '
{
arg
}
'."
)
do_something
()
logger
.
info
(
'<i>This</i> is a boring example'
,
html
=
True
)
logger
.
console
(
'Hello, console!'
)
An obvious limitation is that test libraries using this logging API have
a dependency to Robot Framework. If Robot Framework is not running,
the messages are redirected automatically to Python's standard
logging
module.
Using Python's standard
logging
module
In addition to the new
public logging API
, Robot Framework offers 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
(
f
"Got argument '
{
arg
}
'."
)
do_something
()
logging
.
info
(
'This is a boring example'
)
The
logging
module has slightly different log levels than
Robot Framework. Its levels
DEBUG
,
INFO
,
WARNING
and
ERROR
are mapped
directly to the matching Robot Framework log levels, and
CRITICAL
is mapped to
ERROR
. Custom log levels are mapped to the closest
standard level smaller than the custom level. For example, a level
between
INFO
and
WARNING
is mapped to Robot Framework's
INFO
level.
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
or
ERROR
levels 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.
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__
, the messages may be
logged multiple times depending on the
library scope
.
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 in 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
)
*** Test Cases ***
Returning one value
${
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 lists or list-like objects.
def
return_two_values
():
return
'first value'
,
'second value'
def
return_multiple_values
():
return
[
'a'
,
'list'
,
'of'
,
'strings'
]
*** Test Cases ***
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
${
s1
}
${
s2
}
a list
Should Be Equal
@{
li
}[
0
]
@{
li
}[
1
]
of strings
Detecting is Robot Framework running
Starting from Robot Framework 6.1, it is easy to detect is Robot Framework
running at all and is the dry-run mode active by using the
robot_running
and
dry_run_active
properties of the BuiltIn library. A relatively common
use case is that library initializers may want to avoid doing some work if
the library is not used during execution but is initialized, for example,
by
Libdoc
:
from
robot.libraries.BuiltIn
import
BuiltIn
class
MyLibrary
:
def
__init__
(
self
):
builtin
=
BuiltIn
()
if
builtin
.
robot_running
and
not
builtin
.
dry_run_active
:
# Do some initialization that only makes sense during real execution.
For more information about using the BuiltIn library as a programmatic API,
including another example using
robot_running
, see the
Using BuiltIn library
section.
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 the worst 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.
Messages logged by non-main threads using the normal logging methods from
programmatic logging APIs
are silently ignored.
There is also a
BackgroundLogger
in separate
robotbackgroundlogger
project,
with a similar API as the standard
robot.api.logger
. Normal logging
methods will ignore messages from other than main thread, but the
BackgroundLogger
will save the background messages so that they can be later
logged to Robot's log.
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
as in the example 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
Python has 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
. This tool can
create a library documentation from 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 logical line of a keyword documentation, until the first empty line,
is used for a special purpose and should contain a short overall description
of the keyword. It is used as a
short documentation
by
Libdoc
(for example,
as a tool tip) and also shown in the
test logs
.
By default documentation is considered to follow Robot Framework's
documentation formatting
rules. This simple format allows often used
styles like
*bold*
and
_italic_
, tables, lists, links, etc.
It is possible to use also HTML, plain
text and
reStructuredText
formats. See the
Documentation format
section for information how to set the format in the library source code and
Libdoc
chapter for more information about the formats in general.
Note
Prior to Robot Framework 3.1, the short documentation contained
only the first physical line of the keyword documentation.
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.
Python has 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
module 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. For information about packaging and
distributing Python code see
https://packaging.python.org/
. When such
a package is installed using
pip
or other tools, it is automatically
in the
module search path
.
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 can be deprecated by starting their documentation with text
*DEPRECATED
, case-sensitive, and having a closing
*
also on the first
line of the documentation. For example,
*DEPRECATED*
,
*DEPRECATED.*
, and
*DEPRECATED in version 1.5.*
are all valid markers.
When a deprecated keyword is executed, a deprecation warning is logged and
the warning is shown also in
the console and the Test Execution Errors
section in log files
. The deprecation warning starts with text
Keyword
'<name>' is deprecated.
and has rest of the
short documentation
after
the deprecation marker, if any, afterwards. For example, if the 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 results.
"""
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
.
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. In other words, users do not need to know what APIs their
libraries use.
Only differences between static and dynamic libraries are
how Robot Framework discovers what keywords a library implements,
what arguments and documentation these keywords have, and how the
keywords are actually executed. With the static API, all this is
done using reflection, 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 must have all
keywords in one class or module, whereas with the dynamic API, you can,
for example, implement each keyword as a separate class. This use case is
not so important with Python, though, because its dynamic capabilities and
multi-inheritance already give plenty of flexibility, and there is also
possibility to use the
hybrid library API
.
Another major use case for the dynamic API is implementing a library
so that it works as proxy for an actual library possibly running on
some other process or even on another machine. This kind of a proxy
library can be very thin, and because keyword names and all other
information is got dynamically, there is no need to update the proxy
when new keywords are added to 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.
Python users may also find the
PythonLibCore
project useful.
Getting keyword names
Dynamic libraries tell what keywords they implement with the
get_keyword_names
method. This
method cannot take any arguments, and it must return a list or array
of strings 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 be mapped to 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.
Marking methods to expose as keywords
If a dynamic library should contain both methods which are meant to be keywords
and methods which are meant to be private helper methods, it may be wise to
mark the keyword methods as such so it is easier to implement
get_keyword_names
.
The
robot.api.deco.keyword
decorator allows an easy way to do this since it
creates a
custom 'robot_name' attribute
on the decorated method.
This allows generating the list of keywords just by checking for the
robot_name
attribute on every method in the library during
get_keyword_names
.
from
robot.api.deco
import
keyword
class
DynamicExample
:
def
get_keyword_names
(
self
):
# Get all attributes and their values from the library.
attributes
=
[(
name
,
getattr
(
self
,
name
))
for
name
in
dir
(
self
)]
# Filter out attributes that do not have 'robot_name' set.
keywords
=
[(
name
,
value
)
for
name
,
value
in
attributes
if
hasattr
(
value
,
'robot_name'
)]
# Return value of 'robot_name', if given, or the original 'name'.
return
[
value
.
robot_name
or
name
for
name
,
value
in
keywords
]
def
helper_method
(
self
):
...
@keyword
def
keyword_method
(
self
):
...
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
run_keyword
method to get it executed. This method takes two or three 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
positional arguments
given to the keyword in
the test data, and the optional third argument is a dictionary
containing
named arguments
. If the third argument is missing,
free named
arguments
and
named-only arguments
are not supported, and other
named arguments are mapped to positional arguments.
Note
Prior to Robot Framework 3.1, normal named arguments were
mapped to positional arguments regardless did
run_keyword
accept two or three arguments. The third argument only got
possible free named arguments.
After getting keyword name and arguments, the library 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 or by using the provided logging APIs, 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 but rest of the methods in the dynamic
API are optional. 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
,
named_args
):
print
(
f
"Running keyword '
{
name
}
' with positional arguments
{
args
}
"
f
"and named arguments
{
named_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 accept. For example,
both
First Keyword
and
Second Keyword
in the example above
could be used with any 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 communicate what arguments their keywords expect
by using the
get_keyword_arguments
(alias
getKeywordArguments
) method.
This method gets the name of a keyword as an argument, and it must return
a list of strings containing the arguments accepted by that keyword.
Similarly as other keywords, dynamic keywords can require any number
of
positional arguments
, have
default values
, accept
variable number of
arguments
, accept
free named arguments
and have
named-only arguments
.
The syntax how to represent all these different variables is derived from how
they are specified in Python and explained in the following table.
Representing different arguments with
get_keyword_arguments
Argument type
How to represent
Examples
No arguments
Empty list.
[]
One or more
positional
argument
List of strings containing
argument names.
['argument']
['arg1', 'arg2', 'arg3']
Default values
Two ways how to represent
the argument name and the
default value:
As a string where the
name and the default are
separated with
=
.
As a tuple with the name
and the default as
separate items. New in
Robot Framework 3.2.
String with
=
separator:
['name=default']
['a', 'b=1', 'c=2']
Tuple:
[('name', 'default')]
['a', ('b', 1), ('c', 2)]
Positional-only
arguments
Arguments before the
/
marker. New in Robot
Framework 6.1.
['posonly', '/']
['p', 'q', '/', 'normal']
Variable number
of arguments
(varargs)
Argument after possible
positional arguments has
a
*
prefix
['*varargs']
['argument', '*rest']
['a', 'b=42', '*c']
Named-only
arguments
Arguments after varargs or
a lone
*
if there are no
varargs. With or without
defaults. Requires
run_keyword
to
support
named-only arguments
.
New in Robot Framework 3.1.
['*varargs', 'named']
['*', 'named']
['*', 'x', 'y=default']
['a', '*b', ('c', 42)]
Free named
arguments
(kwargs)
Last arguments has
**
prefix. Requires
run_keyword
to
support
free named arguments
.
['**named']
['a', ('b', 42), '**c']
['*varargs', '**kwargs']
['*', 'kwo', '**kws']
When the
get_keyword_arguments
is used, Robot Framework automatically
calculates how many positional arguments the keyword requires and does it
support free named arguments or not. If a keyword is used with invalid
arguments, an error occurs and
run_keyword
is not even called.
The actual argument names and default values that are returned are also
important. They are needed for
named argument support
and the
Libdoc
tool needs them to be able to create a meaningful library documentation.
As explained in the above table, default values can be specified with argument
names either as a string like
'name=default'
or as a tuple like
('name', 'default')
. The main problem with the former syntax is that all
default values are considered strings whereas the latter syntax allows using
all objects like
('integer', 1)
or
('boolean', True)
. When using other
objects than strings, Robot Framework can do
automatic argument conversion
based on them.
For consistency reasons, also arguments that do not accept default values can
be specified as one item tuples. For example,
['a', 'b=c', '*d']
and
[('a',), ('b', 'c'), ('*d',)]
are equivalent.
If
get_keyword_arguments
is missing or returns Python
None
for a certain
keyword, that keyword gets an argument specification
accepting all arguments. This automatic argument spec is either
[*varargs, **kwargs]
or
[*varargs]
, depending does
run_keyword
support free named arguments
or not.
Note
Support to specify arguments as tuples like
('name', 'default')
is new in Robot Framework 3.2. Support for positional-only arguments
in dynamic library API is new in Robot Framework 6.1.
Getting keyword argument types
Robot Framework 3.1 introduced support for automatic argument conversion
and the dynamic library API supports that as well. The conversion logic
works exactly like with
static libraries
, but how the type information
is specified is naturally different.
With dynamic libraries types can be returned using the optional
get_keyword_types
method (alias
getKeywordTypes
). It can return types
using a list or a dictionary exactly like types can be specified when using
the
@keyword decorator
. Type information can be specified using actual
types like
int
, but especially if a dynamic library gets this information
from external systems, using strings like
'int'
or
'integer'
may be
easier. See the
Supported conversions
section for more information about
supported types and how to specify them.
Robot Framework does automatic argument conversion also based on the
argument default values
. Earlier this did not work with the dynamic API
because it was possible to specify arguments only as strings. As
discussed in the previous section
, this was changed in Robot Framework
3.2 and nowadays default values returned like
('example', True)
are
automatically used for this purpose.
Starting from Robot Framework 7.0, dynamic libraries can also specify the
keyword return type by using key
'return'
with an appropriate type in the
returned type dictionary. This information is not used for anything during
execution, but it is shown by
Libdoc
for documentation purposes.
Getting keyword documentation
If dynamic libraries want to provide keyword documentation, they can implement
the
get_keyword_documentation
method (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.
The main use case is getting keywords' documentations into a
library documentation generated by
Libdoc
. 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
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
in practice.
Dynamic libraries can also specify the general library
documentation directly in the code as the docstring of the library
class and its
__init__
method. If a non-empty documentation is
got both directly from the code and from the
get_keyword_documentation
method, the latter has precedence.
Getting keyword source information
The dynamic API masks the real implementation of keywords from Robot Framework
and thus makes it impossible to see where keywords are implemented. This
means that editors and other tools utilizing Robot Framework APIs cannot
implement features such as go-to-definition. This problem can be solved by
implementing yet another optional dynamic method named
get_keyword_source
(alias
getKeywordSource
) that returns the source information.
The return value from the
get_keyword_source
method must be a string or
None
if no source information is available. In the simple
case it is enough to simply return an absolute path to the file implementing
the keyword. If the line number where the keyword implementation starts
is known, it can be embedded to the return value like
path:lineno
.
Returning only the line number is possible like
:lineno
.
The source information of the library itself is got automatically from
the imported library class the same way as with other library APIs. The
library source path is used with all keywords that do not have their own
source path defined.
Note
Returning source information for keywords is a new feature in
Robot Framework 3.2.
Named argument syntax with dynamic libraries
Also the dynamic library API supports
the
named argument syntax
. Using the syntax works based on the
argument names and default values
got from the library
using the
get_keyword_arguments
method.
If the
run_keyword
method accepts three arguments, the second argument
gets all positional arguments as a list and the last arguments gets all
named arguments as a mapping. If it accepts only two arguments, named
arguments are mapped to positional arguments. In the latter case, if
a keyword has multiple arguments with default values and only some of
the latter ones are given, the framework fills the skipped optional
arguments based on the default values returned by the
get_keyword_arguments
method.
Using the named argument syntax with dynamic libraries is illustrated
by the following examples. All the examples use a keyword
Dynamic
that has an argument specification
[a, b=d1, c=d2]
. The comment on each row
shows how
run_keyword
would be called in these cases if it has two arguments
(i.e. signature is
name, args
) and if it has three arguments (i.e.
name, args, kwargs
).
*** Test Cases ***
# args # args, kwargs
Positional only
Dynamic
x
# [x] # [x], {}
Dynamic
x
y
# [x, y] # [x, y], {}
Dynamic
x
y
z
# [x, y, z] # [x, y, z], {}
Named only
Dynamic
a=x
# [x] # [], {a: x}
Dynamic
c=z
a=x
b=y
# [x, y, z] # [], {a: x, b: y, c: z}
Positional and named
Dynamic
x
b=y
# [x, y] # [x], {b: y}
Dynamic
x
y
c=z
# [x, y, z] # [x, y], {c: z}
Dynamic
x
b=y
c=z
# [x, y, z] # [x], {y: b, c: z}
Intermediate missing
Dynamic
x
c=z
# [x, d1, z] # [x], {c: z}
Note
Prior to Robot Framework 3.1, all normal named arguments were
mapped to positional arguments and the optional
kwargs
was
only used with free named arguments. With the above examples
run_keyword
was always called like it is nowadays called if
it does not support
kwargs
.
Free named arguments with dynamic libraries
Dynamic libraries can also support
free named arguments
(
**named
). A mandatory precondition for
this support is that the
run_keyword
method
takes three arguments
:
the third one will get the free named arguments along with possible other
named arguments. These arguments are passed to the keyword as a mapping.
What arguments a keyword accepts depends on what
get_keyword_arguments
returns for it
. If the last argument starts with
**
, that keyword is
recognized to accept free named arguments.
Using the free named argument syntax with dynamic libraries is illustrated
by the following examples. All the examples use a keyword
Dynamic
that has an argument specification
[a=d1, b=d2, **named]
. The comment shows
the arguments that the
run_keyword
method is actually called with.
*** Test Cases ***
# args, kwargs
No arguments
Dynamic
# [], {}
Only positional
Dynamic
x
# [x], {}
Dynamic
x
y
# [x, y], {}
Only free named
Dynamic
x=1
# [], {x: 1}
Dynamic
x=1
y=2
z=3
# [], {x: 1, y: 2, z: 3}
Positional and free named
Dynamic
x
y=2
# [x], {y: 2}
Dynamic
x
y=2
z=3
# [x], {y: 2, z: 3}
Positional as named and free named
Dynamic
a=1
x=1
# [], {a: 1, x: 1}
Dynamic
b=2
x=1
a=1
# [], {a: 1, b: 2, x: 1}
Note
Prior to Robot Framework 3.1, normal named arguments were mapped
to positional arguments but nowadays they are part of the
kwargs
along with the free named arguments.
Named-only arguments with dynamic libraries
Starting from Robot Framework 3.1, dynamic libraries can have
named-only
arguments
. This requires that the
run_keyword
method
takes three
arguments
: the third getting the named-only arguments along with the other
named arguments.
In the
argument specification
returned by the
get_keyword_arguments
method named-only arguments are specified after possible variable number
of arguments (
*varargs
) or a lone asterisk (
*
) if the keyword does not
accept varargs. Named-only arguments can have default values, and the order
of arguments with and without default values does not matter.
Using the named-only argument syntax with dynamic libraries is illustrated
by the following examples. All the examples use a keyword
Dynamic
that has been specified to have argument specification
[positional=default, *varargs, named, named2=default, **free]
. The comment
shows the arguments that the
run_keyword
method is actually called with.
*** Test Cases ***
# args, kwargs
Only named-only
Dynamic
named=value
# [], {named: value}
Dynamic
named=value
named2=2
# [], {named: value, named2: 2}
Named-only with positional and varargs
Dynamic
argument
named=xxx
# [argument], {named: xxx}
Dynamic
a1
a2
named=3
# [a1, a2], {named: 3}
Named-only with positional as named
Dynamic
named=foo
positional=bar
# [], {positional: bar, named: foo}
Named-only with free named
Dynamic
named=value
foo=bar
# [], {named: value, foo=bar}
Dynamic
named2=2
third=3
named=1
# [], {named: 1, named2: 2, third: 3}
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, kwargs
Execute the specified keyword
with given arguments.
kwargs
is optional.
get_keyword_arguments
name
Return keywords'
argument specification
. Optional method.
get_keyword_types
name
Return keywords'
argument type information
. Optional method. New in RF 3.1.
get_keyword_tags
name
Return keywords'
tags
. Optional method.
get_keyword_documentation
name
Return keywords' and library's
documentation
. Optional method.
get_keyword_source
name
Return keywords'
source
. Optional method. New in RF 3.2.
A good example of using the dynamic API is Robot Framework's own
Remote library
.
Note
Starting from Robot Framework 7.0, dynamic libraries can have asynchronous
implementations of their special methods.
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
(
f
"My Keyword called with '
{
args
}
'."
)
def
__getattr__
(
self
,
name
):
if
name
==
'external_keyword'
:
return
external_keyword
raise
AttributeError
(
f
"Non-existing attribute '
{
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
.
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, 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.
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 Handling Robot Framework's timeouts
Robot Framework has its own
timeouts
that can be used for stopping keyword
execution if a test or a keyword takes too much time.
There are two things to take into account related to them.
Doing cleanup if timeout occurs
Timeouts are technically implemented using
robot.errors.TimeoutExceeded
exception that can occur any time during a keyword execution. If a keyword
wants to make sure possible cleanup activities are always done, it needs to
handle these exceptions. Probably the simplest way to handle exceptions is
using Python's
try/finally
structure:
def
example
():
try
:
do_something
()
finally
:
do_cleanup
()
A benefit of the above is that cleanup is done regardless of the exception.
If there is a need to handle timeouts specially, it is possible to catch
TimeoutExceeded
explicitly. In that case it is important to re-raise the
original exception afterwards:
from
robot.errors
import
TimeoutExceeded
def
example
():
try
:
do_something
()
except
TimeoutExceeded
:
do_cleanup
()
raise
Note
The
TimeoutExceeded
exception was named
TimeoutError
prior to
Robot Framework 7.3. It was renamed to avoid a conflict with Python's
standard exception with the same name. The old name still exists as
a backwards compatible alias in the
robot.errors
module and can
be used if older Robot Framework versions need to be supported.
Allowing timeouts to stop execution
Robot Framework's timeouts can stop normal Python code, but if the code calls
functionality implemented using C or some other language, timeouts may
not work. Well behaving keywords should thus avoid long blocking calls that
cannot be interrupted.
As an example,
subprocess.run
cannot be interrupted on Windows, so
the following simple keyword cannot be stopped by timeouts there:
import
subprocess
def
run_command
(
command
,
*
args
):
result
=
subprocess
.
run
([
command
,
*
args
],
encoding
=
'UTF-8'
)
print
(
f
'stdout:
{
result
.
stdout
}
\n
stderr:
{
result
.
stderr
}
'
)
This problem can be avoided by using the lower level
subprocess.Popen
and handling waiting in a loop with short timeouts. This adds quite a lot
of complexity, though, so it may not be worth the effort in all cases.
import
subprocess
def
run_command
(
command
,
*
args
):
process
=
subprocess
.
Popen
([
command
,
*
args
],
encoding
=
'UTF-8'
,
stdout
=
subprocess
.
PIPE
,
stderr
=
subprocess
.
PIPE
)
while
True
:
try
:
stdout
,
stderr
=
process
.
communicate
(
timeout
=
0.1
)
except
subprocess
.
TimeoutExpired
:
continue
else
:
break
print
(
f
'stdout:
{
stdout
}
\n
stderr:
{
stderr
}
'
)
4.1.9 Using Robot Framework's internal modules
Test libraries 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.
Available APIs
API documentation
is hosted separately
at the excellent
Read the Docs
service. If you are unsure how to use
certain API or is using them forward compatible, please send a question
to
mailing list
.
Using BuiltIn library
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
):
builtin
=
BuiltIn
()
output
=
do_something_that_creates_a_lot_of_output
(
argument
)
if
builtin
.
robot_running
:
output_dir
=
builtin
.
replace_variables
(
'$
{OUTPUT_DIR}
'
)
else
:
output_dir
=
'.'
with
open
(
os
.
path
.
join
(
output_dir
,
'output.txt'
),
'w'
)
as
file
:
file
.
write
(
output
)
print
(
'*HTML* Output written to <a href="output.txt">output.txt</a>'
)
As the above examples illustrates, BuiltIn also has a convenient
robot_running
property for
detecting is Robot Framework running
.
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.
4.1.10 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
.
from
robot.api.deco
import
keyword
from
SeleniumLibrary
import
SeleniumLibrary
class
ExtendedSeleniumLibrary
(
SeleniumLibrary
):
@keyword
def
title_should_start_with
(
self
,
expected
):
title
=
self
.
get_title
()
if
not
title
.
startswith
(
expected
):
raise
AssertionError
(
f
"Title '
{
title
}
' did not start with '
{
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
BuiltIn
keyword
Get Library Instance
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
(
f
"Title '
{
title
}
' did not start with '
{
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
.
*** Settings ***
Library
SeleniumLibrary
Library
SeLibExtensions
*** Test Cases ***
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. 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
4.2.2 Putting Remote library to use
Importing Remote library
Starting and stopping remote servers
4.2.3 Supported argument and return value types
4.2.4 Remote protocol
Required methods
Using
get_keyword_names
and keyword specific getters
Using
get_library_information
Executing remote keywords
Different argument syntaxes
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. There exists ready-made
generic remote servers
for various languages like Python, Java, Ruby, .NET, and so on.
The remote library interface is provided by the Remote library that is
one of the
standard libraries
.
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:
Robot Framework architecture with Remote library
Note
The remote client uses Python's standard
XML-RPC module
. It does
not support custom XML-RPC extensions implemented by some XML-RPC
servers.
4.2.2 Putting Remote library to 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 suite, or just want to give it a more
descriptive name, you can give it an
alias when importing it
.
*** Settings ***
Library
Remote
http://127.0.0.1:8270
AS
Example1
Library
Remote
http://example.com:8080/
AS
Example2
Library
Remote
http://10.0.0.2/example
1 minute
AS
Example3
The URL used by the first example above is also the default address
that the Remote library uses if no address is given.
The last example above shows how to give a custom timeout to the Remote library
as an optional second argument. The timeout is used when initially connecting
to the server and if a connection accidentally closes. Timeout can be
given in Robot Framework
time format
like
60s
or
2 minutes 10 seconds
.
The default timeout is typically several minutes, but it depends on the
operating system and its configuration. Notice that setting a timeout that
is shorter than keyword execution time will interrupt the keyword.
Note
Port
8270
is the default port that remote servers are expected
to use and it has been
registered by IANA
for this purpose.
This port number was selected because 82 and 70 are the ASCII codes
of letters
R
and
F
, respectively.
Note
When connecting to the local machine, it is recommended to use
IP address
127.0.0.1
instead of machine name
localhost
. This
avoids address resolution that can be extremely slow
at least on
Windows
.
Note
If the URI contains no path after the server address, the
XML-RPC
module
used by the Remote library will use
/RPC2
path by
default. In practice using
http://127.0.0.1:8270
is thus identical
to using
http://127.0.0.1:8270/RPC2
. Depending on the remote server
this may or may not be a problem. No extra path is appended if the
address has a path even if the path is just
/
. For example, neither
http://127.0.0.1:8270/
nor
http://127.0.0.1:8270/my/path
will be
modified.
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
Process
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. Typically servers support the following methods:
Regardless of the library used, remote servers should provide
Stop
Remote Server
keyword that can be easily used by executed tests.
Remote servers should have
stop_remote_server
method in their
XML-RPC interface.
Hitting
Ctrl-C
on the console where the server is running should
stop the server.
The server process can be terminated using tools provided by the
operating system (e.g.
kill
).
Note
Servers 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.
Both the Remote library and the Python remote server handle Python values
according to the following rules. Other remote servers should behave similarly.
Strings, numbers and Boolean values are passed without modifications.
Python
None
is converted to an empty string.
All lists, tuples, and other iterable objects (except strings and
dictionaries) are passed as lists so that their contents are converted
recursively.
Dictionaries and other mappings are passed as dicts so that their keys are
converted to strings and values converted to supported types recursively.
Returned dictionaries are converted to so called
dot-accessible dicts
that allow accessing keys as attributes using the
extended variable syntax
like
${result.key}
. This works also with nested dictionaries like
${root.child.leaf}
.
Strings containing bytes in the ASCII range that cannot be represented in
XML (e.g. the null byte) are sent as
Binary objects
that internally use
XML-RPC base64 data type. Received Binary objects are automatically converted
to byte strings.
Other types are converted to strings.
4.2.4 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 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 an extension.
The
Python remote server
can be used as a reference implementation.
Required methods
There are two possibilities how remote servers can provide information about
the keywords they contain. They are briefly explained below and documented
more thoroughly in the subsequent sections.
Remote servers can implement the same methods as the
dynamic library API
has. This means
get_keyword_names
method and optional
get_keyword_arguments
,
get_keyword_types
,
get_keyword_tags
and
get_keyword_documentation
methods.
Notice that using "camel-case names" like
getKeywordNames
is not
possible similarly as in the normal dynamic API.
Starting from Robot Framework 4.0, remote servers can have a single
get_library_information
method that returns all library and keyword
information as a single dictionary. If a remote server has this method,
the other getter methods like
get_keyword_names
are not used at all.
This approach has the benefit that there is only one XML-RPC call to get
information while the approach explained above requires several calls per
keyword. With bigger libraries the difference can be significant.
Regardless how remote servers provide information about their keywords, they
must have
run_keyword
method that is used when keywords are executed.
How the actual keywords are implemented is not relevant for the Remote
library. Remote servers can either act as wrappers for the real test
libraries, like the available
generic remote servers
do, or they can
implement keywords themselves.
Remote servers should additionally have
stop_remote_server
method in their public interface to ease stopping them. They should
also automatically expose this method as
Stop Remote Server
keyword to allow using it in the test data regardless of the test
library. Allowing users to stop the server is not always desirable,
and servers may support disabling this functionality somehow.
The method, and also the exposed keyword, should return
True
or
False
depending on whether stopping is allowed or not. That makes it
possible for external tools to know if stopping the server succeeded.
Using
get_keyword_names
and keyword specific getters
This section explains how the Remote library gets keyword names and other
information when the server implements
get_keyword_names
. The next sections
covers using the newer
get_library_info
method.
The
get_keyword_names
method must return names of the keyword the server
contains as a list of strings. Remote servers can, and should, also implement
get_keyword_arguments
,
get_keyword_types
,
get_keyword_tags
and
get_keyword_documentation
methods to provide more information about
the keywords. All these methods take the name of the keyword as an argument
and what they must return is explained in the table below.
Keyword specific getter methods
Method
Return value
get_keyword_arguments
Arguments as a list of strings in the
same format as with dynamic libraries
.
get_keyword_types
Type information as a list or dictionary of strings. See below for details.
get_keyword_documentation
Documentation as a string.
get_keyword_tags
Tags as a list of strings.
Type information used for
argument conversion
can be returned either as
a list mapping type names to arguments based on position or as a dictionary
mapping argument names to type names directly. In practice this works the same
way as when
specifying types using the @keyword decorator
with normal
libraries. The difference is that because the XML-RPC protocol does not support
arbitrary values, type information needs to be specified using type names
or aliases like
'int'
or
'integer'
, not using actual types like
int
.
Additionally
None
or
null
values may not be allowed by the XML-RPC server,
but an empty string can be used to indicate that certain argument does not
have type information instead.
Argument conversion is supported also based on default values using the
same logic as with normal libraries
. For this to work, arguments with
default values must be returned as tuples, not as strings, the
same way
as with dynamic libraries
. For example, argument conversion works if
argument information is returned like
[('count', 1), ('caseless', True)]
but not if it is
['count=1', 'caseless=True']
.
Remote servers can also provide
general library documentation
to
be used when generating documentation with the
Libdoc
tool. This information
is got by calling
get_keyword_documentation
with special values
__intro__
and
__init__
.
Note
get_keyword_types
is new in Robot Framework 3.1 and support for
argument conversion based on defaults is new in Robot Framework 4.0.
Using
get_library_information
The
get_library_information
method allows returning information about the whole
library in one XML-RPC call. The information must be returned as a dictionary where
keys are keyword names and values are nested dictionaries containing keyword information.
The dictionary can also contain separate entries for generic library information.
The keyword information dictionary can contain keyword arguments, documentation,
tags and types, and the respective keys are
args
,
doc
,
tags
and
types
.
Information must be provided using same semantics as when
get_keyword_arguments
,
get_keyword_documentation
,
get_keyword_tags
and
get_keyword_types
discussed
in the previous section. If some information is not available, it can be omitted
from the info dictionary altogether.
get_library_information
supports also returning general library documentation
to be used with
Libdoc
. It is done by including special
__intro__
and
__init__
entries into the returned library information dictionary.
For example, a Python library like
"""Library documentation."""
from
robot.api.deco
import
keyword
@keyword
(
tags
=
[
'x'
,
'y'
])
def
example
(
a
:
int
,
b
=
True
):
"""Keyword documentation."""
pass
def
another
():
pass
could be mapped into this kind of library information dictionary:
{
'__intro__': {'doc': 'Library documentation'}
'example': {'args': ['a', 'b=True'],
'types': ['int'],
'doc': 'Keyword documentation.',
'tags': ['x', 'y']}
'another: {'args': []}
}
Note
get_library_information
is new in Robot Framework 4.0.
Executing remote keywords
When the Remote library wants the server to execute some keyword, it
calls the remote server's
run_keyword
method and passes it the
keyword name, a list of arguments, and possibly a dictionary of
free named 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. Notice that only the
status
entry is mandatory,
others can be omitted if they are not applicable.
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*HTML* <b>2nd</b>\n*WARN* Another message
. It
is also possible to embed
timestamps
to the log messages
like
*INFO:1308435758660* Message with timestamp
.
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.
continuable
When set to
True
, or any value considered
True
in
Python, the occurred failure is considered
continuable
.
fatal
Like
continuable
, but denotes that the occurred
failure is
fatal
.
Different argument syntaxes
The Remote library is a
dynamic library
, and in general it handles
different argument syntaxes
according to the same rules
as any other
dynamic library.
This includes mandatory arguments, default values, varargs, as well
as
named argument syntax
.
Also free named arguments (
**kwargs
) works mostly the
same way
as with other dynamic libraries
. First of all, the
get_keyword_arguments
must return an argument specification that
contains
**kwargs
exactly like with any other dynamic library.
The main difference is that
remote servers'
run_keyword
method must have an
optional
third argument
that gets the kwargs specified by the user. The third argument must be optional
because, for backwards-compatibility reasons, the Remote library passes kwargs
to the
run_keyword
method only when they have been used in the test data.
In practice
run_keyword
should look something like the following
Python and Java examples, depending on how the language handles optional
arguments.
def
run_keyword
(
name
,
args
,
kwargs
=
None
):
# ...
public
Map
run_keyword
(
String
name
,
List
args
)
{
// ...
}
public
Map
run_keyword
(
String
name
,
List
args
,
Map
kwargs
)
{
// ...
}
4.3 Listener interface
Robot Framework's listener interface provides a powerful mechanism for getting
notifications and for inspecting and modifying data and results during execution.
Listeners are called, for example, when suites, tests and keywords start and end,
when output files are ready, and finally when the whole execution ends.
Example usages include communicating with external test management systems,
sending a message when a test fails, and modifying tests during execution.
Listeners are implemented as classes or modules with certain special methods.
They can be
taken into use from the command line
and be
registered
by libraries
. The former listeners are active during the whole execution
while the latter are active only when executing suites where libraries registering
them are imported.
There are two supported listener interface versions,
listener version 2
and
listener version 3
. They have mostly the same methods, but these methods are
called with different arguments. The newer listener version 3 is more powerful
and generally recommended.
4.3.1 Listener structure
4.3.2 Listener interface versions
Listener version 2
Listener version 3
4.3.3 Taking listeners into use
Registering listeners from command line
Libraries as listeners
4.3.4 Listener calling order
4.3.5 Listener examples
Getting information
Modifying data and results
More examples
4.3.1 Listener structure
Listeners are implement as modules or classes
similarly as libraries
.
They can implement certain named hook methods depending on what events they
are interested in. For example, if a listener wants to get a notification when
a test starts, it can implement the
start_test
method. As discussed in the
subsequent sections, different listener versions have slightly different set of
available methods and they also are called with different arguments.
# Listener implemented as a module using the listener API version 3.
def
start_suite
(
data
,
result
):
print
(
f
"Suite '
{
data
.
name
}
' starting."
)
def
end_test
(
data
,
result
):
print
(
f
"Test '
{
result
.
name
}
' ended with status
{
result
.
status
}
."
)
Listeners do not need to implement any explicit interface, it is enough to
simply implement needed methods and they will be recognized automatically.
There are, however, base classes
robot.api.interfaces.ListenerV2
and
robot.api.interfaces.ListenerV3
that can be used to get
method name completion in editors, type hints, and so on.
# Same as the above example, but uses an optional base class and type hints.
from
robot
import
result
,
running
from
robot.api.interfaces
import
ListenerV3
class
Example
(
ListenerV3
):
def
start_suite
(
self
,
data
:
running
.
TestSuite
,
result
:
result
.
TestSuite
):
print
(
f
"Suite '
{
data
.
name
}
' starting."
)
def
end_test
(
self
,
data
:
running
.
TestCase
,
result
:
result
.
TestCase
):
print
(
f
"Test '
{
result
.
name
}
' ended with status
{
result
.
status
}
."
)
Note
Optional listener base classes are new in Robot Framework 6.1.
In addition to using "snake case" like
start_test
with listener method names,
it is possible to use "camel case" like
startTest
. This support was added
when it was possible to run Robot Framework on Jython and implement listeners
using Java. It is preserved for backwards compatibility reasons, but not
recommended with new listeners.
4.3.2 Listener interface versions
There are two supported listener interface versions with version numbers 2 and 3.
A listener can specify which version to use by having a
ROBOT_LISTENER_API_VERSION
attribute with value 2 or 3, respectively. Starting from Robot Framework 7.0,
the listener version 3 is used by default if the version is not specified.
Listener version 2
and
listener version 3
have mostly the same methods,
but arguments passed to these methods are different. Arguments given to listener 2
methods are strings and dictionaries containing information about execution. This
information can be inspected and sent further, but it is not possible to
modify it directly. Listener 3 methods get the same model objects that Robot Framework
itself uses, and these model objects can be both inspected and modified.
Listener version 3 is more powerful than the older listener version 2
and generally recommended.
Listener version 2
Listeners using the listener API version 2 get notifications about various events
during execution, but they do not have access to actually executed tests and thus
cannot directly affect the execution or created results.
Listener methods in the API version 2 are listed in the following table
and in the API docs of the optional
ListenerV2
base class.
All methods related to test execution progress have the same signature
method(name, attributes)
, where
attributes
is a dictionary containing
details of the event. Listener methods are free to do whatever they want
to do with the information they receive, but they cannot directly change
it. If that is needed,
listener version 3
can be used instead.
Methods in the listener API 2
Method
Arguments
Documentation
start_suite
name, attributes
Called when a test suite starts.
Contents of the attribute dictionary:
id
: Suite id.
s1
for the top level suite,
s1-s1
for its first child suite,
s1-s2
for the second
child, and so on.
longname
: Suite name including parent suites.
doc
: Suite documentation.
metadata
:
Free suite metadata
as a dictionary.
source
: An absolute path of the file/directory the suite
was created from.
suites
: Names of the direct child suites this suite has
as a list.
tests
: Names of the tests this suite has as a list.
Does not include tests of the possible child suites.
totaltests
: The total number of tests in this suite.
and all its sub-suites as an integer.
starttime
: Suite execution start time.
end_suite
name, attributes
Called when a test suite ends.
Contents of the attribute dictionary:
id
: Same as in
start_suite
.
longname
: Same as in
start_suite
.
doc
: Same as in
start_suite
.
metadata
: Same as in
start_suite
.
source
: Same as in
start_suite
.
starttime
: Same as in
start_suite
.
endtime
: Suite execution end time.
elapsedtime
: Total execution time in milliseconds as
an integer
status
: Suite status as string
PASS
,
FAIL
or
SKIP
.
statistics
: Suite statistics (number of passed
and failed tests in the suite) as a string.
message
: Error message if suite setup or teardown
has failed, empty otherwise.
start_test
name, attributes
Called when a test case starts.
Contents of the attribute dictionary:
id
: Test id in format like
s1-s2-t2
, where
the beginning is the parent suite id and the last part
shows test index in that suite.
longname
: Test name including parent suites.
originalname
: Test name with possible variables
unresolved. New in RF 3.2.
doc
: Test documentation.
tags
: Test tags as a list of strings.
template
: The name of the template used for the test.
An empty string if the test not templated.
source
: An absolute path of the test case source file.
New in RF 4.0.
lineno
: Line number where the test starts in the source
file. New in RF 3.2.
starttime
: Test execution execution start time.
end_test
name, attributes
Called when a test case ends.
Contents of the attribute dictionary:
id
: Same as in
start_test
.
longname
: Same as in
start_test
.
originalname
: Same as in
start_test
.
doc
: Same as in
start_test
.
tags
: Same as in
start_test
.
template
: Same as in
start_test
.
source
: Same as in
start_test
.
lineno
: Same as in
start_test
.
starttime
: Same as in
start_test
.
endtime
: Test execution execution end time.
elapsedtime
: Total execution time in milliseconds as
an integer
status
: Test status as string
PASS
,
FAIL
or
SKIP
.
message
: Status message. Normally an error
message or an empty string.
start_keyword
name, attributes
Called when a keyword or a control structure such as
IF/ELSE
or
TRY/EXCEPT
starts.
With keywords
name
is the full keyword name containing
possible library or resource name as a prefix like
MyLibrary.Example Keyword
. With control structures
name
contains string representation of parameters.
Keywords and control structures share most of attributes, but
control structures can have additional attributes depending
on their
type
.
Shared attributes:
type
: String specifying type of the started item. Possible
values are:
KEYWORD
,
SETUP
,
TEARDOWN
,
FOR
,
WHILE
,
ITERATION
,
IF
,
ELSE IF
,
ELSE
,
TRY
,
EXCEPT
,
FINALLY
,
VAR
,
RETURN
,
BREAK
,
CONTINUE
and
ERROR
.
All type values were changed in RF 4.0 and in RF 5.0
FOR ITERATION
was changed to
ITERATION
.
kwname
: Name of the keyword without library or
resource prefix. String representation of parameters with
control structures.
libname
: Name of the library or resource file the keyword
belongs to. An empty string with user keywords in a test
case file and with control structures.
doc
: Keyword documentation.
args
: Keyword's arguments as a list of strings.
assign
: A list of variable names that keyword's
return value is assigned to.
tags
:
Keyword tags
as a list of strings.
source
: An absolute path of the file where the keyword was
used. New in RF 4.0.
lineno
: Line where the keyword was used. Typically an
integer, but can be
None
if a keyword has been executed by
a listener. New in RF 4.0.
status
: Initial keyword status.
NOT RUN
if keyword is
not executed (e.g. due to an earlier failure),
NOT SET
otherwise. New in RF 4.0.
starttime
: Keyword execution start time.
Additional attributes for
FOR
types:
variables
: Assigned variables for each loop iteration
as a list or strings.
flavor
: Type of loop (e.g.
IN RANGE
).
values
: List of values being looped over
as a list or strings.
start
: Start configuration. Only used with
IN ENUMERATE
loops. New in RF 6.1.
mode
: Mode configuration. Only used with
IN ZIP
loops.
New in RF 6.1.
fill
: Fill value configuration. Only used with
IN ZIP
loops. New in RF 6.1.
Additional attributes for
ITERATION
types with
FOR
loops:
variables
: Variables and string representations of their
contents for one
FOR
loop iteration as a dictionary.
Additional attributes for
WHILE
types:
condition
: The looping condition.
limit
: The maximum iteration limit.
on_limit
: What to do if the limit is exceeded.
Valid values are
pass
and
fail
. New in RF 7.0.
on_limit_message
: The custom error raised when the
limit of the WHILE loop is reached. New in RF 6.1.
Additional attributes for
IF
and
ELSE IF
types:
condition
: The conditional expression being evaluated.
With
ELSE IF
new in RF 6.1.
Additional attributes for
EXCEPT
types:
patterns
: The exception patterns being matched
as a list or strings.
pattern_type
: The type of pattern match (e.g.
GLOB
).
variable
: The variable containing the captured exception.
Additional attributes for
RETURN
types:
values
: Return values from a keyword as a list or strings.
Additional attributes for
VAR
types:
name
: Variable name.
value
: Variable value. A string with scalar variables and
a list otherwise.
scope
: Variable scope (e.g.
GLOBAL
) as a string.
Additional attributes for control structures are in general
new in RF 6.0.
VAR
is new in RF 7.0.
end_keyword
name, attributes
Called when a keyword or a control structure ends.
name
is the full keyword name containing
possible library or resource name as a prefix.
For example,
MyLibrary.Example Keyword
.
Control structures have additional attributes, which change
based on the
type
attribute. For descriptions of all
possible attributes, see the
start_keyword
section.
Contents of the attribute dictionary:
type
: Same as with
start_keyword
.
kwname
: Same as with
start_keyword
.
libname
: Same as with
start_keyword
.
doc
: Same as with
start_keyword
.
args
: Same as with
start_keyword
.
assign
: Same as with
start_keyword
.
tags
: Same as with
start_keyword
.
source
: Same as with
start_keyword
.
lineno
: Same as with
start_keyword
.
starttime
: Same as with
start_keyword
.
endtime
: Keyword execution end time.
elapsedtime
: Total execution time in milliseconds as
an integer
status
: Keyword status as string
PASS
,
FAIL
,
SKIP
or
NOT RUN
.
SKIP
and
NOT RUN
are new in RF 4.0.
log_message
message
Called when an executed keyword writes a log message.
message
is a dictionary with the following contents:
message
: The content of the message.
level
:
Log level
used in logging the message.
timestamp
: Message creation time in format
YYYY-MM-DD hh:mm:ss.mil
.
html
: String
yes
or
no
denoting whether the message
should be interpreted as HTML or not.
Not called if the message level is below the current
threshold level
.
message
message
Called when the framework itself writes a
syslog
message.
message
is a dictionary with the same contents as with
log_message
method.
library_import
name, attributes
Called when a library has been imported.
name
is the name of the imported library. If the library
has been given a custom name when imported it using
AS
,
name
is the specified alias.
Contents of the attribute dictionary:
args
: Arguments passed to the library as a list.
originalname
: The original library name if the library has
been given an alias using
AS
, otherwise same as
name
.
source
: An absolute path to the library source. An empty
string if getting the
source of the library failed for some reason.
importer
: An absolute path to the file importing the
library.
None
when
BuiltIn
is imported as well as when
using the
Import Library
keyword.
resource_import
name, attributes
Called when a resource file has been imported.
name
is the name of the imported resource file without
the file extension.
Contents of the attribute dictionary:
source
: An absolute path to the imported resource file.
importer
: An absolute path to the file importing the
resource file.
None
when using the
Import Resource
keyword.
variables_import
name, attributes
Called when a variable file has been imported.
name
is the name of the imported variable file with
the file extension.
Contents of the attribute dictionary:
args
: Arguments passed to the variable file as a list.
source
: An absolute path to the imported variable file.
importer
: An absolute path to the file importing the
resource file.
None
when using the
Import
Variables
keyword.
output_file
path
Called when writing to an
output file
is ready.
path
is an absolute path to the file as a string or
a string
None
if creating the output file is disabled.
log_file
path
Called when writing to a
log file
is ready.
path
is an absolute path to the file as a string.
Not called if creating the log file is disabled.
report_file
path
Called when writing to a
report file
is ready.
path
is an absolute path to the file as a string.
Not called if creating the report file is disabled.
xunit_file
path
Called when writing to an
xunit file
is ready.
path
is an absolute path to the file as a string.
Only called if creating the xunit file is enabled.
debug_file
path
Called when writing to a
debug file
is ready.
path
is an absolute path to the file as a string.
Only called if creating the debug file is enabled.
close
Called when the whole test execution ends.
With
library listeners
called when the library goes out
of scope.
Listener version 3
Listener version 3 has mostly the same methods as
listener version 2
,
but arguments of the methods related to test execution are different.
These methods get actual running and result model objects that used by Robot
Framework itself, and listeners can both query information they need and
change the model objects on the fly.
Note
Modifications to the data can also be done using
pre-run modifiers
.
The main benefit of using listeners is that changes can be done
dynamically based on what happens during the execution. Another
difference is that command like options related to
selecting test cases
affect tests added by pre-run modifiers but not tests added by listeners.
Listener version 3 was enhanced heavily in Robot Framework 7.0 when it got
methods related to keywords and control structures. It was enhanced further
in Robot Framework 7.1 when it got methods related to library, resource file
and variable file imports.
Listener version 3 has separate methods for library keywords, user keywords and
all control structures. If there is a need to listen to all keyword related
events, it is possible to implement
start_keyword
and
end_keyword
. In addition
to that,
start_body_item
and
end_body_item
can be implemented to get
notifications related to all keywords and control structures. These higher level
listener methods are not called if more specific methods like
start_library_keyword
or
end_if
are implemented.
Listener methods in the API version 3 are listed in the following table
and in the API docs of the optional
ListenerV3
base class.
Methods in the listener API 3
Method
Arguments
Documentation
start_suite
data, result
Called when a test suite starts.
data
and
result
are model objects representing
the
executed test suite
and
its
execution results
, respectively.
end_suite
data, result
Called when a test suite ends.
Same arguments as with
start_suite
.
start_test
data, result
Called when a test case starts.
data
and
result
are model objects representing
the
executed test case
and
its
execution results
, respectively.
end_test
data, result
Called when a test case ends.
Same arguments as with
start_test
.
start_keyword
data, result
Called when a keyword starts.
data
and
result
are model objects representing
the
executed keyword call
and
its
execution results
, respectively.
This method is called, by default, with user keywords, library
keywords and when a keyword call is invalid. It is not called
if a more specific
start_user_keyword
,
start_library_keyword
or
start_invalid_keyword
method is implemented.
end_keyword
data, result
Called when a keyword ends.
Same arguments and other semantics as with
start_keyword
.
start_user_keyword
data,
implementation,
result
Called when a user keyword starts.
data
and
result
are the same as with
start_keyword
and
implementation
is the actually executed
user keyword
.
If this method is implemented,
start_keyword
is not called
with user keywords.
end_user_keyword
data,
implementation,
result
Called when a user keyword ends.
Same arguments and other semantics as with
start_user_keyword
.
start_library_keyword
data
implementation,
result
Called when a library keyword starts.
data
and
result
are the same as with
start_keyword
and
implementation
represents the executed
library keyword
.
If this method is implemented,
start_keyword
is not called
with library keywords.
end_library_keyword
data,
implementation,
result
Called when a library keyword ends.
Same arguments and other semantics as with
start_library_keyword
.
start_invalid_keyword
data
implementation,
result
Called when an invalid keyword call starts.
data
and
result
are the same as with
start_keyword
and
implementation
represents the
invalid keyword call
. Keyword may not have been found,
there could have been multiple matches, or the keyword call
itself could have been invalid.
If this method is implemented,
start_keyword
is not called
with invalid keyword calls.
end_invalid_keyword
data,
implementation,
result
Called when an invalid keyword call ends.
Same arguments and other semantics as with
start_invalid_keyword
.
start_for,
start_for_iteration,
start_while,
start_while_iteration,
start_if,
start_if_branch,
start_try,
start_try_branch,
start_group,
start_var,
start_continue,
start_break,
start_return
data, result
Called when control structures start.
See the documentation and type hints of the optional
ListenerV3
base class for more information.
end_for,
end_for_iteration,
end_while,
end_while_iteration,
end_if,
end_if_branch,
end_try,
end_try_branch,
end_group,
end_var,
end_continue,
end_break,
end_return
data, result
Called when control structures end.
See the documentation and type hints of the optional
ListenerV3
base class for more information.
start_error
data, result
Called when invalid syntax starts.
end_error
data, result
Called when invalid syntax ends.
start_body_item
data, result
Called when a keyword or a control structure starts, unless
a more specific method such as
start_keyword
or
start_if
is implemented.
end_body_item
data, result
Called when a keyword or a control structure ends, unless
a more specific method such as
end_keyword
or
end_if
is implemented.
log_message
message
Called when an executed keyword writes a log message.
message
is a model object representing the
logged
message
.
This method is not called if the message has level below
the current
threshold level
.
message
message
Called when the framework itself writes a
syslog
message.
message
is same object as with
log_message
.
library_import
library,
importer
Called after a library has been imported.
library
represents the imported library.
It can be inspected and also modified.
importer
contains information about the location where
the library was imported.
resource_import
resource,
importer
Called after a resource file has been imported.
resource
represents the imported
resource file. It can be inspected and also modified.
importer
contains information about the location where
the resource was imported.
variables_import
attrs,
importer
Called after a variable file has been imported.
attrs
contains information about the imported variable file as
a dictionary. It can be inspected, but modifications to it have no
effect.
importer
contains information about
the location where the variable file was imported.
This method will be changed in the future so that the
attrs
dictionary is replaced with an object representing the imported
variable file.
output_file
path
Called when writing to an
output file
is ready.
path
is an absolute path to the file as a
pathlib.Path
object
or the
None
object if creating the output file is disabled.
log_file
path
Called when writing to a
log file
is ready.
path
is an absolute path to the file as a
pathlib.Path
object.
Not called if creating the log file is disabled.
report_file
path
Called when writing to a
report file
is ready.
path
is an absolute path to the file as a
pathlib.Path
object.
Not called if creating the report file is disabled.
xunit_file
path
Called when writing to an
xunit file
is ready.
path
is an absolute path to the file as a
pathlib.Path
object.
Only called if creating the xunit file is enabled.
debug_file
path
Called when writing to a
debug file
is ready.
path
is an absolute path to the file as a
pathlib.Path
object.
Only called if creating the debug file is enabled.
close
Called when the whole test execution ends.
With
library listeners
called when the library goes out
of scope.
Note
Methods related to keywords and control structures are new in
Robot Framework 7.0.
Note
Methods related to library, resource file and variable file imports
are new in Robot Framework 7.1.
Note
Prior to Robot Framework 7.0, paths passed to result file related listener
version 3 methods were strings.
4.3.3 Taking listeners into use
Registering listeners from command line
Listeners that need to be active during the whole execution must be taken into
use from the command line. That is done using 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, similarly as
library name
is got from the class or module
implementing the library. The specified listeners must be in the same
module
search path
where test libraries are searched from when they are imported.
In addition to registering a listener by using a name, it is possible 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:
robot --listener MyListener tests.robot
robot --listener path/to/MyListener.py tests.robot
robot --listener module.Listener --listener AnotherListener tests.robot
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. If a listener is given as an absolute Windows path,
the colon after the drive letter is not considered a separator.
Additionally, it is possible to use a semicolon (
;
) as an
alternative argument separator. This is useful if listener arguments
themselves contain colons, but requires surrounding the whole value with
quotes on UNIX-like operating systems:
robot --listener listener.py:arg1:arg2 tests.robot
robot --listener "listener.py;arg:with:colons" tests.robot
robot --listener c:\path\listener.py;d:\first\arg;e:\second\arg tests.robot
In addition to passing arguments one-by-one as positional arguments, it is
possible to pass them using the
named argument syntax
similarly as when using
keywords:
robot --listener listener.py:name=value tests.robot
robot --listener "listener.py;name=value:with:colons;second=argument" tests.robot
Listener arguments are automatically converted using
same rules as with
keywords
based on
type hints
and
default values
. For example,
this listener
class
Listener
:
def
__init__
(
self
,
port
:
int
,
log
=
True
):
self
.
port
=
post
self
.
log
=
log
could be used like
robot --listener Listener:8270:false
and the first argument would be converted to an integer based on the type hint
and the second to a Boolean based on the default value.
Note
Both the named argument syntax and argument conversion are new in
Robot Framework 4.0.
Libraries as listeners
Sometimes it is useful also for
test libraries
to get notifications about
test execution. This allows them, for example, to perform certain clean-up
activities automatically when a test suite or the whole test execution ends.
Registering listener
A test library can register a listener by using the
ROBOT_LIBRARY_LISTENER
attribute. The value of this attribute should be an instance of the listener
to use. It may be a totally independent listener or the library itself can
act as a listener. To avoid listener methods to be exposed as keywords in
the latter case, it is possible to prefix them with an underscore.
For example, instead of using
end_suite
it is possible to use
_end_suite
.
Following examples illustrates using an external listener as well as a library
acting as a listener itself:
from
listener
import
Listener
class
LibraryWithExternalListener
:
ROBOT_LIBRARY_SCOPE
=
'GLOBAL'
ROBOT_LIBRARY_LISTENER
=
Listener
()
def
example_keyword
(
self
):
...
class
LibraryItselfAsListener
:
ROBOT_LIBRARY_SCOPE
=
'SUITE'
ROBOT_LISTENER_API_VERSION
=
2
def
__init__
(
self
):
self
.
ROBOT_LIBRARY_LISTENER
=
self
# Use the '_' prefix to avoid listener method becoming a keyword.
def
_end_suite
(
self
,
name
,
attrs
):
print
(
f
"Suite '
{
name
}
' ending with status
{
attrs
[
'id'
]
}
."
)
def
example_keyword
(
self
):
...
As the second example above already demonstrated, library listeners can
specify
listener interface versions
using the
ROBOT_LISTENER_API_VERSION
attribute exactly like any other listener.
Starting from Robot Framework 7.0, a listener can register itself to be a listener
also by using a string
SELF
(case-insensitive) as a listener. This is especially
convenient when using the
@library decorator
:
from
robot.api.deco
import
keyword
,
library
@library
(
scope
=
'SUITE'
,
listener
=
'SELF'
)
class
LibraryItselfAsListener
:
# Listener version is not specified, so uses the listener version 3 by default.
# When using the @library decorator, keywords must use the @keyword decorator,
# so there is no need to use the '_' prefix here.
def
end_suite
(
self
,
data
,
result
):
print
(
f
"Suite '
{
data
.
name
}
' ending with status
{
result
.
status
}
."
)
@keyword
def
example_keyword
(
self
):
...
It is also possible to specify multiple listeners for a single library by
giving
ROBOT_LIBRARY_LISTENER
a value as a list:
from
listeners
import
Listener1
,
Listener2
,
Listener3
class
LibraryWithMultipleListeners
:
ROBOT_LIBRARY_LISTENER
=
[
Listener1
(),
Listener2
(),
Listener3
()]
def
example_keyword
(
self
):
...
Called listener methods
Library listeners get notifications about all events in suites where
libraries using them are imported. In practice this means that suite,
test, keyword, control structure and log message related methods are
called. In addition to them, the
close
method is called when the library
goes out of the scope.
If library creates a new listener instance every time when the library
itself is instantiated, the actual listener instance to use will change
according to the
library scope
.
4.3.4 Listener calling order
By default, listeners are called in the order they are taken into use so that
listeners registered from the command line are called before library listeners.
It is, however, possible to control the calling order by setting the special
ROBOT_LISTENER_PRIORITY
attribute to an integer or a floating point value.
The bigger the number, the higher precedence the listener has and the earlier
it is called. The number can be positive or negative and it is zero by default.
The custom order does not affect the
close
method of library listeners, though.
That method is always called when the library goes out of its scope.
Note
Controlling listener calling order is new in Robot Framework 7.1.
4.3.5 Listener examples
This section contains examples using the listener interface. First examples
illustrate getting notifications during execution and latter examples modify
executed tests and created results.
Getting information
The first example is implemented as a Python module. It uses the
listener
version 2
, but could equally well be implemented by using the
listener
version 3
.
"""Listener that stops execution if a test fails."""
ROBOT_LISTENER_API_VERSION
=
2
def
end_test
(
name
,
attrs
):
if
attrs
[
'status'
]
==
'FAIL'
:
print
(
f
"Test '
{
name
}
'"
failed
:
{
attrs
[
'message'
]}
")
input
(
"Press enter to continue."
)
If the above example would be saved to, for example,
PauseExecution.py
file, it could be used from the command line like this:
robot --listener path/to/PauseExecution.py tests.robot
The next example, which still uses the listener version 2, 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 it 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
Example
:
ROBOT_LISTENER_API_VERSION
=
2
def
__init__
(
self
,
file_name
=
'listen.txt'
):
path
=
os
.
path
.
join
(
tempfile
.
gettempdir
(),
file_name
)
self
.
file
=
open
(
path
,
'w'
)
def
start_suite
(
self
,
name
,
attrs
):
self
.
file
.
write
(
"
%s
'
%s
'
\n
"
%
(
name
,
attrs
[
'doc'
]))
def
start_test
(
self
,
name
,
attrs
):
tags
=
' '
.
join
(
attrs
[
'tags'
])
self
.
file
.
write
(
"-
%s
'
%s
' [
%s
] :: "
%
(
name
,
attrs
[
'doc'
],
tags
))
def
end_test
(
self
,
name
,
attrs
):
if
attrs
[
'status'
]
==
'PASS'
:
self
.
file
.
write
(
'PASS
\n
'
)
else
:
self
.
file
.
write
(
'FAIL:
%s
\n
'
%
attrs
[
'message'
])
def
end_suite
(
self
,
name
,
attrs
):
self
.
file
.
write
(
'
%s
\n
%s
\n
'
%
(
attrs
[
'status'
],
attrs
[
'message'
]))
def
close
(
self
):
self
.
file
.
close
()
Modifying data and results
The following examples illustrate how to modify the executed tests and suites
as well as the execution results. All these examples require using
the
listener version 3
.
Modifying executed suites and tests
Changing what is executed is as easy as modifying the model objects representing
executed data passed to listener methods. This is illustrated by the example below that
adds a new test to each executed suite and a new keyword call to each test.
def
start_suite
(
data
,
result
):
data
.
tests
.
create
(
name
=
'New test'
)
def
start_test
(
data
,
result
):
data
.
body
.
create_keyword
(
name
=
'Log'
,
args
=
[
'Keyword added by listener!'
])
This API is very similar to the
pre-run modifier
API that can be used
to modify suites and tests before the whole test execution starts. The main
benefit of using the listener API is that modifications can be done
dynamically based on execution results or otherwise. This allows, for example,
interesting possibilities for model based testing.
Although the listener interface is not built on top of Robot Framework's
internal
visitor interface
similarly as the pre-run modifier API,
listeners can still use the visitors interface themselves. For example,
the
SelectEveryXthTest
visitor used in
pre-run modifier
examples could
be used like this:
from
SelectEveryXthTest
import
SelectEveryXthTest
def
start_suite
(
suite
,
result
):
selector
=
SelectEveryXthTest
(
x
=
2
)
suite
.
visit
(
selector
)
Accessing library or resource file
It is possible to get more information about the actually executed keyword and
the library or resource file it belongs to:
from
robot.running
import
Keyword
as
KeywordData
,
LibraryKeyword
from
robot.result
import
Keyword
as
KeywordResult
def
start_library_keyword
(
data
:
KeywordData
,
implementation
:
LibraryKeyword
,
result
:
KeywordResult
):
library
=
implementation
.
owner
print
(
f
"Keyword '
{
implementation
.
name
}
' is implemented in library "
f
"'
{
library
.
name
}
' at '
{
implementation
.
source
}
' on line "
f
"
{
implementation
.
lineno
}
. The library has
{
library
.
scope
.
name
}
"
f
"scope and the current instance is
{
library
.
instance
}
."
)
As the above example illustrates, it is possible to get an access to the actual
library instance. This means that listeners can inspect the library state and also
modify it. With user keywords it is even possible to modify the keyword itself or,
via the
owner
resource file, any other keyword in the resource file.
Modifying results
Test execution results can be altered by modifying the result objects passed to
listener methods. This is demonstrated by the following listener that is implemented
as a class and also uses type hints:
from
robot
import
result
,
running
class
ResultModifier
:
def
__init__
(
self
,
max_seconds
:
float
=
10.0
):
self
.
max_seconds
=
max_seconds
def
start_suite
(
self
,
data
:
running
.
TestSuite
,
result
:
result
.
TestSuite
):
result
.
doc
=
'Documentation set by listener.'
# Information about tests only available via data at this point.
smoke_tests
=
[
test
for
test
in
data
.
tests
if
'smoke'
in
test
.
tags
]
result
.
metadata
[
'Smoke tests'
]
=
len
(
smoke_tests
)
def
end_test
(
self
,
data
:
running
.
TestCase
,
result
:
result
.
TestCase
):
elapsed_seconds
=
result
.
elapsed_time
.
total_seconds
()
if
result
.
status
==
'PASS'
and
elapsed_seconds
>
self
.
max_seconds
:
result
.
status
=
'FAIL'
result
.
message
=
'Test execution took too long.'
def
log_message
(
self
,
msg
:
result
.
Message
):
if
msg
.
level
==
'WARN'
and
not
msg
.
html
:
msg
.
message
=
f
'<b style="font-size: 1.5em">
{
msg
.
message
}
</b>'
msg
.
html
=
True
if
self
.
_message_is_not_relevant
(
msg
.
message
):
msg
.
message
=
None
def
_message_is_not_relevant
(
self
,
message
:
str
)
->
bool
:
...
A limitation is that modifying the name of the current test suite or test
case is not possible because it has already been written to the
output.xml
file when listeners are called. Due to the same reason modifying already
finished tests in the
end_suite
method has no effect either.
When modifying logged messages, it is possible to remove a message altogether
by setting
message
to
None
as the above example demonstrates. This can be
used for removing sensitive or non-relevant messages so that there is nothing
visible in the log file.
This API is very similar to the
pre-Rebot modifier
API that can be used
to modify results before report and log are generated. The main difference is
that listeners modify also the created
output.xml
file.
Note
Removing messages altogether by setting them to
None
is new in
Robot Framework 7.2.
Changing keyword and control structure status
Listeners can also affect the execution flow by changing statuses of the executed
keywords and control structures. For example, if a listener changes the status of
a passed keyword to FAIL, the keyword is considered failed exactly as if it had
failed normally. Similarly, it is possible to change the status of a passed or
failed keyword to SKIP to get the keyword and the whole test skipped. It is
also possible to silence failures by changing the status to PASS, but this
should be done only in special cases and with great care to avoid hiding real
failures.
The following example demonstrates changing the status by failing keywords
that take too long time to execute. The previous example had similar logic
with tests, but this listener also stops the execution immediately if there
is a keyword that is too slow. As the example shows, listeners can also change
the error message, not only the status.
from
robot
import
result
,
running
class
KeywordPerformanceMonitor
:
def
__init__
(
self
,
max_seconds
:
float
=
0.1
):
self
.
max_seconds
=
max_seconds
def
end_keyword
(
self
,
data
:
running
.
Keyword
,
result
:
result
.
Keyword
):
elapsed_seconds
=
result
.
elapsed_time
.
total_seconds
()
if
result
.
status
==
'PASS'
and
elapsed_seconds
>
self
.
max_seconds
:
result
.
status
=
'FAIL'
result
.
message
=
'Keyword execution took too long.'
Note
Changes to status only affect the execution flow starting from
Robot Framework 7.1.
More examples
Keyword and control structure related listener version 3 methods are so versatile
that covering them fully here in the User Guide is not possible. For more examples,
you can see the
acceptance tests
using theses methods in various ways.
4.4 Parser interface
Robot Framework supports external parsers that can handle custom data formats or
even override Robot Framework's own parser.
Note
Custom parsers are new in Robot Framework 6.1.
4.4.1 Taking parsers into use
4.4.2 Parser API
EXTENSION
or
extension
attribute
parse
method
parse_init
method
Optional base class
4.4.3 Examples
Parser implemented as module
Parser implemented as class
Parser extending optional base class
Parser as preprocessor
4.4.1 Taking parsers into use
Parsers are taken into use from the command line with the
--parser
option using exactly the same semantics as with
listeners
. This includes
specifying parsers as names or paths, giving arguments to parser classes, and
so on:
robot --parser MyParser tests.custom
robot --parser path/to/MyParser.py tests.custom
robot --parser Parser1:arg --parser Parser2:a1:a2 path/to/tests
4.4.2 Parser API
Parsers can be implemented both as modules and classes. This section explains
what attributes and methods they must contain.
EXTENSION
or
extension
attribute
This attribute specifies what file extension or extensions the parser supports.
Both
EXTENSION
and
extension
names are accepted, and the former has precedence
if both exist. The attribute can be either a string or a sequence of strings.
Extensions are case-insensitive and can be specified with or without the leading
dot. If a parser is implemented as a class, it is possible to set this attribute
either as a class attribute or as an instance attribute.
Also extensions containing multiple parts like
.example.ext
or
.robot.zip
are supported.
Note
If a parser supports the
.robot
extension, it will be used
for parsing these files instead of the standard parser.
parse
method
The mandatory
parse
method is responsible for parsing
suite files
. It is
called with each parsed file that has an extension that the parser supports.
The method must return a
TestSuite
object.
In simple cases
parse
can be implemented so that it accepts just a single
argument that is a
pathlib.Path
object pointing to the file to
parse. If the parser is interested in defaults for
Test Setup
,
Test Teardown
,
Test Tags
and
Test Timeout
set in higher level
suite initialization files
, the
parse
method must
accept two arguments. In that case the second argument is a
TestDefaults
object.
parse_init
method
The optional
parse_init
method is responsible for parsing
suite initialization
files
i.e. files in format
__init__.ext
where
.ext
is an extension
supported by the parser. The method must return a
TestSuite
object representing the whole directory. Suites created from child suite files
and directories will be added to its child suites.
Also
parse_init
can be implemented so that it accepts one or two arguments,
depending on is it interested in test related default values or not. If it
accepts defaults, it can manipulate the passed
TestDefaults
object and changes
are seen when parsing child suite files.
This method is only needed if a parser needs to support suite initialization files.
Optional base class
Parsers do not need to implement any explicit interface, but it may be helpful
to extend the optional
Parser
base class. The main benefit is that the base
class has documentation and type hints. It also works as a bit more formal API
specification.
4.4.3 Examples
Parser implemented as module
The first example demonstrates a simple parser implemented as a module and
supporting one hard-coded extension. It just creates a dummy suite and does not
actually parse anything.
from
robot.api
import
TestSuite
EXTENSION
=
'.example'
def
parse
(
source
):
suite
=
TestSuite
(
name
=
'Example'
,
source
=
source
)
test
=
suite
.
tests
.
create
(
name
=
'Test'
)
test
.
body
.
create_keyword
(
name
=
'Log'
,
args
=
[
'Hello!'
])
return
suite
Parser implemented as class
The second parser is implemented as a class that accepts the extension to use
as an argument. The parser reads the given source file and creates dummy tests
from each line it contains.
from
pathlib
import
Path
from
robot.api
import
TestSuite
class
ExampleParser
:
def
__init__
(
self
,
extension
:
str
):
self
.
extension
=
extension
def
parse
(
self
,
source
:
Path
)
->
TestSuite
:
name
=
TestSuite
.
name_from_source
(
source
,
self
.
extension
)
suite
=
TestSuite
(
name
,
source
=
source
)
for
line
in
source
.
read_text
()
.
splitlines
():
test
=
suite
.
tests
.
create
(
name
=
line
)
test
.
body
.
create_keyword
(
name
=
'Log'
,
args
=
[
'Hello!'
])
return
suite
Parser extending optional base class
This parser extends the optional
Parser
base class. It supports parsing suite
initialization files, uses
TestDefaults
and registers multiple extensions.
from
pathlib
import
Path
from
robot.api
import
TestSuite
from
robot.api.interfaces
import
Parser
,
TestDefaults
class
ExampleParser
(
Parser
):
extension
=
(
'example'
,
'another'
)
def
parse
(
self
,
source
:
Path
,
defaults
:
TestDefaults
)
->
TestSuite
:
"""Create a suite and set possible defaults from init files to tests."""
suite
=
TestSuite
(
TestSuite
.
name_from_source
(
source
),
source
=
source
)
for
line
in
source
.
read_text
()
.
splitlines
():
test
=
suite
.
tests
.
create
(
name
=
line
,
doc
=
'Example'
)
test
.
body
.
create_keyword
(
name
=
'Log'
,
args
=
[
'Hello!'
])
defaults
.
set_to
(
test
)
return
suite
def
parse_init
(
self
,
source
:
Path
,
defaults
:
TestDefaults
)
->
TestSuite
:
"""Create a dummy suite and set some defaults.
This method is called only if there is an initialization file with
a supported extension.
"""
defaults
.
tags
=
(
'tags'
,
'from init'
)
defaults
.
setup
=
{
'name'
:
'Log'
,
'args'
:
[
'Hello from init!'
]}
return
TestSuite
(
TestSuite
.
name_from_source
(
source
.
parent
),
doc
=
'Example'
,
source
=
source
,
metadata
=
{
'Example'
:
'Value'
})
Parser as preprocessor
The final example parser acts as a preprocessor for Robot Framework data files
that supports headers in format
=== Test Cases ===
in addition to
*** Test Cases ***
. In this kind of usage it is convenient to use
TestSuite.from_string
,
TestSuite.from_model
and
TestSuite.from_file_system
factory methods for constructing the returned suite.
from
pathlib
import
Path
from
robot.running
import
TestDefaults
,
TestSuite
class
RobotPreprocessor
:
extension
=
'.robot'
def
parse
(
self
,
source
:
Path
,
defaults
:
TestDefaults
)
->
TestSuite
:
data
=
source
.
read_text
()
for
header
in
'Settings'
,
'Variables'
,
'Test Cases'
,
'Keywords'
:
data
=
data
.
replace
(
f
'===
{
header
}
==='
,
f
'***
{
header
}
***'
)
suite
=
TestSuite
.
from_string
(
data
,
defaults
=
defaults
)
return
suite
.
config
(
name
=
TestSuite
.
name_from_source
(
source
),
source
=
source
)
5 Supporting Tools
5.1 Library documentation tool (Libdoc)
5.2 Test data documentation tool (Testdoc)
5.3 Test data clean-up tool (Tidy)
5.4 External tools
5.1 Library documentation tool (Libdoc)
5.1.1 General usage
5.1.2 Writing documentation
5.1.3 Documentation syntax
5.1.4 Internal linking
5.1.5 Representing arguments
5.1.6 Libdoc example
Libdoc is Robot Framework's built-in tool that can generate documentation for
Robot Framework libraries and resource files. It can generate HTML documentation
for humans as well as machine readable spec files in XML and JSON formats.
Libdoc also has few special commands to show library or resource information
on the console.
Documentation can be created for:
libraries implemented using the normal static library
API
,
libraries using the
dynamic API
, including remote libraries,
resource files
,
suite files
, and
suite initialization files
.
Additionally it is possible to use XML and JSON spec files created by Libdoc
earlier as an input.
Note
Support for generating documentation for suite files and suite
initialization files is new in Robot Framework 6.0.
5.1.1 General usage
Synopsis
libdoc [options] library_or_resource output_file
libdoc [options] library_or_resource list|show|version [names]
Options
-f
,
--format
<html|xml|json|libspec>
Specifies whether to generate an HTML output for humans or
a machine readable spec file in XML or JSON format. The
libspec
format means XML spec with documentations converted
to HTML. The default format is got from the output file
extension.
-s
,
--specdocformat
<raw|html>
Specifies the documentation format used with XML and JSON
spec files.
raw
means preserving the original documentation
format and
html
means converting documentation to HTML. The
default is
raw
with XML spec files and
html
with JSON
specs and when using the special
libspec
format.
-F
,
--docformat
<robot|html|text|rest>
Specifies the source documentation format. Possible
values are Robot Framework's documentation format,
HTML, plain text, and reStructuredText. Default value
can be specified in test library source code and
the initial default value is
robot
.
--theme
<dark|light|none>
Use dark or light HTML theme. If this option is not used,
or the value is
none
, the theme is selected based on
the browser color scheme. Only applicable with HTML outputs.
New in Robot Framework 6.0.
--language
<lang>
Set the default language in documentation.
lang
must be a code of a built-in language, which are
en
and
fi
. New in Robot Framework 7.2.
-N
,
--name
<newname>
Sets the name of the documented library or resource.
-V
,
--version
<newversion>
Sets the version of the documented library or
resource. The default value for test libraries is
defined in the source code
.
-P
,
--pythonpath
<path>
Additional locations where to search for libraries
and resources similarly as when
running tests
.
--quiet
Do not print the path of the generated output file
to the console.
-h
,
--help
Prints this help.
Executing Libdoc
The easiest way to run Libdoc is using the
libdoc
command created as part of
the normal installation:
libdoc ExampleLibrary ExampleLibrary.html
Alternatively it is possible to execute the
robot.libdoc
module directly.
This approach is especially useful if you have installed Robot Framework using
multiple Python versions and want to use a specific version with Libdoc:
python -m robot.libdoc ExampleLibrary ExampleLibrary.html
python3.9 -m robot.libdoc ExampleLibrary ExampleLibrary.html
Yet another alternative is running the
robot.libdoc
module as a script:
python path/to/robot/libdoc.py ExampleLibrary ExampleLibrary.html
Note
The separate
libdoc
command is new in Robot Framework 4.0.
Specifying library or resource file
Python libraries and dynamic libraries with name or path
When documenting libraries implemented with Python or that use the
dynamic library API
, it is possible to specify the library either by
using just the library name or path to the library source code:
libdoc ExampleLibrary ExampleLibrary.html
libdoc src/ExampleLibrary.py docs/ExampleLibrary.html
In the former case the library is searched using the
module search path
and its name must be in the same format as when
importing libraries
in
Robot Framework test data.
If these libraries require arguments when they are imported, the arguments
must be catenated with the library name or path using two colons like
MyLibrary::arg1::arg2
. If arguments change what keywords the library
provides or otherwise alter its documentation, it might be a good idea to use
--name
option to also change the library name accordingly.
Resource files with path
Resource files must always be specified using a path:
libdoc example.resource example.html
If the path does not exist, resource files are also searched from all directories
in the
module search path
similarly as when executing test cases.
Libdoc spec files
Earlier generated Libdoc XML or JSON spec files can also be used as inputs.
This works if spec files use either
*.xml
,
*.libspec
or
*.json
extension:
libdoc Example.xml Example.html
libdoc Example.libspec Example.html
libdoc Example.json Example.html
Note
Support for the
*.libspec
extension is new in
Robot Framework 3.2.
Note
Support for the
*.json
extension is new in
Robot Framework 4.0.
Generating documentation
Libdoc can generate documentation in HTML (for humans) and XML or JSON (for tools)
formats. The file where to write the documentation is specified as the second
argument after the library/resource name or path, and the output format is
got from the output file extension by default.
Libdoc HTML documentation
Most Robot Framework libraries use Libdoc to generate library documentation
in HTML format. This format is thus familiar for most people who have used
Robot Framework. A simple example can be seen below, and it has been generated
based on the example found a
bit later in this section
.
The HTML documentation starts with general library introduction, continues
with a section about configuring the library when it is imported (when
applicable), and finally has shortcuts to all keywords and the keywords
themselves. The magnifying glass icon on the lower right corner opens the
keyword search dialog that can also be opened by simply pressing the
s
key.
Libdoc automatically creates HTML documentation if the output file extension
is
*.html
. If there is a need to use some other extension, the
format can be specified explicitly with the
--format
option.
Starting from Robot Framework 7.2, it is possible to localise the static
texts in the HTML documentation by using the
--language
option.
See the
README.rst
file in
src/web/libodc
directory in the project
repository for up to date information about how to add new languages
for the localisation.
libdoc OperatingSystem OperatingSystem.html
libdoc --name MyLibrary Remote::http://10.0.0.42:8270 MyLibrary.html
libdoc --format HTML test/resource.robot doc/resource.htm
Libdoc XML spec files
Libdoc can also generate documentation in XML format that is suitable for
external tools such as editors. It contains all the same information as
the HTML format but in a machine readable format.
XML spec files also contain library and keyword source information so that
the library and each keyword can have source path (
source
attribute) and
line number (
lineno
attribute). The source path is relative to the directory
where the spec file is generated thus does not refer to a correct file if
the spec is moved. The source path is omitted with keywords if it is
the same as with the library, and both the source path and the line number
are omitted if getting them from the library fails for whatever reason.
Libdoc automatically uses the XML format if the output file extension is
*.xml
or
*.libspec
. When using the special
*.libspec
extension, Libdoc automatically enables the options
-f XML -s HTML
which means
creating an XML output file where keyword documentation is converted to HTML.
If needed, the format can be explicitly set with the
--format
option.
libdoc OperatingSystem OperatingSystem.xml
libdoc test/resource.robot doc/resource.libspec
libdoc --format xml MyLibrary MyLibrary.spec
libdoc --format xml -s html MyLibrary MyLibrary.xml
The exact Libdoc spec file format is documented with an
XML schema
(XSD)
at
https://github.com/robotframework/robotframework/tree/master/doc/schema
.
The spec file format may change between Robot Framework major releases.
To make it easier for external tools to know how to parse a certain
spec file, the spec file root element has a dedicated
specversion
attribute. It was added in Robot Framework 3.2 with value
2
and earlier
spec files can be considered to have version
1
. The spec version will
be incremented in the future if and when changes are made.
Robot Framework 4.0 introduced new spec version
3
which is incompatible
with earlier versions.
Note
The
XML:HTML
format introduced in Robot Framework 3.2. has been
replaced by the format
LIBSPEC
ot the option combination
--format XML --specdocformat HTML
.
Note
Including source information and spec version are new in Robot
Framework 3.2.
Libdoc JSON spec files
Since Robot Framework 4.0 Libdoc can also generate documentation in JSON
format that is suitable for external tools such as editors or web pages.
It contains all the same information as the HTML format but in a machine
readable format.
Similar to XML spec files the JSON spec files contain all information and
can also be used as input to Libdoc. From that format any other output format
can be created. By default the library documentation strings are converted
to HTML format within the JSON output file.
The exact JSON spec file format is documented with an
JSON schema
at
https://github.com/robotframework/robotframework/tree/master/doc/schema
.
The spec file format may change between Robot Framework major releases.
Viewing information on console
Libdoc has three special commands to show information on the console.
These commands are used instead of the name of the output file, and they can
also take additional arguments.
list
List names of the keywords the library/resource contains. Can be
limited to show only certain keywords by passing optional patterns
as arguments. Keyword is listed if its name contains given pattern.
show
Show library/resource documentation. Can be limited to show only
certain keywords by passing names as arguments. Keyword is shown if
its name matches any given name. Special argument
intro
will show
only the library introduction and importing sections.
version
Show library version
Optional patterns given to
list
and
show
are case and space
insensitive. Both also accept
*
and
?
as wildcards.
Examples:
libdoc Dialogs list
libdoc SeleniumLibrary list browser
libdoc Remote::10.0.0.42:8270 show
libdoc Dialogs show PauseExecution execute*
libdoc SeleniumLibrary show intro
libdoc SeleniumLibrary version
5.1.2 Writing documentation
This section discusses writing documentation for
Python
based test
libraries that use the static library API as well as for
dynamic libraries
and
resource files
.
Creating test libraries
and
resource files
is
described in more details elsewhere in the User Guide.
Python libraries
The documentation for Python libraries that use the
static library API
is written simply as doc strings for the library class or module and for
methods implementing keywords. The first line of the method documentation is
considered as a short documentation for the keyword (used, for example, as
a tool tip in links in the generated HTML documentation), and it should
thus be as describing as possible, but not too long.
The simple example below illustrates how to write the documentation in
general. How the HTML documentation generated based on this example looks
like can be seen
above
, and there is also a
bit longer example
at
the end of this chapter.
class
ExampleLibrary
:
"""Library for demo purposes.
This library is only used in an example and it doesn't do anything useful.
"""
def
my_keyword
(
self
):
"""Does nothing."""
pass
def
your_keyword
(
self
,
arg
):
"""Takes one argument and *does nothing* with it.
Examples:
| Your Keyword | xxx |
| Your Keyword | yyy |
"""
pass
Tip
If you library does some initialization work that should not be done
when using Libdoc, you can
easily detect is Robot Framework running
Tip
For more information on Python documentation strings, see
PEP-257
.
Dynamic libraries
To be able to generate meaningful documentation for dynamic libraries,
the libraries must return keyword argument names and documentation using
get_keyword_arguments
and
get_keyword_documentation
methods (or using their camelCase variants
getKeywordArguments
and
getKeywordDocumentation
). Libraries can also support
general library documentation via special
__intro__
and
__init__
values to the
get_keyword_documentation
method.
See the
Dynamic library API
section for more information about how to
create these methods.
Importing section
A separate section about how the library is imported is created based on its
initialization methods. If the library has an
__init__
method that takes arguments in addition to
self
, its documentation and
arguments are shown.
class
TestLibrary
:
def
__init__
(
self
,
mode
=
'default'
)
"""Creates new TestLibrary. `mode` argument is used to determine mode."""
self
.
mode
=
mode
def
some_keyword
(
self
,
arg
):
"""Does something based on given `arg`.
What is done depends on the `mode` specified when `importing` the library.
"""
if
self
.
mode
==
'secret'
:
# ...
Resource file documentation
Keywords in resource files can have documentation using
[Documentation]
setting, and this documentation is also used by
Libdoc. First line of the documentation (until the first
implicit newline
or explicit
\n
) is considered to be the short
documentation similarly as with test libraries.
Also the resource file itself can have
Documentation
in the
Setting section for documenting the whole resource file.
Possible variables in resource files can not be documented.
*** Settings ***
Documentation
Resource file for demo purposes.
...
This resource is only used in an example and it doesn't do anything useful.
*** Keywords ***
My Keyword
[
Documentation
]
Does nothing
No Operation
Your Keyword
[
Arguments
] ${
arg
}
[
Documentation
]
Takes one argument and *does nothing* with it.
...
...
Examples:
...
| Your Keyword | xxx |
...
| Your Keyword | yyy |
No Operation
5.1.3 Documentation syntax
Libdoc supports documentation in Robot Framework's own
documentation
syntax
, HTML, plain text, and
reStructuredText
. The format to use can be
specified in
library source code
using
ROBOT_LIBRARY_DOC_FORMAT
attribute or given from the command line using
--docformat (-F)
option.
In both cases the possible case-insensitive values are
ROBOT
(default),
HTML
,
TEXT
and
reST
.
Robot Framework's own documentation format is the default and generally
recommended format. Other formats are especially useful when using existing
code with existing documentation in test libraries.
Robot Framework documentation syntax
Most important features in Robot Framework's
documentation syntax
are
formatting using
*bold*
and
_italic_
, custom links and
automatic conversion of URLs to links, and the possibility to create tables and
pre-formatted text blocks (useful for examples) simply with pipe character.
If documentation gets longer, support for section titles can also be handy.
Some of the most important formatting features are illustrated in the example
below. Notice that since this is the default format, there is no need to use
ROBOT_LIBRARY_DOC_FORMAT
attribute nor give the format from the command
line.
"""Example library in Robot Framework format.
- Formatting with *bold* and _italic_.
- URLs like http://example.com are turned to links.
- Custom links like [http://robotframework.org|Robot Framework] are supported.
- Linking to `My Keyword` works.
"""
def
my_keyword
():
"""Nothing more to see here."""
Creating table of contents automatically
With bigger libraries it is often useful to add a table of contents to
the library introduction. When using the Robot Framework documentation format,
this can be done automatically by adding a special
%TOC%
marker into a line
on its own. The table of contents is created based on the top-level
section titles
(e.g.
= Section =
) used in the introduction. In addition
to them, the TOC also gets links to the
automatically created sections
for shortcuts and keywords as well as for importing and tags sections when
applicable.
"""Example library demonstrating TOC generation.
The %TOC% marker only creates the actual table of contents and possible
header or other explanation needs to be added separately like done below.
== Table of contents ==
%TOC%
= Section title =
The top-level section titles are automatically added to the TOC.
= Second section =
== Sub section ==
Sub section titles are not added to the TOC.
"""
def
my_keyword
():
"""Nothing more to see here."""
Note
Automatic TOC generation is a new feature in Robot Framework 3.2.
HTML documentation syntax
When using HTML format, you can create documentation pretty much freely using
any syntax. The main drawback is that HTML markup is not that human friendly,
and that can make the documentation in the source code hard to maintain and read.
Documentation in HTML format is used by Libdoc directly without any
transformation or escaping. The special syntax for
linking to keywords
using
syntax like
`My Keyword`
is supported, however.
Example below contains the same formatting examples as the previous example.
Now
ROBOT_LIBRARY_DOC_FORMAT
attribute must be used or format given
on the command line like
--docformat HTML
.
"""Example library in HTML format.
<ul>
<li>Formatting with <b>bold</b> and <i>italic</i>.
<li>URLs are not turned to links automatically.
<li>Custom links like <a href="http://www.w3.org/html">HTML</a> are supported.
<li>Linking to `My Keyword` works.
</ul>
"""
ROBOT_LIBRARY_DOC_FORMAT
=
'HTML'
def
my_keyword
():
"""Nothing more to see here."""
Plain text documentation syntax
When the plain text format is used, Libdoc uses the documentation as-is.
Newlines and other whitespace are preserved except for indentation, and
HTML special characters (
<>&
) escaped. The only formatting done is
turning URLs into clickable links and supporting
internal linking
like
`My Keyword`
.
"""Example library in plain text format.
- Formatting is not supported.
- URLs like http://example.com are turned to links.
- Custom links are not supported.
- Linking to `My Keyword` works.
"""
ROBOT_LIBRARY_DOC_FORMAT
=
'text'
def
my_keyword
():
"""Nothing more to see here."""
reStructuredText documentation syntax
reStructuredText
is simple yet powerful markup syntax used widely in Python
projects (including this User Guide) and elsewhere. The main limitation
is that you need to have the
docutils
module installed to be able to generate
documentation using it. Because backtick characters have special meaning in
reStructuredText,
linking to keywords
requires them to be escaped like
\`My Keyword\`
.
One of the nice features that reStructured supports is the ability to mark code
blocks that can be syntax highlighted.
Syntax highlight requires additional
Pygments
module and supports all the
languages that Pygments supports.
"""Example library in reStructuredText format.
- Formatting with **bold** and *italic*.
- URLs like http://example.com are turned to links.
- Custom links like reStructuredText__ are supported.
- Linking to \`My Keyword\` works but requires backtics to be escaped.
__ http://docutils.sourceforge.net
.. code:: robotframework
*** Test Cases ***
Example
My keyword # How cool is this!!?!!?!1!!
"""
ROBOT_LIBRARY_DOC_FORMAT
=
'reST'
def
my_keyword
():
"""Nothing more to see here."""
5.1.4 Internal linking
Libdoc supports internal linking to keywords and different
sections in the documentation. Linking is done by surrounding the
target name with backtick characters like
`target`
. Target
names are case-insensitive and possible targets are explained in the
subsequent sections.
There is no error or warning if a link target is not found, but instead Libdoc
just formats the text in italics. Earlier this formatting was recommended to
be used when referring to keyword arguments, but that was problematic because
it could accidentally create internal links. Nowadays it is recommended to
use
inline code style
with double backticks like
``argument``
instead. The old formatting of single backticks
may even be removed in the future in favor of giving an error when a link
target is not found.
In addition to the examples in the following sections, internal linking
and argument formatting is shown also in the
longer example
at the
end of this chapter.
Linking to keywords
All keywords the library have automatically create link targets and they can
be linked using syntax
`Keyword Name`
. This is illustrated with
the example below where both keywords have links to each others.
def
keyword
(
log_level
=
"INFO"
):
"""Does something and logs the output using the given level.
Valid values for log level` are "INFO" (default) "DEBUG" and "TRACE".
See also `Another Keyword`.
"""
# ...
def
another_keyword
(
argument
,
log_level
=
"INFO"
):
"""Does something with the given argument else and logs the output.
See `Keyword` for information about valid log levels.
"""
# ...
Note
When using
reStructuredText documentation syntax
, backticks must
be escaped like
\`Keyword Name\`
.
Linking to automatic sections
The documentation generated by Libdoc always contains sections
for overall library introduction and for
keywords. If a library itself takes arguments, there is also
separate
importing section
. If any of the keywords has
tags
,
a separate selector for them is also shown in the overview.
All the sections act as targets that can be linked, and the possible
target names are listed in the table below. Using these targets is
shown in the example of the next section.
Automatic section link targets
Section
Target
Introduction
`introduction`
and
`library introduction`
Importing
`importing`
and
`library importing`
Keywords
`keywords`
Note
Before Robot Framework 4.0 there were also sections for tags and shortcuts.
In Robot Framework 4.0 these have been removed in favor of the overview menu. This means
that prior linking to shortcuts or tags sections does not work.
Linking to custom sections
Robot Framework's
documentation syntax
supports custom
section titles
, and the titles used in the
library or resource file introduction automatically create link
targets. The example below illustrates linking both to automatic and
custom sections:
"""Library for Libdoc demonstration purposes.
This library does not do anything useful.
= My section =
We do have a custom section in the documentation, though.
"""
def
keyword
():
"""Does nothing.
See `introduction` for more information and `My section` to test how
linking to custom sections works.
"""
pass
Note
Linking to custom sections works only when using
Robot Framework
documentation syntax
.
5.1.5 Representing arguments
Libdoc shows information about keywords' arguments automatically.
Included information
The following information is shown for all keywords regardless are they implemented
in libraries or in resource files:
Argument name. User keyword arguments are shown without the
${}
decoration
to make arguments look the same regardless where keywords originate from.
Marker telling is the argument
positional-only
,
named-only
,
free positional
,
free named
, or
normal argument
that can be given
either by position or by name.
Possible default value. Shown like
= 42
.
Possible type. Shown like
<int>
. Can be a link to type documentation as explained
in the next section.
When referring to arguments in keyword documentation, it is recommended to
use
inline code style
like
``argument``
.
Automatically listing type documentation
As mentioned above, Libdoc automatically shows possible type information when
listing arguments. If the type is a custom type based on
Enum
or
TypedDict
,
the type is
automatically converted
, or the type has
custom converter
,
also the type itself is listed separately to show more information about it.
When these types are used in arguments, the type name also becomes a link
to the type information.
All listed data types show possible type documentation as well as what argument
types are supported. In addition to that, types based on
Enum
list available
members and types based on
TypedDict
show the dictionary structure.
Note
Automatically listing types based on
Enum
and
TypedDict
is new
in Robot Framework 4.0. Listing other types is new in Robot Framework 5.0.
5.1.6 Libdoc example
The following example illustrates how to use the most important
documentation formatting
possibilities,
internal linking
, and so
on.
Click here
to see how the generated documentation looks like.
class
LoggingLibrary
:
"""Library for logging messages.
= Table of contents =
%TOC%
= Usage =
This library has several keyword, for example `Log Message`, for logging
messages. In reality the library is used only for _Libdoc_ demonstration
purposes.
= Valid log levels =
Valid log levels are ``INFO``, ``DEBUG``, and ``TRACE``. The default log
level can be set during `importing`.
= Examples =
Notice how keywords are linked from examples.
| `Log Message` | My message | | |
| `Log Two Messages` | My message | Second message | level=DEBUG |
| `Log Messages` | First message | Second message | Third message |
"""
ROBOT_LIBRARY_VERSION
=
'0.1'
def
__init__
(
self
,
default_level
=
'INFO'
):
"""The default log level can be given at library import time.
See `Valid log levels` section for information about available log
levels.
Examples:
| =Setting= | =Value= | =Value= | =Comment= |
| Library | LoggingLibrary | | # Use default level (INFO) |
| Library | LoggingLibrary | DEBUG | # Use the given level |
"""
self
.
default_level
=
self
.
_verify_level
(
default_level
)
def
_verify_level
(
self
,
level
):
level
=
level
.
upper
()
if
level
not
in
[
'INFO'
,
'DEBUG'
,
'TRACE'
]:
raise
RuntimeError
(
"Invalid log level'
%s
'. Valid levels are "
"'INFO', 'DEBUG', and 'TRACE'"
)
return
level
def
log_message
(
self
,
message
,
level
=
None
):
"""Writes given message to the log file using the specified log level.
The message to log and the log level to use are defined using
``message`` and ``level`` arguments, respectively.
If no log level is given, the default level given during `library
importing` is used.
"""
level
=
self
.
_verify_level
(
level
)
if
level
else
self
.
default_level
print
(
"*
%s
*
%s
"
%
(
level
,
message
))
def
log_two_messages
(
self
,
message1
,
message2
,
level
=
None
):
"""Writes given messages to the log file using the specified log level.
See `Log Message` keyword for more information.
"""
self
.
log_message
(
message1
,
level
)
self
.
log_message
(
message2
,
level
)
def
log_messages
(
self
,
*
messages
):
"""Logs given messages using the log level set during `importing`.
See also `Log Message` and `Log Two Messages`.
"""
for
msg
in
messages
:
self
.
log_message
(
msg
)
All
standard libraries
have documentation generated by
Libdoc and their documentation (and source code) act as a more
realistic examples.
5.2 Test data documentation tool (Testdoc)
5.2.1 General usage
5.2.2 Generating documentation
Testdoc is Robot Framework's built-in tool for generating high level
documentation based on test cases. The created documentation is in HTML
format and it includes name, documentation and other metadata of each
test suite and test case, as well as the top-level keywords and their
arguments.
Note
The built-in Testdoc tool is deprecated and will be removed in Robot
Framework 8.0. Use the new and enhanced
external Testdoc
instead.
5.2.1 General usage
Synopsis
python -m robot.testdoc [options] data_sources output_file
Options
-T
,
--title
<title>
Set the title of the generated documentation.
Underscores in the title are converted to spaces.
The default title is the name of the top level suite.
-N
,
--name
<name>
Override the name of the top level test suite.
-D
,
--doc
<doc>
Override the documentation of the top level test suite.
-M
,
--metadata
<name:value>
Set/override free metadata of the top level test suite.
-G
,
--settag
<tag>
Set given tag(s) to all test cases.
-t
,
--test
<name>
Include tests by name.
-s
,
--suite
<name>
Include suites by name.
-i
,
--include
<tag>
Include tests by tags.
-e
,
--exclude
<tag>
Exclude tests by tags.
-A
,
--argumentfile
<path>
Text file to read more arguments from. Works
exactly like
argument files
when running
tests.
-h
,
--help
Print this help in the console.
All options except
--title
have exactly the same semantics as same
options have when
executing test cases
.
5.2.2 Generating documentation
Data can be given as a single file, directory, or as multiple files and
directories. In all these cases, the last argument must be the file where
to write the output.
Testdoc can be executed as an installed module like
python -m robot.testdoc
or as a script like
python path/robot/testdoc.py
.
Examples:
python -m robot.testdoc my_test.robot testdoc.html
python path/to/robot/testdoc.py --name "Smoke tests" --include smoke path/to/tests smoke.html
5.3 Test data clean-up tool (Tidy)
The built-in Tidy tool was deprecated in Robot Framework 4.1 in favor of the
new and enhanced external
Robotidy
tool. It was removed altogether in
Robot Framework 5.0.
5.4 External tools
There are plenty of external tools that can be used with Robot Framework.
These tools include plugins for various IDEs and text editors, tools for
parallel execution and data-driven testing, plugins for continuous integration
systems, and so on.
These tools are developed as separate projects independently from Robot
Framework itself. For a list of the available tools see
http://robotframework.org/
.
6 Appendices
6.1 Available settings
6.2 Command line options
6.3 Translations
6.4 Documentation formatting
6.5 Time format
6.6 Boolean arguments
6.7 Evaluating expressions
6.8 Registrations
6.1 Available settings
This appendix lists all settings that can be used in different sections.
Note
Settings can be
localized
. See the
Translations
appendix for
supported translations.
6.1.1 Setting section
6.1.2 Test Case section
6.1.3 Keyword section
6.1.1 Setting section
The Setting section is used to import 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 section can only include settings for
importing libraries, resources, and variables.
Settings available in the Setting section
Name
Description
Library
Used for
importing libraries
.
Resource
Used for
taking resource files into use
.
Variables
Used for
taking variable files into use
.
Name
Used for setting a custom
suite name
.
Documentation
Used for specifying a
suite
or
resource file
documentation.
Metadata
Used for setting
free suite metadata
.
Suite Setup
Used for specifying the
suite setup
.
Suite Teardown
Used for specifying the
suite teardown
.
Test Tags
Used for specifying
test case tags
for all tests
in a suite.
Force Tags,
Default Tags
Deprecated settings
for specifying test case tags.
Keyword Tags
Used for specifying
user keyword tags
for all
keywords in a certain file.
Test Setup
Used for specifying a default
test setup
.
Test Teardown
Used for specifying a default
test teardown
.
Test Template
Used for specifying a default
template keyword
for test cases.
Test Timeout
Used for specifying a default
test case timeout
.
Task Setup,
Task Teardown,
Task Template,
Task Timeout
Aliases for Test Setup, Test Teardown, Test Template
and Test Timeout, respectively, that can be used when
creating tasks
.
6.1.2 Test Case section
The settings in the Test Case section are always specific to the test
case for which they are defined. Some of these settings override the
default values defined in the Settings section.
Exactly same settings are available when
creating tasks
in the Task section.
Settings available in the Test Case section
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
.
[Template]
Used for specifying a
template keyword
.
[Timeout]
Used for specifying a
test case timeout
.
6.1.3 Keyword section
Settings in the Keyword section are specific to the user keyword for
which they are defined.
Settings available in the Keyword section
Name
Description
[Documentation]
Used for specifying a
user keyword documentation
.
[Tags]
Used for specifying
user keyword tags
.
[Arguments]
Used for specifying
user keyword arguments
.
[Setup]
Used for specifying a
user keyword setup
.
New in Robot Framework 7.0.
[Teardown]
Used for specifying
user keyword teardown
.
[Timeout]
Used for specifying a
user keyword timeout
.
[Return]
Used for specifying
user keyword return values
.
Deprecated in Robot Framework 7.0. Use the
RETURN
statement instead.
6.2 Command line options
This appendix lists all the command line options that are available
when
executing test cases
and when
post-processing outputs
.
Also environment variables affecting execution and post-processing
are listed.
6.2.1 Command line options for test execution
6.2.2 Command line options for post-processing outputs
6.2.3 Environment variables for execution and post-processing
6.2.1 Command line options for test execution
--rpa
Turn on
generic automation
mode.
--language
<lang>
Activate
localization
.
lang
can be a name or a code
of a
built-in language
, or a path
or a module name of a custom language file.
-F
,
--extension
<value>
Parse only these files
when executing a directory.
-I
,
--parseinclude
<pattern>
Parse only matching files
when executing a directory.
-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
.
--task
<name>
Alias for
--test
that can be used when
executing tasks
.
-s
,
--suite
<name>
Selects the test suites
by name.
-R
,
--rerunfailed
<file>
Selects failed tests
from an earlier
output file
to be re-executed.
-S
,
--rerunfailedsuites
<file>
Selects failed test suites
from an earlier
output file
to be re-executed.
-i
,
--include
<tag>
Selects the test cases
by tag.
-e
,
--exclude
<tag>
Selects the test cases
by tag.
--skip
<tag>
Tests having given tag will be
skipped
. Tag can be a pattern.
--skiponfailure
<tag>
Tests having given tag will be
skipped
if they fail.
-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
.
--legacyoutput
Creates output file in
Robot Framework 6.x compatible format
.
-l
,
--log
<file>
Sets the path to the generated
log file
.
-r
,
--report
<file>
Sets the path to the generated
report file
.
-x
,
--xunit
<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
output files
listed above.
--splitlog
Split log file
into smaller pieces that open in
browser transparently.
--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.
--maxerrorlines
<lines>
Sets the number of
error lines
shown in report when tests fail.
--maxassignlength
<characters>
Sets the number of characters shown in log when
variables are assigned
.
-L
,
--loglevel
<level>
Sets the threshold level
for logging. Optionally
the default
visible log level
can be given
separated with a colon (:).
--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.
--expandkeywords
<name:pattern|tag:pattern>
Automatically
expand keywords
in the generated log file.
--removekeywords
<all|passed|name:pattern|tag:pattern|for|while|wuks>
Removes keyword data
from the generated log file.
--flattenkeywords
<for|while|iteration|name:pattern|tag:pattern>
Flattens keywords
in the generated log file.
--listener
<name:args>
Sets a listener
for monitoring test execution.
--nostatusrc
Sets the
return code
to zero regardless of failures
in test cases. Error codes are returned normally.
--runemptysuite
Executes tests also if the selected
test suites are empty
.
--dryrun
In the
dry run
mode tests are run without executing
keywords originating from test libraries. Useful for
validating test data syntax.
-X
,
--exitonfailure
Stops test execution
if any test fails.
--exitonerror
Stops test execution
if any error occurs when parsing test data, importing libraries, and so on.
--skipteardownonexit
Skips teardowns
if test execution is prematurely stopped.
--prerunmodifier
<name:args>
Activate
programmatic modification of test data
.
--prerebotmodifier
<name:args>
Activate
programmatic modification of results
.
--randomize
<all|suites|tests|none>
Randomizes
test execution order.
--console
<verbose|dotted|quiet|none>
Console output type
.
--dotted
Shortcut for
--console dotted
.
--quiet
Shortcut for
--console quiet
.
-W
,
--consolewidth
<width>
Sets the width
of the console output.
-C
,
--consolecolors
<auto|on|ansi|off>
Specifies are colors
used on the console.
--consolelinks
<auto|off>
Controls
making paths to results files hyperlinks
.
-K
,
--consolemarkers
<auto|on|off>
Show
markers on the console
when top level
keywords in a test case end.
-P
,
--pythonpath
<path>
Additional locations to add to the
module search path
.
-A
,
--argumentfile
<path>
A text file to
read more arguments
from.
-h
,
--help
Prints
usage instructions
.
--version
Prints the
version information
.
6.2.2 Command line options for post-processing outputs
--rpa
Turn on
generic automation
mode.
-R
,
--merge
Changes result combining behavior to
merging
.
-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
.
--task
<name>
Alias for
--test
.
-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.
-d
,
--outputdir
<dir>
Defines where to
create output files
.
-o
,
--output
<file>
Sets the path to the generated
output file
.
--legacyoutput
Creates output file in
Robot Framework 6.x compatible format
.
-l
,
--log
<file>
Sets the path to the generated
log file
.
-r
,
--report
<file>
Sets the path to the generated
report file
.
-x
,
--xunit
<file>
Sets the path to the generated
xUnit compatible result file
.
-T
,
--timestampoutputs
Adds a timestamp
to
output files
listed above.
--splitlog
Split log file
into smaller pieces that open in
browser transparently.
--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.
-L
,
--loglevel
<level>
Sets the threshold level
to select log messages.
Optionally the default
visible log level
can be given
separated with a colon (:).
--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.
--expandkeywords
<name:pattern|tag:pattern>
Automatically
expand keywords
in the generated log file.
--removekeywords
<all|passed|name:pattern|tag:pattern|for|wuks>
Removes keyword data
from the generated outputs.
--flattenkeywords
<for|foritem|name:pattern|tag:pattern>
Flattens keywords
in 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.
--processemptysuite
Processes output files even if files contain
empty test suites
.
--prerebotmodifier
<name:args>
Activate
programmatic modification of results
.
-C
,
--consolecolors
<auto|on|ansi|off>
Specifies are colors
used on the console.
--consolelinks
<auto|off>
Controls
making paths to results files hyperlinks
.
-P
,
--pythonpath
<path>
Additional locations to add to the
module search path
.
-A
,
--argumentfile
<path>
A text file to
read more arguments
from.
-h
,
--help
Prints
usage instructions
.
--version
Prints the
version information
.
6.2.3 Environment variables for execution and post-processing
ROBOT_OPTIONS
and
REBOT_OPTIONS
Space separated list of default options to be placed
in front of any explicit options
on the command line.
ROBOT_SYSLOG_FILE
Path to a
syslog
file where Robot Framework writes internal
information about parsing test case files and running
tests.
ROBOT_SYSLOG_LEVEL
Log level to use when writing to the
syslog
file.
ROBOT_INTERNAL_TRACES
When set to any non-empty value, Robot Framework's
internal methods are included in
error tracebacks
.
6.3 Translations
Robot Framework supports translating
section headers
,
settings
,
Given/When/Then prefixes
used in Behavior Driven Development (BDD)
as well as
true and false strings
used in automatic Boolean argument
conversion. This appendix lists all translations for all languages,
excluding English, that Robot Framework supports out-of-the-box.
How to actually activate translations is explained in the
Localization
section.
That section also explains how to create custom language definitions and
how to contribute new translations.
6.3.1 Arabic (ar)
6.3.2 Bulgarian (bg)
6.3.3 Bosnian (bs)
6.3.4 Czech (cs)
6.3.5 German (de)
6.3.6 Spanish (es)
6.3.7 Finnish (fi)
6.3.8 French (fr)
6.3.9 Hindi (hi)
6.3.10 Italian (it)
6.3.11 Japanese (ja)
6.3.12 Korean (ko)
6.3.13 Dutch (nl)
6.3.14 Polish (pl)
6.3.15 Portuguese (pt)
6.3.16 Brazilian Portuguese (pt-BR)
6.3.17 Romanian (ro)
6.3.18 Russian (ru)
6.3.19 Swedish (sv)
6.3.20 Thai (th)
6.3.21 Turkish (tr)
6.3.22 Ukrainian (uk)
6.3.23 Vietnamese (vi)
6.3.24 Chinese Simplified (zh-CN)
6.3.25 Chinese Traditional (zh-TW)
6.3.1 Arabic (ar)
New in Robot Framework 7.3.
Settings
Setting
Translation
Library
المكتبة
Resource
المورد
Variables
المتغيرات
Name
الاسم
Documentation
التوثيق
Metadata
البيانات الوصفية
Suite Setup
إعداد المجموعة
Suite Teardown
تفكيك المجموعة
Test Setup
تهيئة الاختبار
Task Setup
تهيئة المهمة
Test Teardown
تفكيك الاختبار
Task Teardown
تفكيك المهمة
Test Template
قالب الاختبار
Task Template
قالب المهمة
Test Timeout
مهلة الاختبار
Task Timeout
مهلة المهمة
Test Tags
علامات الاختبار
Task Tags
علامات المهمة
Keyword Tags
علامات الأوامر
Tags
العلامات
Setup
إعداد
Teardown
تفكيك
Template
قالب
Timeout
المهلة الزمنية
Arguments
المعطيات
BDD prefixes
Prefix
Translation
Given
بافتراض
When
عندما, لما
Then
إذن, عندها
And
و
But
لكن
Boolean strings
True/False
Values
True
نعم, صحيح
False
لا, خطأ
6.3.2 Bulgarian (bg)
Settings
Setting
Translation
Library
Библиотека
Resource
Ресурс
Variables
Променлива
Name
Documentation
Документация
Metadata
Метаданни
Suite Setup
Първоначални настройки на комплекта
Suite Teardown
Приключване на комплекта
Test Setup
Първоначални настройки на тестове
Task Setup
Първоначални настройки на задачи
Test Teardown
Приключване на тестове
Task Teardown
Приключване на задачи
Test Template
Шаблон за тестове
Task Template
Шаблон за задачи
Test Timeout
Таймаут за тестове
Task Timeout
Таймаут за задачи
Test Tags
Етикети за тестове
Task Tags
Етикети за задачи
Keyword Tags
Етикети за ключови думи
Tags
Етикети
Setup
Първоначални настройки
Teardown
Приключване
Template
Шаблон
Timeout
Таймаут
Arguments
Аргументи
BDD prefixes
Prefix
Translation
Given
В случай че
When
Когато
Then
Тогава
And
И
But
Но
Boolean strings
True/False
Values
True
Вярно, Да, Включен
False
Невярно, Не, Изключен, Нищо
6.3.3 Bosnian (bs)
Settings
Setting
Translation
Library
Biblioteka
Resource
Resursi
Variables
Varijable
Name
Documentation
Dokumentacija
Metadata
Metadata
Suite Setup
Suite Postavke
Suite Teardown
Suite Teardown
Test Setup
Test Postavke
Task Setup
Task Postavke
Test Teardown
Test Teardown
Task Teardown
Task Teardown
Test Template
Test Template
Task Template
Task Template
Test Timeout
Test Timeout
Task Timeout
Task Timeout
Test Tags
Test Tagovi
Task Tags
Task Tagovi
Keyword Tags
Keyword Tagovi
Tags
Tagovi
Setup
Postavke
Teardown
Teardown
Template
Template
Timeout
Timeout
Arguments
Argumenti
BDD prefixes
Prefix
Translation
Given
Uslovno
When
Kada
Then
Tada
And
I
But
Ali
Boolean strings
True/False
Values
True
False
6.3.4 Czech (cs)
Settings
Setting
Translation
Library
Knihovna
Resource
Zdroj
Variables
Proměnná
Name
Název
Documentation
Dokumentace
Metadata
Metadata
Suite Setup
Příprava sady
Suite Teardown
Ukončení sady
Test Setup
Příprava testu
Task Setup
Příprava úlohy
Test Teardown
Ukončení testu
Task Teardown
Ukončení úlohy
Test Template
Šablona testu
Task Template
Šablona úlohy
Test Timeout
Časový limit testu
Task Timeout
Časový limit úlohy
Test Tags
Štítky testů
Task Tags
Štítky úloh
Keyword Tags
Štítky klíčových slov
Tags
Štítky
Setup
Příprava
Teardown
Ukončení
Template
Šablona
Timeout
Časový limit
Arguments
Argumenty
BDD prefixes
Prefix
Translation
Given
Pokud
When
Když
Then
Pak
And
A
But
Ale
Boolean strings
True/False
Values
True
Pravda, Ano, Zapnuto
False
Nepravda, Ne, Vypnuto, Nic
6.3.5 German (de)
Settings
Setting
Translation
Library
Bibliothek
Resource
Ressource
Variables
Variablen
Name
Name
Documentation
Dokumentation
Metadata
Metadaten
Suite Setup
Suitevorbereitung
Suite Teardown
Suitenachbereitung
Test Setup
Testvorbereitung
Task Setup
Aufgabenvorbereitung
Test Teardown
Testnachbereitung
Task Teardown
Aufgabennachbereitung
Test Template
Testvorlage
Task Template
Aufgabenvorlage
Test Timeout
Testzeitlimit
Task Timeout
Aufgabenzeitlimit
Test Tags
Testmarker
Task Tags
Aufgabenmarker
Keyword Tags
Schlüsselwortmarker
Tags
Marker
Setup
Vorbereitung
Teardown
Nachbereitung
Template
Vorlage
Timeout
Zeitlimit
Arguments
Argumente
BDD prefixes
Prefix
Translation
Given
Angenommen
When
Wenn
Then
Dann
And
Und
But
Aber
Boolean strings
True/False
Values
True
Wahr, Ja, An, Ein
False
Falsch, Nein, Aus, Unwahr
6.3.6 Spanish (es)
Settings
Setting
Translation
Library
Biblioteca
Resource
Recursos
Variables
Variable
Name
Nombre
Documentation
Documentación
Metadata
Metadatos
Suite Setup
Configuración de la Suite
Suite Teardown
Desmontaje de la Suite
Test Setup
Configuración de prueba
Task Setup
Configuración de tarea
Test Teardown
Desmontaje de la prueba
Task Teardown
Desmontaje de tareas
Test Template
Plantilla de prueba
Task Template
Plantilla de tareas
Test Timeout
Tiempo de espera de la prueba
Task Timeout
Tiempo de espera de las tareas
Test Tags
Etiquetas de la prueba
Task Tags
Etiquetas de las tareas
Keyword Tags
Etiquetas de palabras clave
Tags
Etiquetas
Setup
Configuración
Teardown
Desmontaje
Template
Plantilla
Timeout
Tiempo agotado
Arguments
Argumentos
BDD prefixes
Prefix
Translation
Given
Dado
When
Cuando
Then
Entonces
And
Y
But
Pero
Boolean strings
True/False
Values
True
Verdadero, Si, On
False
Falso, No, Off, Ninguno
6.3.7 Finnish (fi)
Settings
Setting
Translation
Library
Kirjasto
Resource
Resurssi
Variables
Muuttujat
Name
Nimi
Documentation
Dokumentaatio
Metadata
Metatiedot
Suite Setup
Setin Alustus
Suite Teardown
Setin Alasajo
Test Setup
Testin Alustus
Task Setup
Tehtävän Alustus
Test Teardown
Testin Alasajo
Task Teardown
Tehtävän Alasajo
Test Template
Testin Malli
Task Template
Tehtävän Malli
Test Timeout
Testin Aikaraja
Task Timeout
Tehtävän Aikaraja
Test Tags
Testin Tagit
Task Tags
Tehtävän Tagit
Keyword Tags
Avainsanan Tagit
Tags
Tagit
Setup
Alustus
Teardown
Alasajo
Template
Malli
Timeout
Aikaraja
Arguments
Argumentit
BDD prefixes
Prefix
Translation
Given
Oletetaan
When
Kun
Then
Niin
And
Ja
But
Mutta
Boolean strings
True/False
Values
True
Tosi, Kyllä, Päällä
False
Epätosi, Ei, Pois
6.3.8 French (fr)
Settings
Setting
Translation
Library
Bibliothèque
Resource
Ressource
Variables
Variable
Name
Nom
Documentation
Documentation
Metadata
Méta-donnée
Suite Setup
Mise en place de suite
Suite Teardown
Démontage de suite
Test Setup
Mise en place de test
Task Setup
Mise en place de tâche
Test Teardown
Démontage de test
Task Teardown
Démontage de test
Test Template
Modèle de test
Task Template
Modèle de tâche
Test Timeout
Délai de test
Task Timeout
Délai de tâche
Test Tags
Étiquette de test
Task Tags
Étiquette de tâche
Keyword Tags
Etiquette de mot-clé
Tags
Étiquette
Setup
Mise en place
Teardown
Démontage
Template
Modèle
Timeout
Délai d'attente
Arguments
Arguments
BDD prefixes
Prefix
Translation
Given
Étant donné, Étant donné que, Étant donné qu', Soit, Sachant que, Sachant qu', Sachant, Etant donné, Etant donné que, Etant donné qu', Etant donnée, Etant données
When
Lorsque, Quand, Lorsqu'
Then
Alors, Donc
And
Et, Et que, Et qu'
But
Mais, Mais que, Mais qu'
Boolean strings
True/False
Values
True
Vrai, Oui, Actif
False
Faux, Non, Désactivé, Aucun
6.3.9 Hindi (hi)
Settings
Setting
Translation
Library
कोड़ प्रतिबिंब संग्रह
Resource
संसाधन
Variables
चर
Name
Documentation
प्रलेखन
Metadata
अधि-आंकड़ा
Suite Setup
जांच की शुरुवात
Suite Teardown
परीक्षण कार्य अंत
Test Setup
परीक्षण कार्य प्रारंभ
Task Setup
परीक्षण कार्य प्रारंभ
Test Teardown
परीक्षण कार्य अंत
Task Teardown
परीक्षण कार्य अंत
Test Template
परीक्षण ढांचा
Task Template
परीक्षण ढांचा
Test Timeout
परीक्षण कार्य समय समाप्त
Task Timeout
कार्य समयबाह्य
Test Tags
जाँचका उपनाम
Task Tags
कार्यका उपनाम
Keyword Tags
कुंजीशब्द का उपनाम
Tags
निशान
Setup
व्यवस्थापना
Teardown
विमोचन
Template
साँचा
Timeout
समय समाप्त
Arguments
प्राचल
BDD prefixes
Prefix
Translation
Given
दिया हुआ
When
जब
Then
तब
And
और
But
परंतु
Boolean strings
True/False
Values
True
यथार्थ, निश्चित, हां, पर
False
गलत, नहीं, हालाँकि, यद्यपि, नहीं, हैं
6.3.10 Italian (it)
Settings
Setting
Translation
Library
Libreria
Resource
Risorsa
Variables
Variabile
Name
Nome
Documentation
Documentazione
Metadata
Metadati
Suite Setup
Configurazione Suite
Suite Teardown
Distruzione Suite
Test Setup
Configurazione Test
Task Setup
Configurazione Attività
Test Teardown
Distruzione Test
Task Teardown
Distruzione Attività
Test Template
Modello Test
Task Template
Modello Attività
Test Timeout
Timeout Test
Task Timeout
Timeout Attività
Test Tags
Tag Del Test
Task Tags
Tag Attività
Keyword Tags
Tag Parola Chiave
Tags
Tag
Setup
Configurazione
Teardown
Distruzione
Template
Template
Timeout
Timeout
Arguments
Parametri
BDD prefixes
Prefix
Translation
Given
Dato
When
Quando
Then
Allora
And
E
But
Ma
Boolean strings
True/False
Values
True
Vero, Sì, On
False
Falso, No, Off, Nessuno
6.3.11 Japanese (ja)
New in Robot Framework 7.0.1.
Settings
Setting
Translation
Library
ライブラリ
Resource
リソース
Variables
変数
Name
名前
Documentation
ドキュメント
Metadata
メタデータ
Suite Setup
スイート セットアップ
Suite Teardown
スイート ティアダウン
Test Setup
テスト セットアップ
Task Setup
タスク セットアップ
Test Teardown
テスト ティアダウン
Task Teardown
タスク ティアダウン
Test Template
テスト テンプレート
Task Template
タスク テンプレート
Test Timeout
テスト タイムアウト
Task Timeout
タスク タイムアウト
Test Tags
テスト タグ
Task Tags
タスク タグ
Keyword Tags
キーワード タグ
Tags
タグ
Setup
セットアップ
Teardown
ティアダウン
Template
テンプレート
Timeout
タイムアウト
Arguments
引数
BDD prefixes
Prefix
Translation
Given
仮定, 指定, 前提条件
When
条件, 次の場合, もし, 実行条件
Then
アクション, その時, 動作
And
および, 及び, かつ, 且つ, ならびに, 並びに, そして, それから
But
ただし, 但し
Boolean strings
True/False
Values
True
真, 有効, はい, オン
False
偽, 無効, いいえ, オフ
6.3.12 Korean (ko)
New in Robot Framework 7.1.
Settings
Setting
Translation
Library
라이브러리
Resource
자료
Variables
변수
Name
이름
Documentation
문서
Metadata
메타데이터
Suite Setup
스위트 설정
Suite Teardown
스위트 중단
Test Setup
테스트 설정
Task Setup
작업 설정
Test Teardown
테스트 중단
Task Teardown
작업 중단
Test Template
테스트 템플릿
Task Template
작업 템플릿
Test Timeout
테스트 시간 초과
Task Timeout
작업 시간 초과
Test Tags
테스트 태그
Task Tags
작업 태그
Keyword Tags
키워드 태그
Tags
태그
Setup
설정
Teardown
중단
Template
템플릿
Timeout
시간 초과
Arguments
주장
BDD prefixes
Prefix
Translation
Given
주어진
When
때
Then
보다
And
그리고
But
하지만
Boolean strings
True/False
Values
True
참, 네, 켜기
False
거짓, 아니오, 끄기
6.3.13 Dutch (nl)
Settings
Setting
Translation
Library
Bibliotheek
Resource
Resource
Variables
Variabele
Name
Naam
Documentation
Documentatie
Metadata
Metadata
Suite Setup
Suitevoorbereiding
Suite Teardown
Suite-afronding
Test Setup
Testvoorbereiding
Task Setup
Taakvoorbereiding
Test Teardown
Testafronding
Task Teardown
Taakafronding
Test Template
Testsjabloon
Task Template
Taaksjabloon
Test Timeout
Testtijdslimiet
Task Timeout
Taaktijdslimiet
Test Tags
Testlabels
Task Tags
Taaklabels
Keyword Tags
Actiewoordlabels
Tags
Labels
Setup
Voorbereiding
Teardown
Afronding
Template
Sjabloon
Timeout
Tijdslimiet
Arguments
Parameters
BDD prefixes
Prefix
Translation
Given
Stel, Gegeven
When
Als
Then
Dan
And
En
But
Maar
Boolean strings
True/False
Values
True
Waar, Ja, Aan
False
Onwaar, Nee, Uit, Geen
6.3.14 Polish (pl)
Settings
Setting
Translation
Library
Biblioteka
Resource
Zasób
Variables
Zmienne
Name
Nazwa
Documentation
Dokumentacja
Metadata
Metadane
Suite Setup
Inicjalizacja Zestawu
Suite Teardown
Ukończenie Zestawu
Test Setup
Inicjalizacja Testu
Task Setup
Inicjalizacja Zadania
Test Teardown
Ukończenie Testu
Task Teardown
Ukończenie Zadania
Test Template
Szablon Testu
Task Template
Szablon Zadania
Test Timeout
Limit Czasowy Testu
Task Timeout
Limit Czasowy Zadania
Test Tags
Znaczniki Testu
Task Tags
Znaczniki Zadania
Keyword Tags
Znaczniki Słowa Kluczowego
Tags
Znaczniki
Setup
Inicjalizacja
Teardown
Ukończenie
Template
Szablon
Timeout
Limit Czasowy
Arguments
Argumenty
BDD prefixes
Prefix
Translation
Given
Zakładając, Zakładając, że, Mając
When
Jeżeli, Jeśli, Gdy, Kiedy
Then
Wtedy
And
Oraz, I
But
Ale
Boolean strings
True/False
Values
True
Prawda, Tak, Włączone
False
Fałsz, Nie, Wyłączone, Nic
6.3.15 Portuguese (pt)
Settings
Setting
Translation
Library
Biblioteca
Resource
Recurso
Variables
Variável
Name
Nome
Documentation
Documentação
Metadata
Metadados
Suite Setup
Inicialização de Suíte
Suite Teardown
Finalização de Suíte
Test Setup
Inicialização de Teste
Task Setup
Inicialização de Tarefa
Test Teardown
Finalização de Teste
Task Teardown
Finalização de Tarefa
Test Template
Modelo de Teste
Task Template
Modelo de Tarefa
Test Timeout
Tempo Limite de Teste
Task Timeout
Tempo Limite de Tarefa
Test Tags
Etiquetas de Testes
Task Tags
Etiquetas de Tarefas
Keyword Tags
Etiquetas de Palavras-Chave
Tags
Etiquetas
Setup
Inicialização
Teardown
Finalização
Template
Modelo
Timeout
Tempo Limite
Arguments
Argumentos
BDD prefixes
Prefix
Translation
Given
Dado
When
Quando
Then
Então
And
E
But
Mas
Boolean strings
True/False
Values
True
Verdadeiro, Verdade, Sim, Ligado
False
Falso, Não, Desligado, Desativado, Nada
6.3.16 Brazilian Portuguese (pt-BR)
Settings
Setting
Translation
Library
Biblioteca
Resource
Recurso
Variables
Variável
Name
Nome
Documentation
Documentação
Metadata
Metadados
Suite Setup
Configuração da Suíte
Suite Teardown
Finalização de Suíte
Test Setup
Inicialização de Teste
Task Setup
Inicialização de Tarefa
Test Teardown
Finalização de Teste
Task Teardown
Finalização de Tarefa
Test Template
Modelo de Teste
Task Template
Modelo de Tarefa
Test Timeout
Tempo Limite de Teste
Task Timeout
Tempo Limite de Tarefa
Test Tags
Test Tags
Task Tags
Task Tags
Keyword Tags
Keyword Tags
Tags
Etiquetas
Setup
Inicialização
Teardown
Finalização
Template
Modelo
Timeout
Tempo Limite
Arguments
Argumentos
BDD prefixes
Prefix
Translation
Given
Dado
When
Quando
Then
Então
And
E
But
Mas
Boolean strings
True/False
Values
True
Verdadeiro, Verdade, Sim, Ligado
False
Falso, Não, Desligado, Desativado, Nada
6.3.17 Romanian (ro)
Settings
Setting
Translation
Library
Librarie
Resource
Resursa
Variables
Variabila
Name
Nume
Documentation
Documentatie
Metadata
Metadate
Suite Setup
Configurare De Suita
Suite Teardown
Configurare De Intrerupere
Test Setup
Setare De Test
Task Setup
Configuarare activitate
Test Teardown
Inrerupere De Test
Task Teardown
Intrerupere activitate
Test Template
Sablon De Test
Task Template
Sablon de activitate
Test Timeout
Timp Expirare Test
Task Timeout
Timp de expirare activitate
Test Tags
Taguri De Test
Task Tags
Etichete activitate
Keyword Tags
Etichete metode
Tags
Etichete
Setup
Setare
Teardown
Intrerupere
Template
Sablon
Timeout
Expirare
Arguments
Argumente
BDD prefixes
Prefix
Translation
Given
Fie ca
When
Cand
Then
Atunci
And
Si
But
Dar
Boolean strings
True/False
Values
True
Adevarat, Da, Cand
False
Fals, Nu, Oprit, Niciun
6.3.18 Russian (ru)
Settings
Setting
Translation
Library
Библиотека
Resource
Ресурс
Variables
Переменные
Name
Documentation
Документация
Metadata
Метаданные
Suite Setup
Инициализация комплекта тестов
Suite Teardown
Завершение комплекта тестов
Test Setup
Инициализация теста
Task Setup
Инициализация задания
Test Teardown
Завершение теста
Task Teardown
Завершение задания
Test Template
Шаблон теста
Task Template
Шаблон задания
Test Timeout
Лимит выполнения теста
Task Timeout
Лимит задания
Test Tags
Теги тестов
Task Tags
Метки заданий
Keyword Tags
Метки ключевых слов
Tags
Метки
Setup
Инициализация
Teardown
Завершение
Template
Шаблон
Timeout
Лимит
Arguments
Аргументы
BDD prefixes
Prefix
Translation
Given
Дано
When
Когда
Then
Тогда
And
И
But
Но
Boolean strings
True/False
Values
True
False
6.3.19 Swedish (sv)
Settings
Setting
Translation
Library
Bibliotek
Resource
Resurs
Variables
Variabel
Name
Namn
Documentation
Dokumentation
Metadata
Metadata
Suite Setup
Svit konfigurering
Suite Teardown
Svit nedrivning
Test Setup
Test konfigurering
Task Setup
Task konfigurering
Test Teardown
Test nedrivning
Task Teardown
Task nedrivning
Test Template
Test mall
Task Template
Task mall
Test Timeout
Test timeout
Task Timeout
Task timeout
Test Tags
Test taggar
Task Tags
Arbetsuppgift taggar
Keyword Tags
Nyckelord taggar
Tags
Taggar
Setup
Konfigurering
Teardown
Nedrivning
Template
Mall
Timeout
Timeout
Arguments
Argument
BDD prefixes
Prefix
Translation
Given
Givet
When
När
Then
Då
And
Och
But
Men
Boolean strings
True/False
Values
True
Sant, Ja, På
False
Falskt, Nej, Av, Ingen
6.3.20 Thai (th)
Settings
Setting
Translation
Library
ชุดคำสั่งที่ใช้
Resource
ไฟล์ที่ใช้
Variables
ชุดตัวแปร
Name
Documentation
เอกสาร
Metadata
รายละเอียดเพิ่มเติม
Suite Setup
กำหนดค่าเริ่มต้นของชุดการทดสอบ
Suite Teardown
คืนค่าของชุดการทดสอบ
Test Setup
กำหนดค่าเริ่มต้นของการทดสอบ
Task Setup
กำหนดค่าเริ่มต้นของงาน
Test Teardown
คืนค่าของการทดสอบ
Task Teardown
คืนค่าของงาน
Test Template
โครงสร้างของการทดสอบ
Task Template
โครงสร้างของงาน
Test Timeout
เวลารอของการทดสอบ
Task Timeout
เวลารอของงาน
Test Tags
กลุ่มของการทดสอบ
Task Tags
กลุ่มของงาน
Keyword Tags
กลุ่มของคำสั่งเพิ่มเติม
Tags
กลุ่ม
Setup
กำหนดค่าเริ่มต้น
Teardown
คืนค่า
Template
โครงสร้าง
Timeout
หมดเวลา
Arguments
ค่าที่ส่งเข้ามา
BDD prefixes
Prefix
Translation
Given
กำหนดให้
When
เมื่อ
Then
ดังนั้น
And
และ
But
แต่
Boolean strings
True/False
Values
True
False
6.3.21 Turkish (tr)
Settings
Setting
Translation
Library
Kütüphane
Resource
Kaynak
Variables
Değişkenler
Name
Documentation
Dokümantasyon
Metadata
Üstveri
Suite Setup
Takım Kurulumu
Suite Teardown
Takım Bitişi
Test Setup
Test Kurulumu
Task Setup
Görev Kurulumu
Test Teardown
Test Bitişi
Task Teardown
Görev Bitişi
Test Template
Test Taslağı
Task Template
Görev Taslağı
Test Timeout
Test Zaman Aşımı
Task Timeout
Görev Zaman Aşımı
Test Tags
Test Etiketleri
Task Tags
Görev Etiketleri
Keyword Tags
Anahtar Kelime Etiketleri
Tags
Etiketler
Setup
Kurulum
Teardown
Bitiş
Template
Taslak
Timeout
Zaman Aşımı
Arguments
Argümanlar
BDD prefixes
Prefix
Translation
Given
Diyelim ki
When
Eğer ki
Then
O zaman
And
Ve
But
Ancak
Boolean strings
True/False
Values
True
Doğru, Evet, Açik
False
Yanliş, Hayir, Kapali
6.3.22 Ukrainian (uk)
Settings
Setting
Translation
Library
Бібліотека
Resource
Ресурс
Variables
Змінна
Name
Documentation
Документація
Metadata
Метадані
Suite Setup
Налаштування Suite
Suite Teardown
Розбірка Suite
Test Setup
Налаштування тесту
Task Setup
Налаштування завдання
Test Teardown
Розбирання тестy
Task Teardown
Розбір завдання
Test Template
Тестовий шаблон
Task Template
Шаблон завдання
Test Timeout
Час тестування
Task Timeout
Час очікування завдання
Test Tags
Тестові теги
Task Tags
Теги завдань
Keyword Tags
Теги ключових слів
Tags
Теги
Setup
Встановлення
Teardown
Cпростовувати пункт за пунктом
Template
Шаблон
Timeout
Час вийшов
Arguments
Аргументи
BDD prefixes
Prefix
Translation
Given
Дано
When
Коли
Then
Тоді
And
Та
But
Але
Boolean strings
True/False
Values
True
False
6.3.23 Vietnamese (vi)
New in Robot Framework 6.1.
Settings
Setting
Translation
Library
Thư viện
Resource
Tài nguyên
Variables
Biến số
Name
Tên
Documentation
Tài liệu hướng dẫn
Metadata
Dữ liệu tham chiếu
Suite Setup
Tiền thiết lập bộ kịch bản kiểm thử
Suite Teardown
Hậu thiết lập bộ kịch bản kiểm thử
Test Setup
Tiền thiết lập kịch bản kiểm thử
Task Setup
Tiền thiểt lập nhiệm vụ
Test Teardown
Hậu thiết lập kịch bản kiểm thử
Task Teardown
Hậu thiết lập nhiệm vụ
Test Template
Mẫu kịch bản kiểm thử
Task Template
Mẫu nhiễm vụ
Test Timeout
Thời gian chờ kịch bản kiểm thử
Task Timeout
Thời gian chờ nhiệm vụ
Test Tags
Các nhãn kịch bản kiểm thử
Task Tags
Các nhãn nhiệm vụ
Keyword Tags
Các từ khóa nhãn
Tags
Các thẻ
Setup
Tiền thiết lập
Teardown
Hậu thiết lập
Template
Mẫu
Timeout
Thời gian chờ
Arguments
Các đối số
BDD prefixes
Prefix
Translation
Given
Đã cho
When
Khi
Then
Thì
And
Và
But
Nhưng
Boolean strings
True/False
Values
True
Đúng, Vâng, Mở
False
Sai, Không, Tắt, Không Có Gì
6.3.24 Chinese Simplified (zh-CN)
Settings
Setting
Translation
Library
程序库
Resource
资源文件
Variables
变量文件
Name
Documentation
说明
Metadata
元数据
Suite Setup
用例集启程
Suite Teardown
用例集终程
Test Setup
用例启程
Task Setup
任务启程
Test Teardown
用例终程
Task Teardown
任务终程
Test Template
用例模板
Task Template
任务模板
Test Timeout
用例超时
Task Timeout
任务超时
Test Tags
用例标签
Task Tags
任务标签
Keyword Tags
关键字标签
Tags
标签
Setup
启程
Teardown
终程
Template
模板
Timeout
超时
Arguments
参数
BDD prefixes
Prefix
Translation
Given
假定
When
当
Then
那么
And
并且
But
但是
Boolean strings
True/False
Values
True
真, 是, 开
False
假, 否, 关, 空
6.3.25 Chinese Traditional (zh-TW)
Settings
Setting
Translation
Library
函式庫
Resource
資源文件
Variables
變量文件
Name
Documentation
說明
Metadata
元數據
Suite Setup
測試套啟程
Suite Teardown
測試套終程
Test Setup
測試啟程
Task Setup
任務啟程
Test Teardown
測試終程
Task Teardown
任務終程
Test Template
測試模板
Task Template
任務模板
Test Timeout
測試逾時
Task Timeout
任務逾時
Test Tags
測試標籤
Task Tags
任務標籤
Keyword Tags
關鍵字標籤
Tags
標籤
Setup
啟程
Teardown
終程
Template
模板
Timeout
逾時
Arguments
参数
BDD prefixes
Prefix
Translation
Given
假定
When
當
Then
那麼
And
並且
But
但是
Boolean strings
True/False
Values
True
真, 是, 開
False
假, 否, 關, 空
6.4 Documentation formatting
It is possible to use simple HTML formatting with
test suite
,
test case
and
user keyword
documentation and
free suite
metadata
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.
6.4.1 Handling whitespace in test data
Newlines
Spaces
6.4.2 Paragraphs
6.4.3 Inline styles
6.4.4 URLs
6.4.5 Custom links and images
Link with text content
Link with image content
Image with title text
6.4.6 Section titles
6.4.7 Tables
6.4.8 Lists
6.4.9 Preformatted text
6.4.10 Horizontal ruler
6.4.1 Handling whitespace in test data
Newlines
When documenting test suites, test cases and user keywords or adding metadata
to test suites, newlines can be added manually using
\n
escape sequence
.
*** Settings ***
Documentation
First line.\n\nSecond paragraph. This time\nwith multiple lines.
Metadata
Example list
- first item\n- second item\n- third
Note
As explained in the
Paragraphs
section below, the single newline in
Second paragraph, this time\nwith multiple lines.
does not actually
affect how that paragraph is rendered. Newlines are needed when
creating
lists
or other such constructs, though.
Adding newlines manually to a long documentation takes some effort and extra
characters also make the documentation harder to read. This can be avoided,
though, as newlines are inserted automatically
between
continued documentation and metadata lines
. In practice this
means that the above example could be written also as follows.
*** Settings ***
Documentation
...
First line.
...
...
Second paragraph. This time
...
with multiple lines.
Metadata
...
Example list
...
- first item
...
- second item
...
- third
No automatic newline is added if a line already ends with a literal newline
or if it ends with an
escaping backslash
:
*** Test Cases ***
Ends with newline
[
Documentation
]
Ends with a newline and\n
...
automatic newline is not added.
Ends with backslash
[
Documentation
]
Ends with a backslash and \
...
no newline is added.
Spaces
Unlike elsewhere in Robot Framework data, leading spaces and consecutive internal
spaces are preserved in documentation and metadata. This makes it possible, for example,
to split
list items
to multiple rows and have
preformatted text
with spaces:
*** Test Cases ***
Long list item
[
Documentation
]
...
List:
...
- Short item.
...
- Second item is pretty long and it is split to
...
multiple rows. Leading spaces are preserved.
...
- Another short item.
Preformatted text
[
Documentation
]
...
Example with consecutive internal spaces:
...
...
| *** Test Cases ***
...
| Example
...
|
Keyword
Note
Preserving spaces in documentation and metadata is new in Robot Framework 6.1.
With earlier versions spaces need to be escaped with a backslash.
6.4.2 Paragraphs
All regular text in the formatted HTML
documentation is represented as paragraphs. In practice, lines separated
by a single newline will be combined in a paragraph regardless whether the
newline is added manually or automatically. Multiple paragraphs can be separated
with an empty line (i.e. two newlines) and also tables, lists, and other
specially formatted blocks discussed in subsequent sections end a paragraph.
For example, the following test suite or resource file documentation:
*** Settings ***
Documentation
...
First paragraph has only one line.
...
...
Second paragraph, this time created
...
with multiple lines.
will be formatted in HTML as:
First paragraph has only one line.
Second paragraph, this time created with multiple lines.
6.4.3 Inline styles
The documentation syntax supports inline styles
bold
,
italic
and
code
.
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*_
.
The code style is created using double backticks like
``code``
.
The result is monospaced text with light gray background.
Asterisks, underscores or double backticks alone, or in the middle of a word,
do not start formatting, but punctuation characters before or after them
are allowed. When multiple lines form a
paragraph
, all inline styles can
span over multiple lines.
Inline style examples
Unformatted
Formatted
*bold*
bold
_italic_
italic
_*bold italic*_
bold italic
``code``
code
*bold*, then _italic_ and finally ``some code``
bold
, then
italic
and finally
some code
This is *bold\n
on multiple\n
lines*.
This is
bold
on multiple
lines
.
6.4.4 URLs
All strings that look like URLs are automatically converted into
clickable links. Additionally, URLs that end with extension
.jpg
,
.jpeg
,
.png
,
.gif
,
.bmp
or
.svg
(case-insensitive) will automatically create images. For
example, URLs like
http://example.com
are turned into links, and
http:///host/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, and for test suite metadata.
Note
.svg
image support is new in Robot Framework 3.2.
6.4.5 Custom links and images
It is possible to create custom links
and embed images using special syntax
[link|content]
. This creates
a link or image depending are
link
and
content
images.
They are considered images if they have the same image extensions that are
special with
URLs
or start with
data:image/
. The surrounding square
brackets and the pipe character between the parts are mandatory in all cases.
Note
Support for the
data:image/
prefix is new in Robot Framework 3.2.
Link with text content
If neither
link
nor
content
is an image, the end result is
a normal link where
link
is the link target and
content
the visible text:
[file.html|this file] -> <a href="file.html">this file</a>
[http://host|that host] -> <a href="http://host">that host</a>
Link with image content
If
content
is an image, you get a link where the link content is an
image. Link target is created by
link
and it can be either text or image:
[robot.html|robot.png] -> <a href="robot.html"><img src="robot.png"></a>
[robot.html|data:image/png;base64,oooxxx=] -> <a href="robot.html"><img src="data:image/png;base64,oooxxx="></a>
[image.jpg|thumb.jpg] -> <a href="image.jpg"><img src="thumb.jpg"></a>
Image with title text
If
link
is an image but
content
is not, the syntax creates an
image where the
content
is the title text shown when mouse is over
the image:
[robot.jpeg|Robot rocks!] -> <img src="robot.jpeg" title="Robot rocks!">
[data:image/png;base64,oooxxx=|Robot rocks!] -> <img src="data:image/png;base64,oooxxx=" title="Robot rocks!">
6.4.6 Section titles
If documentation gets longer, it is often a good idea to split it into
sections. It is possible to separate
sections with titles using syntax
= My Title =
, where the number of
equal signs denotes the level of the title:
= First section =
== Subsection ==
Some text.
== Second subsection ==
More text.
= Second section =
You probably got the idea.
Notice that only three title levels are supported and that spaces between
equal signs and the title text are mandatory.
6.4.7 Tables
Tables are created using pipe characters with spaces around them
as column separators and newlines as row separators. Header
cells can be created by surrounding the cell content with equal signs
and optional spaces like
= Header =
or
=Header=
. Tables
cells can also contain links and formatting such as bold and italic:
| =A= | =B= | = C = |
| _1_ | Hello | world! |
| _2_ | Hi |
The created table always has a thin border and normal text is left-aligned.
Text in header cells is bold and centered. Empty cells are automatically
added to make rows equally long. For example, the above example would be
formatted like this in HTML:
A
B
C
1
Hello
world
2
Hi
6.4.8 Lists
Lists are created by starting a line with a hyphen and space ('- '). List items
can be split into multiple lines by indenting continuing lines with one or more
spaces. A line that does not start with '- ' and is not indented ends the list:
Example:
- a list item
- second list item
is continued
This is outside the list.
The above documentation is formatted like this in HTML:
Example:
a list item
second list item is continued
This is outside the list.
6.4.9 Preformatted text
It is possible to embed blocks of
preformatted text in the documentation. Preformatted block is created by
starting lines with '| ', one space being mandatory after the pipe character
except on otherwise empty lines. The starting '| ' sequence will be removed
from the resulting HTML, but all other whitespace is preserved.
In the following documentation, the two middle lines form a preformatted
block when converted to HTML:
Doc before block:
| inside block
| some additional whitespace
After block.
The above documentation is formatted like this:
Doc before block:
inside block
some additional whitespace
After block.
6.4.10 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 or more
hyphens alone on a line:
Some text here.
---
More text...
The above documentation is formatted like this:
Some text here.
More text...
6.5 Time format
Robot Framework has its own time format that is both flexible to use and easy
to understand. It is used by several keywords (for example,
BuiltIn
keywords
Sleep
and
Wait Until Keyword Succeeds
),
DateTime
library, and
timeouts
.
6.5.1 Time as number
6.5.2 Time as time string
6.5.3 Time as "timer" string
6.5.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.
Note
In some contexts plain numbers can be interpreted otherwise as
times. For example, with
WHILE loop limit
integers denote
the maximum iteration count.
6.5.2 Time as time string
Representing the time as a time string 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 it is possible to add
-
prefix to specify negative
times. The available time specifiers are:
weeks, week, w
days, day, d
hours, hour, h
minutes, minute, mins, min, m
seconds, second, secs, sec, s
milliseconds, millisecond, millis, ms
microseconds, microsecond, us, μs
nanoseconds, nanosecond, ns
Examples:
1 min 30 secs
1.5 minutes
90 s
1 day 2 hours 3 minutes 4 seconds 5 milliseconds 6 microseconds 7 nanoseconds
8 weeks 7 days 6 hours 5 minutes 4 seconds 3 milliseconds 2 microseconds 1 nanosecond
1d 2h 3m 4s 5ms 6μs 7 ns
8w 7d 6h 5m 4s 3ms 2μs 1ns
- 10 seconds
Note
Support for micro and nanoseconds is new in Robot Framework 6.0.
Support for weeks is new in Robot Framework 7.1.
6.5.3 Time as "timer" string
Time can also be given in timer like
format
hh:mm:ss.mil
. In this format both hour and millisecond parts
are optional, leading and trailing zeros can be left out when they are not
meaningful, and negative times can be represented by adding the
-
prefix. For example, following timer and time string values are identical:
Timer and time string examples
Timer
Time string
00:00:01
1 second
01:02:03
1 hour 2 minutes 3 seconds
1:00:00
1 hour
100:00:00
100 hours
00:02
2 seconds
42:00
42 minutes
00:01:02.003
1 minute 2 seconds 3 milliseconds
00:01.5
1.5 seconds
-01:02.345
- 1 minute 2 seconds 345 milliseconds
6.6 Boolean arguments
Many keywords in Robot Framework
standard libraries
accept arguments that
are handled as Boolean values true or false. If such an argument is given as
a string, it is considered false if it is an empty string or equal to
FALSE
,
NONE
,
NO
,
OFF
or
0
, case-insensitively. Other
strings are considered true unless the keyword documentation explicitly
states otherwise, and other argument types are tested using the same
rules as in Python
.
*** Keywords ***
True examples
Should Be Equal
${
x
} ${
y
}
Custom error
values=True
# Strings are generally true.
Should Be Equal
${
x
} ${
y
}
Custom error
values=yes
# Same as the above.
Should Be Equal
${
x
} ${
y
}
Custom error
values=
${
TRUE
}
# Python `True` is true.
Should Be Equal
${
x
} ${
y
}
Custom error
values=
${
42
}
# Numbers other than 0 are true.
False examples
Should Be Equal
${
x
} ${
y
}
Custom error
values=False
# String `false` is false.
Should Be Equal
${
x
} ${
y
}
Custom error
values=no
# Also string `no` is false.
Should Be Equal
${
x
} ${
y
}
Custom error
values=
${
EMPTY
}
# Empty string is false.
Should Be Equal
${
x
} ${
y
}
Custom error
values=
${
FALSE
}
# Python `False` is false.
Should Be Equal
${
x
} ${
y
}
Custom error
values=no values
# Special false string with this keyword.
Note
Considering
OFF
and
0
false is new in Robot Framework 3.1.
6.7 Evaluating expressions
This appendix explains how expressions are evaluated using Python in different
contexts and how variables in expressions are handled.
6.7.1 Introduction
6.7.2 Evaluation namespace
6.7.3 Using variables
Normal
${variable}
syntax
Special
$variable
syntax
6.7.1 Introduction
Constructs such as
IF/ELSE structures
,
WHILE loops
and
inline Python evaluation
as well as several
BuiltIn
keywords accept an expression that is evaluated in Python:
*** Test Cases ***
IF/ELSE
IF
${
x
}
> 0
Log to console
${
x
}
is positive
ELSE
Log to console
${
x
}
is negative
END
Inline Python evaluation
Log to console
${
x
}
is
${
{'positive' if
${
x
}
> 0 else 'negative'
}
}
Evaluate keyword
${
type
} =
Evaluate
'positive' if
${
x
}
> 0 else 'negative'
Log to console
${
x
}
is
${
type
}
Should Be True keyword
Should Be True
${
x
}
> 0
Notice that instead of creating complicated
expressions, it is often better to move the logic into a
test library
.
That typically eases maintenance and also enhances execution speed.
6.7.2 Evaluation namespace
Expressions are evaluated using Python's
eval
function so that normal Python
constructs like
'${x}' == 'expected'
,
${x} > 0
and
'${x}'.upper() not in ('FAIL', 'BAD')
can be used and all
builtin functions like
len()
and
int()
are available.
In addition to that, all unrecognized Python variables are considered to be
modules that are automatically imported. It is possible to use all available
Python modules, including the standard modules and the installed third party
modules.
The following examples demonstrate using Python builtins as well as modules
using the
inline Python evaluation
syntax, but same expressions would also
work with
IF/ELSE structures
and
BuiltIn
keywords without the need to use
the
${{}}
decoration around the expression:
*** Variables ***
${
VAR
}
123
*** Test Cases ***
Python syntax
Should Be True
${
{'
${
VAR
}
' == '123'
}
}
Should Be True
${
{'
${
VAR
}
'.startswith('x') or '
${
VAR
}
' in '012345'
}
}
Python builtins
Should Be Equal
${
{len('
${
VAR
}
')
}
}
${
3
}
Should Be Equal
${
{int('
${
VAR
}
')
}
}
${
123
}
Access modules
Should Be Equal
${
{os.sep
}
}
${
/
}
Should Be Equal
${
{round(math.pi, 2)
}
}
${
3.14
}
Should Start With
${
{robot.__version__
}
}
4.
A limitation of using modules is that nested modules like
rootmod.submod
can only be used if the root module automatically imports the submodule. That is
not always the case and using such modules is not possible. An concrete example
that is relevant in the automation context is the
selenium
module that is
implemented, at least at the time of this writing, so that just importing
selenium
does not import the
selenium.webdriver
submodule.
Another limitation is that modules cannot be used in the expression part of
a list comprehension. A workaround to both of these problems
is using the
BuiltIn
keyword
Evaluate
that accepts modules to be imported
and added to the evaluation namespace as an argument:
*** Test Cases ***
Does not work due to nested module structure
Log
${
{selenium.webdriver.ChromeOptions()
}
}
Evaluate keyword with nested module
${
options
} =
Evaluate
selenium.webdriver.ChromeOptions()
modules=selenium.webdriver
Log
${
options
}
Does not work due to list comprehension
Log
${
{[json.loads(item) for item in ('1', '"b"')]
}
}
Evaluate keyword with list comprehension
${
items
} =
Evaluate
[json.loads(item) for item in ('1', '"b"')]
modules=json
Log
${
items
}
The
Evaluate
keyword also supports custom evaluation namespaces if further
customization is needed. See its documentation in the
BuiltIn
library for more details.
6.7.3 Using variables
Normal
${variable}
syntax
When a variable is used in the expression using the normal
${variable}
syntax, its value is replaced before the expression is evaluated. This
means that the value used in the expression will be the string
representation of the variable value, not the variable value itself.
This is not a problem with numbers and other objects that have a string
representation that can be evaluated directly. For example, if we have
a return code as an integer in variable
${rc}
, using something like
${rc} > 0
is fine.
With other objects the behavior depends on the string representation.
Most importantly, strings must always be quoted either with
single or double quotes like
'${x}'
, and if they can contain newlines, they must be
triple-quoted like
'''${x}'''
. Strings containing quotes themselves cause
additional problems, but triple-quoting typically handles them. Also the
backslash character
\
is problematic, but can be handled by
using Python's raw-string notation like
r'${path}'
.
*** Test Cases ***
Using normal variable syntax
Should Be True
${
rc
}
> 0
IF
'
${
status
}
'.upper() == 'PASS'
Log
Passed
END
IF
'FAIL' in r'''
${
output
}
'''
Log
Output contains FAIL
END
Special
$variable
syntax
Quoting strings is not that convenient, but there are cases where replacing the variable
with its string representation causes even bigger problems. For example, if the variable
value can be either a string or Python
None
, quoting like
'${var}'
is needed because
otherwise strings do not work, but then
None
is interpreted to be a string as well.
Luckily there is an easy solution to these problems discussed in this section.
Actual variables values are available in the evaluation namespace and can be accessed
using special variable syntax without the curly braces like
$variable
. Such variables
should never be quoted, not even if they contain strings.
Compare this these examples with the example in the previous section:
*** Test Cases ***
Using special variable syntax
Should Be True
$rc > 0
IF
$status.upper() == 'PASS'
Log
Passed
END
IF
'FAIL' in $output
Log
Output contains FAIL
END
Only possible using special variable syntax
Should Be True
$example is not None
Should Be True
len($result) > 1 and $result[1] == 'OK'
Using the
$variable
syntax slows down expression evaluation a little.
This should not typically matter, but should be taken into account if
complex expressions are evaluated often and there are strict time
constrains. Moving such logic to test libraries is typically a good idea
anyway.
Note
Due to technical reasons, these special variables are available during
evaluation as local variables. That makes them unavailable in non-local
scopes such as in the expression part of list comprehensions and inside
lambdas.
6.8 Registrations
This appendix lists file extensions, media types, and so on, that are
associated with Robot Framework.
6.8.1 Suite file extensions
Suite files
with the following extensions are parsed automatically:
.robot
Suite file using the
plain text format
.
.robot.rst
Suite file using the
reStructuredText format
.
.rbt
Suite file using the
JSON format
.
Using other extensions is possible, but it requires
separate configuration
.
6.8.2 Resource file extensions
Resource files
can use the following extensions:
.resource
Recommended when using the plain text format.
.robot
,
.txt
and
.tsv
Supported with the plain text format for backwards compatibility reasons.
.resource
is recommended and may be mandated in the future.
.rst
and
.rest
Resource file using the
reStructuredText format
.
.rsrc
and
.json
Resource file using the
JSON format
. |
| Markdown | # Robot Framework User Guide
## Version 7.4.2
Copyright © 2008-2015 Nokia Networks
Copyright © 2016- Robot Framework Foundation
Licensed under the [Creative Commons Attribution 3.0 Unported](http://creativecommons.org/licenses/by/3.0) license
Table of Contents
- [1 Getting started](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-started)
- [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction)
- [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#why-robot-framework)
- [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#high-level-architecture)
- [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#screenshots)
- [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-more-information)
- [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#copyright-and-license)
- [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions)
- [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-installation)
- [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-using-pip)
- [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-from-source)
- [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#verifying-installation)
- [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dependencies)
- [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments)
- [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#demonstrations)
- [2 Creating test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data)
- [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-syntax)
- [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#files-and-directories)
- [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections)
- [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats)
- [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rules-for-parsing-the-data)
- [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization)
- [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#style)
- [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases)
- [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax)
- [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments)
- [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures)
- [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation)
- [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases)
- [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown)
- [2\.2.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates)
- [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-case-styles)
- [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks)
- [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-syntax)
- [2\.3.2 Task related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-settings)
- [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites)
- [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files)
- [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories)
- [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name)
- [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation)
- [2\.4.5 Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata)
- [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown)
- [2\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries)
- [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries)
- [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import)
- [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library)
- [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries)
- [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries)
- [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables)
- [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-1)
- [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables)
- [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables)
- [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables)
- [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes)
- [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-variable-features)
- [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords)
- [2\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-syntax)
- [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation)
- [2\.7.3 User keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags)
- [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments)
- [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name)
- [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values)
- [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown)
- [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#private-user-keywords)
- [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#recursion)
- [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files)
- [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files)
- [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#control-structures)
- [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops)
- [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops)
- [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-control-using-break-and-continue)
- [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-syntax)
- [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax)
- [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-syntax)
- [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-features)
- [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names)
- [2\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts)
- [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parallel-execution-of-keywords)
- [3 Executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases)
- [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage-1)
- [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution)
- [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-command-line-options)
- [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-results)
- [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files)
- [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information)
- [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-start-up-scripts)
- [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#making-robot-files-executable)
- [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems)
- [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-execution)
- [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-flow)
- [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-and-suite-statuses)
- [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuing-on-failure)
- [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully)
- [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution)
- [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generic-automation-mode)
- [3\.3.2 Task related command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-command-line-options)
- [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs)
- [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-rebot)
- [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-reports-logs-and-output-files)
- [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs)
- [3\.4.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs)
- [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-output-files)
- [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution)
- [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse)
- [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases)
- [3\.5.3 Setting metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-metadata)
- [3\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions)
- [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-variables)
- [3\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run)
- [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order)
- [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data)
- [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-console-output)
- [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners)
- [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-files)
- [3\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files)
- [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels)
- [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs)
- [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics)
- [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords)
- [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords)
- [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution)
- [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports)
- [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results)
- [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)
- [4 Extending Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-robot-framework)
- [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries)
- [4\.1.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-2)
- [4\.1.2 Creating test library class or module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-library-class-or-module)
- [4\.1.3 Creating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords)
- [4\.1.4 Communicating with Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#communicating-with-robot-framework)
- [4\.1.5 Distributing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#distributing-test-libraries)
- [4\.1.6 Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api)
- [4\.1.7 Hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api)
- [4\.1.8 Handling Robot Framework's timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-robot-framework-s-timeouts)
- [4\.1.9 Using Robot Framework's internal modules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules)
- [4\.1.10 Extending existing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries)
- [4\.2 Remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface)
- [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-3)
- [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#putting-remote-library-to-use)
- [4\.2.3 Supported argument and return value types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types)
- [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol)
- [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface)
- [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-structure)
- [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions)
- [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-listeners-into-use)
- [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-calling-order)
- [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-examples)
- [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface)
- [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-parsers-into-use)
- [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-api)
- [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#examples-2)
- [5 Supporting Tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supporting-tools)
- [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-documentation-tool-libdoc)
- [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage)
- [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#writing-documentation)
- [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax)
- [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking-1)
- [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#representing-arguments)
- [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example)
- [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-documentation-tool-testdoc)
- [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage-1)
- [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-documentation-1)
- [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-clean-up-tool-tidy)
- [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-tools)
- [6 Appendices](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#appendices)
- [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings)
- [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-section-1)
- [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-section)
- [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-section-1)
- [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options)
- [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-test-execution)
- [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-post-processing-outputs)
- [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables-for-execution-and-post-processing)
- [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations)
- [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
- [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting)
- [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-whitespace-in-test-data)
- [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs)
- [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles)
- [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls)
- [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-links-and-images)
- [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles)
- [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tables)
- [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists)
- [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text)
- [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#horizontal-ruler)
- [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format)
- [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number)
- [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string)
- [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string)
- [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-arguments)
- [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions)
- [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-4)
- [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluation-namespace)
- [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables-1)
- [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registrations)
- [6\.8.1 Suite file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-file-extensions)
- [6\.8.2 Resource file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-extensions)
- [6\.8.3 Media type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#media-type)
- [6\.8.4 Remote server port](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-server-port)
# [1 Getting started](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-1)
- [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction)
- [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#copyright-and-license)
- [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions)
- [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#demonstrations)
## [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-226)
Robot Framework is a Python-based, extensible keyword-driven automation framework for acceptance testing, acceptance test driven development (ATDD), behavior driven development (BDD) and robotic process automation (RPA). It can be used in distributed, heterogeneous environments, where automation requires using different technologies and interfaces.
The framework has a rich ecosystem around it consisting of various generic libraries and tools that are developed as separate projects. For more information about Robot Framework and the ecosystem, see <http://robotframework.org>.
Robot Framework is open source software released under the [Apache License 2.0](http://apache.org/licenses/LICENSE-2.0). Its development is sponsored by the [Robot Framework Foundation](http://robotframework.org/foundation).
Note
The official RPA support was added in Robot Framework 3.1. This User Guide still talks mainly about creating tests, test data, and test libraries, but same concepts apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
- [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#why-robot-framework)
- [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#high-level-architecture)
- [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#screenshots)
- [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-more-information)
- [Project pages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#project-pages)
- [Mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists)
### [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-230)
- Enables easy-to-use tabular syntax for [creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) in a uniform way.
- Provides ability to create reusable [higher-level keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) from the existing keywords.
- Provides easy-to-read result [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) in HTML format.
- Is platform and application independent.
- Provides a simple [library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) for creating customized test libraries which can be implemented natively with Python.
- Provides a [command line interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and XML based [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for integration into existing build infrastructure (continuous integration systems).
- Provides support for testing web applications, rest APIs, mobile applications, running processes, connecting to remote systems via Telnet or SSH, and so on.
- Supports creating [data-driven test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
- Has built-in support for [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), practical particularly for testing in different environments.
- Provides [tagging](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) to categorize and [select test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) to be executed.
- Enables easy integration with source control: [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) are just files and directories that can be versioned with the production code.
- Provides [test-case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [test-suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) -level setup and teardown.
- The modular architecture supports creating tests even for applications with several diverse interfaces.
### [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-231)
Robot Framework is a generic, application and technology independent framework. It has a highly modular architecture illustrated in the diagram below.

Robot Framework architecture
The [test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data) is in simple, easy-to-edit tabular format. When Robot Framework is started, it processes the data, [executes test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) 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 [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries). Libraries can either use application interfaces directly or use lower level test tools as drivers.
### [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-232)
Following screenshots show examples of the [test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data) and created [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).

Test case file

Reports and logs
### [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-233)
#### [Project pages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-234)
The number one place to find more information about Robot Framework and the rich ecosystem around it is <http://robotframework.org>. Robot Framework itself is hosted on [GitHub](https://github.com/robotframework/robotframework).
#### [Mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-235)
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](http://www.catb.org/~esr/faqs/smart-questions.html).
[robotframework-users](http://groups.google.com/group/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](http://groups.google.com/group/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](http://groups.google.com/group/robotframework-devel)
Discussion about Robot Framework development.
## [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-227)
Robot Framework is open source software provided under the [Apache License 2.0](http://apache.org/licenses/LICENSE-2.0). Robot Framework documentation such as this User Guide use the [Creative Commons Attribution 3.0 Unported](http://creativecommons.org/licenses/by/3.0) license. Most libraries and tools in the larger ecosystem around the framework are also open source, but they may use different licenses.
The full Robot Framework copyright notice is included below:
```
Copyright 2008-2015 Nokia Networks
Copyright 2016- Robot Framework Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
## [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-228)
These instructions cover installing [Robot Framework](https://robotframework.org/) and its preconditions on different operating systems. If you already have [Python](http://python.org/) installed, you can install Robot Framework using the standard package manager [pip](https://pip.pypa.io/):
```
pip install robotframework
```
- [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-installation)
- [Installing Python on Linux](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-linux)
- [Installing Python on Windows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-windows)
- [Installing Python on macOS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-macos)
- [PyPy installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pypy-installation)
- [Configuring `PATH`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path)
- [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-using-pip)
- [Running `pip` command](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-pip-command)
- [Installing and uninstalling Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-and-uninstalling-robot-framework)
- [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-from-source)
- [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#verifying-installation)
- [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dependencies)
- [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments)
### [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-236)
[Robot Framework](https://robotframework.org/) is implemented using [Python](http://python.org/), and a precondition to install it is having Python or its alternative implementation [PyPy](https://pypy.org/) installed. Another recommended precondition is having the [pip](https://pip.pypa.io/) package manager available.
Robot Framework requires Python 3.8 or newer. The latest version that supports Python 3.6 and 3.7 is [Robot Framework 6.1.1](https://github.com/robotframework/robotframework/blob/v6.1.1/INSTALL.rst). If you need to use Python 2, [Jython](http://jython.org/) or [IronPython](http://ironpython.net/), you can use [Robot Framework 4.1.3](https://github.com/robotframework/robotframework/blob/v4.1.3/INSTALL.rst).
#### [Installing Python on Linux](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-237)
On Linux you should have suitable Python installation with [pip](https://pip.pypa.io/) available by default. If not, you need to consult your distributions documentation to learn how to install them. This is also true if you want to use some other Python version than the one provided by your distribution by default.
To check what Python version you have installed, you can run `python --version` command in a terminal:
```
$ python --version
Python 3.10.13
```
Notice that if your distribution provides also older Python 2, running `python` may use that. To use Python 3, you can use `python3` command or even more version specific command like `python3.8`. You need to use these version specific variants also if you have multiple Python 3 versions installed and need to pinpoint which one to use:
```
$ python3.11 --version
Python 3.11.7
$ python3.12 --version
Python 3.12.1
```
Installing Robot Framework directly under the system provided Python has a risk that possible problems can affect the whole Python installation used also by the operating system itself. Nowadays Linux distributions typically use [user installs](https://pip.pypa.io/en/stable/user_guide/#user-installs) by default to avoid such problems, but users can also themselves decide to use [virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments).
#### [Installing Python on Windows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-238)
On Windows Python is not available by default, but it is easy to install. The recommended way to install it is using the official Windows installers available at <http://python.org>. For other alternatives, such as installing from the Microsoft Store, see the [official Python documentation](https://docs.python.org/3/using/windows.html).
When installing Python on Windows, it is recommended to add Python to [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) to make it and tools like pip and Robot Framework easier to execute from the command line. When using the [official installer](https://docs.python.org/3/using/windows.html#windows-full), you just need to select the `Add Python 3.x to PATH` checkbox on the first dialog.
To make sure Python installation has been successful and Python has been added to `PATH`, you can open the command prompt and execute `python --version`:
```
C:\>python --version
Python 3.10.9
```
If you install multiple Python versions on Windows, the version that is used when you execute `python` is the one first in `PATH`. If you need to use others, the easiest way is using the [py launcher](https://docs.python.org/3/using/windows.html#launcher):
```
C:\>py --version
Python 3.10.9
C:\>py -3.12 --version
Python 3.12.1
```
#### [Installing Python on macOS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-239)
MacOS does not provide Python 3 compatible Python version by default, so it needs to be installed separately. The recommended approach is using the official macOS installers available at <http://python.org>. If you are using a package manager like [Homebrew](https://brew.sh/), installing Python via it is possible as well.
You can validate Python installation on macOS using `python --version` like on other operating systems.
#### [PyPy installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-240)
[PyPy](https://pypy.org/) is an alternative Python implementation. Its main advantage over the standard Python implementation is that it can be faster and use less memory, but this depends on the context where and how it is used. If execution speed is important, at least testing PyPy is probably a good idea.
Installing PyPy is a straightforward procedure and you can find both installers and installation instructions at <http://pypy.org>. To validate that PyPy installation was successful, run `pypy --version` or `pypy3 --version`.
Note
Using Robot Framework with PyPy is officially supported only on Linux.
#### [Configuring `PATH`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-241)
The [PATH environment variable](https://en.wikipedia.org/wiki/PATH_\(variable\)) lists directories where commands executed in a system are searched from. To make using Python, [pip](https://pip.pypa.io/) and Robot Framework easier from the command line, it is recommended to add the Python installation directory as well as the directory where commands like `pip` and `robot` are installed into `PATH`.
When using Python on Linux or macOS, Python and tools installed with it should be automatically in `PATH`. If you nevertheless need to update `PATH`, you typically need to edit some system wide or user specific configuration file. Which file to edit and how depends on the operating system and you need to consult its documentation for more details.
On Windows the easiest way to make sure `PATH` is configured correctly is setting the `Add Python 3.x to PATH` checkbox when [running the installer](https://docs.python.org/3/using/windows.html#the-full-installer). To manually modify `PATH` on Windows, follow these steps:
1. Find `Environment Variables` under `Settings`. There are variables affecting the whole system and variables affecting only the current user. Modifying the former will require admin rights, but modifying the latter is typically enough.
2. Select `PATH` (often written like `Path`) and click `Edit`. If you are editing user variables and `PATH` does not exist, click `New` instead.
3. Add both the Python installation directory and the Scripts directory under the installation directory into `PATH`.
4. Exit the dialog with `Ok` to save the changes.
5. Start a new command prompt for the changes to take effect.
### [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-242)
These instructions cover installing Robot Framework using [pip](https://pip.pypa.io/), the standard Python package manager. If you are using some other package manager like [Conda](https://conda.io/), you can use it instead but need to study its documentation for instructions.
When installing Python, you typically get pip installed automatically. If that is not the case, you need to check the documentation of that Python installation for instructions how to install it separately.
#### [Running `pip` command](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-243)
Typically you use pip by running the `pip` command, but on Linux you may need to use `pip3` or even more Python version specific variant like `pip3.8` instead. When running `pip` or any of its variants, the pip version that is found first in [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) will be used. If you have multiple Python versions installed, you may need to pinpoint which exact version you want to use. This is typically easiest done by running `python -m pip` and substituting `python` with the Python version you want to use.
To make sure you have pip available, you can run `pip --version` or equivalent.
Examples on Linux:
```
$ pip --version
pip 23.2.1 from ... (python 3.10)
$ python3.12 -m pip --version
pip 23.3.1 from ... (python 3.12)
```
Examples on Windows:
```
C:\> pip --version
pip 23.2.1 from ... (python 3.10)
C:\> py -m 3.12 -m pip --version
pip 23.3.2 from ... (python 3.12)
```
In the subsequent sections pip is always run using the `pip` command. You may need to use some of the other approaches explained above in your environment.
#### [Installing and uninstalling Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-244)
The easiest way to use pip is by letting it find and download packages it installs from the [Python Package Index (PyPI)](https://pypi.org/project/robotframework), but it can also install packages downloaded from the PyPI separately. The most common usages are shown below and [pip](https://pip.pypa.io/) documentation has more information and examples.
```
# Install the latest version (does not upgrade)
pip install robotframework
# Upgrade to the latest stable version
pip install --upgrade robotframework
# Upgrade to the latest version even if it is a pre-release
pip install --upgrade --pre robotframework
# Install a specific version
pip install robotframework==7.0
# Install separately downloaded package (no network connection needed)
pip install robotframework-7.0-py3-none-any.whl
# Install latest (possibly unreleased) code directly from GitHub
pip install https://github.com/robotframework/robotframework/archive/master.zip
# Uninstall
pip uninstall robotframework
```
### [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-245)
Another installation alternative is getting Robot Framework source code and installing it using the provided `setup.py` script. This approach is recommended only if you do not have [pip](https://pip.pypa.io/) available for some reason.
You can get the source code by downloading a source distribution package from [PyPI](https://pypi.org/project/robotframework) and extracting it. An alternative is cloning the [GitHub](https://github.com/robotframework/robotframework) repository and checking out the needed release tag.
Once you have the source code, you can install it with the following command:
```
python setup.py install
```
The `setup.py` script accepts several arguments allowing, for example, installation into a non-default location that does not require administrative rights. It is also used for creating different distribution packages. Run `python setup.py --help` for more details.
### [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-246)
To make sure that the correct Robot Framework version has been installed, run the following command:
```
$ robot --version
Robot Framework 7.0 (Python 3.10.3 on linux)
```
If running these commands fails with a message saying that the command is not found or recognized, a good first step is double-checking the [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) configuration.
If you have installed Robot Framework under multiple Python versions, running `robot` will execute the one first in [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path). To select explicitly, you can run `python -m robot` and substitute `python` with the right Python version.
```
$ python3.12 -m robot --version
Robot Framework 7.0 (Python 3.12.1 on linux)
C:\>py -3.11 -m robot --version
Robot Framework 7.0 (Python 3.11.7 on win32)
```
### [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-247)
Robot Framework core functionality has no mandatory dependencies other than Python and its standard library. Some individual features may require optional dependencies to be installed, though. What dependencies are needed is always explained in the relevant documentation.
### [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-248)
Python [virtual environments](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) allow Python packages to be installed in an isolated location for a particular system or application, rather than installing all packages into the same global location. They have two main use cases:
- Install packages needed by different projects into their own environments. This avoids conflicts if projects need different versions of same packages.
- Avoid installing everything under the global Python installation. This is especially important on Linux where the global Python installation may be used by the distribution itself and messing it up can cause severe problems.
## [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-229)
There are several demo projects that introduce Robot Framework and help getting started with it.
[Quick Start Guide](https://github.com/robotframework/QuickStartGuide/blob/master/QuickStart.rst)
Introduces the most important features of Robot Framework and acts as an executable demo.
[Robot Framework demo](https://github.com/robotframework/RobotDemo)
Simple example test cases. Demonstrates also creating custom test libraries.
[Web testing demo](https://github.com/robotframework/WebDemo)
Demonstrates how to create tests and higher level keywords. The system under test is a simple web page that is tested using [SeleniumLibrary](https://github.com/robotframework/SeleniumLibrary).
[ATDD with Robot Framework](https://code.google.com/p/atdd-with-robot-framework)
Demonstrates how to use Robot Framework when following Acceptance Test Driven Development (ATDD) process.
# [2 Creating test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-16)
- [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-syntax)
- [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases)
- [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks)
- [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites)
- [2\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries)
- [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables)
- [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords)
- [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files)
- [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#control-structures)
- [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-features)
## [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-249)
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. Although this section mostly uses term *test*, the same rules apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
- [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#files-and-directories)
- [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections)
- [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats)
- [Space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format)
- [Pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format)
- [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format)
- [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format)
- [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rules-for-parsing-the-data)
- [Ignored data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignored-data)
- [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping)
- [Dividing data to several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows)
- [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization)
- [Enabling languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages)
- [Built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages)
- [Custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files)
- [Contributing translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations)
- [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#style)
### [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-259)
The hierarchical structure for arranging test cases is built as follows:
- Test cases are created in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files).
- A test case file automatically creates a [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites) containing the test cases in that file.
- A directory containing test case files forms a higher-level test suite. Such a [suite directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories) has suites created from test case files as its child 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) configuring the created test suite.
In addition to this, there are:
- [Test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) containing the lowest-level keywords.
- [Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) with [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) and higher-level [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords).
- [Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) to provide more flexible ways to create variables than resource files.
Test case files, test suite initialization files and resource files are all created using Robot Framework test data syntax. Test libraries and variable files are created using "real" programming languages, most often Python.
### [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-260)
Robot Framework data is defined in different sections, often also called tables, listed below:
| Section | Used for |
|---|---|
| Settings | 1\) Importing [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) and [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files). 2\) Defining metadata for [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) and [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase). |
| Variables | Defining [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) that can be used elsewhere in the test data. |
| Test Cases | [Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) from available keywords. |
| Tasks | [Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) using available keywords. Single file can only contain either tests or tasks. |
| Keywords | [Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) from existing lower-level keywords |
| Comments | Additional comments or data. Ignored by Robot Framework. |
Different sections are recognized by their header row. The recommended header format is `*** Settings ***`, but the header is case-insensitive, surrounding spaces are optional, and the number of asterisk characters can vary as long as there is at least one asterisk in the beginning. For example, also `*settings` would be recognized as a section header.
Robot Framework supports also singular headers like `*** Setting ***,` but that support was deprecated in Robot Framework 6.0. There is a visible deprecation warning starting from Robot Framework 7.0 and singular headers will eventually not be supported at all.
The header row can contain also other data than the actual section header. The extra data must be separated from the section header using the data format dependent separator, typically two or more spaces. These extra headers are ignored at parsing time, but they can be used for documenting purposes. This is especially useful when creating test cases using the [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
Possible data before the first section is ignored.
Note
Section headers can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
### [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-261)
The most common approach to create Robot Framework data is using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format) where pieces of the data, such as keywords and their arguments, are separated from each others with two or more spaces. An alternative is using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format) where the separator is the pipe character surrounded with spaces (\|).
Suite files typically use the .robot extension, but what files are parsed [can be configured](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse). [Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) can use the .robot extension as well, but using the dedicated .resource extension is recommended and may be mandated in the future. Files containing non-ASCII characters must be saved using the UTF-8 encoding.
Robot Framework supports also [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) files so that normal Robot Framework data is [embedded into code blocks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format). Only files with the .robot.rst extension are parsed by default. If you would rather use just .rst or .rest extension, that needs to be configured separately.
Robot Framework data can also be created in the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format) that is targeted more for tool developers than normal Robot Framework users. Only JSON files with the custom .rbt extension are parsed by default.
Earlier Robot Framework versions supported data also in HTML and TSV formats. The TSV format still works if the data is compatible with the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format), but the support for the HTML format has been removed altogether. If you encounter such data files, you need to convert them to the plain text format to be able to use them with Robot Framework 3.2 or newer. The easiest way to do that is using the [Tidy](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tidy) tool, but you must use the version included with Robot Framework 3.1 because newer versions do not understand the HTML format at all.
#### [Space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-262)
When Robot Framework parses data, it first splits the data to lines and then lines to tokens such as keywords and arguments. When using the space separated format, the separator between tokens is two or more spaces or alternatively one or more tab characters. In addition to the normal ASCII space, any Unicode character considered to be a space (e.g. no-break space) works as a separator. The number of spaces used as separator can vary, as long as there are at least two, making it possible to align the data nicely in settings and elsewhere when it makes the data easier to understand.
```
*** Settings ***
Documentation Example using the space separated format.
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
*** Test Cases ***
My Test
[Documentation] Example test.
Log ${MESSAGE}
My Keyword ${CURDIR}
Another Test
Should Be Equal ${MESSAGE} Hello, world!
*** Keywords ***
My Keyword
[Arguments] ${path}
Directory Should Exist ${path}
```
Because tabs and consecutive spaces are considered separators, they must be escaped if they are needed in keyword arguments or elsewhere in the actual data. It is possible to use special escape syntax like `\t` for tab and `\xA0` for no-break space as well as [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) `${SPACE}` and `${EMPTY}`. See the [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) section for details.
Tip
Although using two spaces as a separator is enough, it is recommended to use four spaces to make the separator easier to recognize.
Note
Prior to Robot Framework 3.2, non-ASCII spaces used in the data were converted to ASCII spaces during parsing. Nowadays all data is preserved as-is.
#### [Pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-263)
The biggest problem of the space delimited format is that visually separating keywords from 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 delimited variant can work better because it makes the separator more visible.
One file can contain both space separated and pipe separated lines. Pipe separated lines are recognized by the mandatory leading pipe character, but the pipe at the end of the line is optional. There must always be at least one space or tab on both sides of the pipe except at the beginning and at the end of the line. There is no need to align the pipes, but that often makes the data easier to read.
```
| *** Settings *** |
| Documentation | Example using the pipe separated format.
| Library | OperatingSystem
| *** Variables *** |
| ${MESSAGE} | Hello, world!
| *** Test Cases *** | | |
| My Test | [Documentation] | Example test. |
| | Log | ${MESSAGE} |
| | My Keyword | ${CURDIR} |
| Another Test | Should Be Equal | ${MESSAGE} | Hello, world!
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
```
When using the pipe separated format, consecutive spaces or tabs inside arguments do not need to be escaped. Similarly empty columns do not need to be escaped except [if they are at the end](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping). Possible pipes surrounded by spaces in the actual test data must be escaped with a backslash, though:
```
| *** Test Cases *** | | | |
| Escaping Pipe | ${file count} = | Execute Command | ls -1 *.txt \| wc -l |
| | Should Be Equal | ${file count} | 42 |
```
Note
Preserving consecutive spaces and tabs in arguments is new in Robot Framework 3.2. Prior to it non-ASCII spaces used in the data were also converted to ASCII spaces.
#### [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-264)
[reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) (reST) is an 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. reST documents are most often compiled to HTML, but also other output formats are supported. Using reST with Robot Framework allows you to mix richly formatted documents and test data in a concise text format that is easy to work with using simple text editors, diff tools, and source control systems.
Note
Using [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) files with Robot Framework requires the Python [docutils](https://pypi.python.org/pypi/docutils) module to be installed.
When using Robot Framework with reStructuredText files, normal Robot Framework data is embedded to so called code blocks. In standard reST code blocks are marked using the `code` directive, but Robot Framework supports also `code-block` or `sourcecode` directives used by the [Sphinx](http://sphinx-doc.org/) tool.
```
reStructuredText example
------------------------
This text is outside code blocks and thus ignored.
.. code:: robotframework
*** Settings ***
Documentation Example using the reStructuredText format.
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
*** Test Cases ***
My Test
[Documentation] Example test.
Log ${MESSAGE}
My Keyword ${CURDIR}
Another Test
Should Be Equal ${MESSAGE} Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
.. code:: robotframework
# Both space and pipe separated formats are supported.
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
.. code:: python
# This code block is ignored.
def example():
print('Hello, world!')
```
Robot Framework supports reStructuredText files using .robot.rst, .rst and .rest extensions. To avoid parsing unrelated reStructuredText files, only files with the .robot.rst extension are parsed by default when executing a directory. Parsing files with other extensions [can be enabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) by using either \--parseinclude or \--extension option.
When Robot Framework parses reStructuredText files, errors below level `SEVERE` are ignored to avoid noise about possible non-standard directives and other such markup. This may hide also real errors, but they can be seen when processing files using reStructuredText tooling normally.
Note
Parsing .robot.rst files automatically is new in Robot Framework 6.1.
#### [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-265)
Robot Framework supports data also in the [JSON](https://json.org/) format. This format is designed more for tool developers than for regular Robot Framework users and it is not meant to be edited manually. Its most important use cases are:
- Transferring data between processes and machines. A suite can be converted to JSON in one machine and recreated somewhere else.
- Saving a suite, possibly a nested suite, constructed from normal Robot Framework data into a single JSON file that is faster to parse.
- Alternative data format for external tools generating tests or tasks.
Note
The JSON data support is new in Robot Framework 6.1 and it can be enhanced in future Robot Framework versions. If you have an enhancement idea or believe you have encountered a bug, please submit an [issue](https://issues.robotframework.org/) or start a discussion thread on the `#devel` channel on our [Slack](http://slack.robotframework.org/).
##### Converting suite to JSON
A suite structure can be serialized into JSON by using the [TestSuite.to\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.to_json) method. When used without arguments, it returns JSON data as a string, but it also accepts a path or an open file where to write JSON data along with configuration options related to JSON formatting:
```
from robot.running import TestSuite
# Create suite based on data on the file system.
suite = TestSuite.from_file_system('/path/to/data')
# Get JSON data as a string.
data = suite.to_json()
# Save JSON data to a file with custom indentation.
suite.to_json('data.rbt', indent=2)
```
If you would rather work with Python data and then convert that to JSON or some other format yourself, you can use [TestSuite.to\_dict](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.to_dict) instead.
##### Creating suite from JSON
A suite can be constructed from JSON data using the [TestSuite.from\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_json) method. It works both with JSON strings and paths to JSON files:
```
from robot.running import TestSuite
# Create suite from JSON data in a file.
suite = TestSuite.from_json('data.rbt')
# Create suite from a JSON string.
suite = TestSuite.from_json('{"name": "Suite", "tests": [{"name": "Test"}]}')
# Execute suite. Notice that log and report needs to be created separately.
suite.run(output='example.xml')
```
If you have data as a Python dictionary, you can use [TestSuite.from\_dict](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_dict) instead. Regardless of how a suite is recreated, it exists only in memory and original data files on the file system are not recreated.
As the above example demonstrates, the created suite can be executed using the [TestSuite.run](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.run) method. It may, however, be easier to execute a JSON file directly as explained in the following section.
##### Executing JSON files
When executing tests or tasks using the `robot` command, JSON files with the custom .rbt extension are parsed automatically. This includes running individual JSON files like `robot tests.rbt` and running directories containing .rbt files. If you would rather use the standard .json extension, you need to [configure which files are parsed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse).
##### Adjusting suite source
Suite source in the data got from `TestSuite.to_json` and `TestSuite.to_dict` is in absolute format. If a suite is recreated later on a different machine, the source may thus not match the directory structure on that machine. To avoid that, it is possible to use the [TestSuite.adjust\_source](https://robot-framework.readthedocs.io/en/master/autodoc/robot.model.html#robot.model.testsuite.TestSuite.adjust_source) method to make the suite source relative before getting the data and add a correct root directory after the suite is recreated:
```
from robot.running import TestSuite
# Create a suite, adjust source and convert to JSON.
suite = TestSuite.from_file_system('/path/to/data')
suite.adjust_source(relative_to='/path/to')
suite.to_json('data.rbt')
# Recreate suite elsewhere and adjust source accordingly.
suite = TestSuite.from_json('data.rbt')
suite.adjust_source(root='/new/path/to')
```
##### JSON structure
Imports, variables and keywords created in suite files are included in the generated JSON along with tests and tasks. The exact JSON structure is documented in the running.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
### [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-266)
#### [Ignored data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-267)
When Robot Framework parses the test data files, it ignores:
- All data before the first [test data section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections).
- Data in the [Comments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections) section.
- All empty rows.
- All empty cells at the end of rows when using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format).
- All single backslashes (\\) when not used for [escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping).
- All characters following the hash character (`#`), when it is the first character of a cell. This means that hash marks can be used to enter comments in the 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, place it to the documentation or other metadata of test cases or suites, or log it with the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Log or Comment.
#### [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-268)
The escape character in Robot Framework test data is the backslash (\\) and additionally [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) `${EMPTY}` and `${SPACE}` can often be used for escaping. Different escaping mechanisms are discussed in the sections below.
##### Escaping special characters
The backslash character can be used to escape special characters so that their literal values are used.
| Character | Meaning | Examples |
|---|---|---|
| `\$` | Dollar sign, never starts a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable). | `\${notvar}` |
| `\@` | At sign, never starts a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable). | `\@{notvar}` |
| `\&` | Ampersand, never starts a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable). | `\&{notvar}` |
| `\%` | Percent sign, never starts an [environment variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variable). | `\%{notvar}` |
| `\#` | Hash sign, never starts a [comment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#comment). | `\# not comment` |
| `\=` | Equal sign, never part of [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). | `not\=named` |
| `\|` | Pipe character, not a separator in the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format). | `ls -1 *.txt \| wc -l` |
| `\\` | Backslash character, never escapes anything. | `c:\\temp, \\${var}` |
##### Forming escape sequences
The backslash character also allows creating special escape sequences that are recognized as characters that would otherwise be hard or impossible to create in the test data.
| Sequence | Meaning | Examples |
|---|---|---|
| `\n` | Newline character. | `first line\n2nd line` |
| `\r` | Carriage return character | `text\rmore text` |
| `\t` | Tab character. | `text\tmore text` |
| `\xhh` | Character with hex value `hh`. | `null byte: \x00, ä: \xE4` |
| `\uhhhh` | Character with hex value `hhhh`. | `snowman: \u2603` |
| `\Uhhhhhhhh` | Character with hex value `hhhhhhhh`. | `love hotel: \U0001f3e9` |
Note
All strings created in the test data, including characters like `\x02`, are Unicode and must be explicitly converted to byte strings if needed. This can be done, for example, using Convert To Bytes or Encode String To Bytes keywords in [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) and [String](https://robotframework.org/robotframework/latest/libraries/String.html) libraries, respectively, or with something like `value.encode('UTF-8')` in Python code.
Note
If invalid hexadecimal values are used with `\x`, `\u` or `\U` escapes, the end result is the original value without the backslash character. For example, `\xAX` (not hex) and `\U00110000` (too large value) result with `xAX` and `U00110000`, respectively. This behavior may change in the future, though.
Note
[Built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${\n}` can be used if operating system dependent line terminator is needed (`\r\n` on Windows and `\n` elsewhere).
##### Handling empty values
When using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format), the number of spaces used as a separator can vary and thus empty values cannot be recognized unless they are escaped. Empty cells can be escaped either with the backslash character or with [built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${EMPTY}`. The latter is typically recommended as it is easier to understand.
```
*** Test Cases ***
Using backslash
Do Something first arg \
Do Something \ second arg
Using ${EMPTY}
Do Something first arg ${EMPTY}
Do Something ${EMPTY} second arg
```
When using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format), empty values need to be escaped only when they are at the end of the row:
```
| *** Test Cases *** | | | |
| Using backslash | Do Something | first arg | \ |
| | Do Something | | second arg |
| | | | |
| Using ${EMPTY} | Do Something | first arg | ${EMPTY} |
| | Do Something | | second arg |
```
##### Handling spaces
Spaces, especially consecutive spaces, as part of arguments for keywords or needed otherwise are problematic for two reasons:
- Two or more consecutive spaces is considered a separator when using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format).
- Leading and trailing spaces are ignored when using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format).
In these cases spaces need to be escaped. Similarly as when escaping empty values, it is possible to do that either by using the backslash character or by using the [built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${SPACE}`.
| Escaping with backslash | Escaping with `${SPACE}` | Notes |
|---|---|---|
| \\ leading space | `${SPACE}leading space` | |
| trailing space \\ | `trailing space${SPACE}` | Backslash must be after the space. |
| \\ \\ | `${SPACE}` | Backslash needed on both sides. |
| consecutive \\ \\ spaces | `consecutive${SPACE * 3}spaces` | Using [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax). |
As the above examples show, using the `${SPACE}` variable often makes the test data easier to understand. It is especially handy in combination with the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) when more than one space is needed.
#### [Dividing data to several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-269)
If there is more data than readily fits a row, it is possible to split it and start continuing rows with ellipsis (`...`). Ellipses can be indented to match the indentation of the starting row and they must always be followed by the normal test data separator.
In most places split lines have exact same semantics as lines that are not split. Exceptions to this rule are [suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation), [test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation) and [keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation) documentation as well [suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata). With them split values are automatically [joined together with the newline character](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines) to ease creating multiline values.
The `...` syntax allows also splitting variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section). When long scalar variables (e.g. `${STRING}`) are split to multiple rows, the final value is got by concatenating the rows together. The separator is a space by default, but that can be changed by starting the value with `SEPARATOR=<sep>`.
Splitting lines is illustrated in the following two examples containing exactly same data without and with splitting.
```
*** Settings ***
Documentation Here we have documentation for this suite.\nDocumentation is often quite long.\n\nIt can also contain multiple paragraphs.
Test Tags test tag 1 test tag 2 test tag 3 test tag 4 test tag 5
*** Variables ***
${STRING} This is a long string. It has multiple sentences. It does not have newlines.
${MULTILINE} This is a long multiline string.\nThis is the second line.\nThis is the third and the last line.
@{LIST} this list is quite long and items in it can also be long
&{DICT} first=This value is pretty long. second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[Tags] you probably do not have this many tags in real life
Do X first argument second argument third argument fourth argument fifth argument sixth argument
${var} = Get X first argument passed to this keyword is pretty long second argument passed to this keyword is long too
```
```
*** Settings ***
Documentation Here we have documentation for this suite.
... Documentation is often quite long.
...
... It can also contain multiple paragraphs.
Test Tags test tag 1 test tag 2 test tag 3
... test tag 4 test tag 5
*** Variables ***
${STRING} This is a long string.
... It has multiple sentences.
... It does not have newlines.
${MULTILINE} SEPARATOR=\n
... This is a long multiline string.
... This is the second line.
... This is the third and the last line.
@{LIST} this list is quite long and
... items in it can also be long
&{DICT} first=This value is pretty long.
... second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[Tags] you probably do not have this many
... tags in real life
Do X first argument second argument third argument
... fourth argument fifth argument sixth argument
${var} = Get X
... first argument passed to this keyword is pretty long
... second argument passed to this keyword is long too
```
### [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-270)
Robot Framework localization efforts were started in Robot Framework 6.0 that allowed translation of [section headers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections), [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings), [Given/When/Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages) used in Behavior Driven Development (BDD), and [true and false strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) used in automatic Boolean argument conversion. The plan is to extend localization support in the future, for example, to log and report and possibly also to control structures.
This section explains how to [activate languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions), what [built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages) are supported, how to create [custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files) and how new translations can be [contributed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations).
#### [Enabling languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-271)
##### Using command line option
The main mechanism to activate languages is specifying them from the command line using the \--language option. When enabling [built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages), it is possible to use either the language name like `Finnish` or the language code like `fi`. Both names and codes are case and space insensitive and also the hyphen (`-`) is ignored. To enable multiple languages, the \--language option needs to be used multiple times:
```
robot --language Finnish testit.robot
robot --language pt --language ptbr testes.robot
```
The same \--language option is also used when activating [custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files). With them the value can be either a path to the file or, if the file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), the module name:
```
robot --language Custom.py tests.robot
robot --language MyLang tests.robot
```
For backwards compatibility reasons, and to support partial translations, English is always activated automatically. Future versions may allow disabling it.
##### Pre-file configuration
It is also possible to enable languages directly in data files by having a line `Language: <value>` (case-insensitive) before any of the section headers. The value after the colon is interpreted the same way as with the \--language option:
```
Language: Finnish
*** Asetukset ***
Dokumentaatio Example using Finnish.
```
If there is a need to enable multiple languages, the `Language:` line can be repeated. These configuration lines cannot be in comments so something like `# Language: Finnish` has no effect.
Due to technical limitations, the per-file language configuration affects also parsing subsequent files as well as the whole execution. This behavior is likely to change in the future and *should not* be relied upon. If you use per-file configuration, use it with all files or enable languages globally with the \--language option.
#### [Built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-272)
The following languages are supported out-of-the-box. Click the language name to see the actual translations:
- [Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
All these translations have been provided by the awesome Robot Framework community. If a language you are interested in is not included, you can consider [contributing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations) it\!
#### [Custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-273)
If a language you would need is not available as a built-in language, or you want to create a totally custom language for some specific need, you can easily create a custom language file. Language files are Python files that contain one or more language definitions that are all loaded when the language file is taken into use. Language definitions are created by extending the `robot.api.Language` base class and overriding class attributes as needed:
```
from robot.api import Language
class Example(Language):
test_cases_header = 'Validations'
tags_setting = 'Labels'
given_prefixes = ['Assuming']
true_strings = ['OK', '\N{THUMBS UP SIGN}']
```
Assuming the above code would be in file example.py, a path to that file or just the module name `example` could be used when the language file is [activated](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages).
The above example adds only some of the possible translations. That is fine because English is automatically enabled anyway. Most values must be specified as strings, but BDD prefixes and true/false strings allow more than one value and must be given as lists. For more examples, see Robot Framework's internal [languages](https://github.com/robotframework/robotframework/blob/master/src/robot/conf/languages.py) module that contains the `Language` class as well as all built-in language definitions.
#### [Contributing translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-274)
If you want to add translation for a new language or enhance existing, head to [Crowdin](https://robotframework.crowdin.com/) that we use for collaboration. For more details, see the separate [Localization](https://github.com/MarketSquare/localization) project, and for questions and free discussion join the `#localization` channel on our [Slack](http://slack.robotframework.org/).
### [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-275)
Robot Framework syntax creates a simple programming language, and similarly as with other languages, it is important to think about the coding style. Robot Framework syntax is pretty flexible on purpose, but there are some generally recommended conventions:
- Four space indentation.
- Four space separation between keywords and arguments, settings and their values, etc... In some cases it makes sense to use more than four spaces. For example when aligning values in the Settings or Variables section or in [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
- Global [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) using capital letters like `${EXAMPLE}` and local variables using lower-case letters like `${example}`.
- Consistency within a single file and preferably within the whole project.
One case where there currently is no strong convention is keyword capitalization. Robot Framework itself typically uses title case like Example Keyword in documentation and elsewhere, and this style is often used in Robot Framework data as well. It does not work too well with longer, sentence-like keywords such as Log into system as an admin, though.
Teams and organizations using Robot Framework should have their own coding standards. The community developed [Robot Framework Style Guide](https://docs.robotframework.org/docs/style_guide) is an excellent starting point that can be amended as needed. It is also possible to enforce these conventions by using the [Robocop](https://robocop.readthedocs.io/) linter and the [Robotidy](https://robotidy.readthedocs.io/) code formatter.
## [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-250)
This section describes the overall test case syntax. Organizing test cases into [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) using [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories) is discussed in the next section.
When using Robot Framework for other automation purposes than test automation, it is recommended to create *tasks* instead of tests. The task syntax is for most parts identical to the test syntax, and the differences are explained in the [Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) section.
- [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax)
- [Settings in the Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-test-case-section)
- [Test case related settings in the Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-related-settings-in-the-setting-section)
- [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments)
- [Positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments)
- [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values)
- [Variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments)
- [Named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments)
- [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments)
- [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments)
- [Arguments embedded to keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arguments-embedded-to-keyword-names)
- [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures)
- [When test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-test-case-fails)
- [Error messages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#error-messages)
- [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation)
- [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases)
- [Deprecation of Force Tags and Default Tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecation-of-force-tags-and-default-tags)
- [Reserved tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags)
- [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown)
- [2\.2.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates)
- [Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage)
- [Templates with multiple iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-multiple-iterations)
- [Templates with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-embedded-arguments)
- [Templates with `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-for-loops)
- [Templates with `IF/ELSE` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-if-else-structures)
- [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-case-styles)
- [Keyword-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-driven-style)
- [Data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style)
- [Behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style)
### [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-276)
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-277)
Test cases are constructed in test case sections from the available keywords. Keywords can be imported from [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) or [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files), or created in the [keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) of the test case file itself.
The first column in the test case section 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 section. It is an error to have something between the section headers and the first test.
The second column normally has keyword names. An exception to this rule is [setting variables from keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-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.
```
*** Test Cases ***
Valid Login
Open Login Page
Input Username 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
```
Note
Although test case names can contain any character, using `?` and especially `*` is not generally recommended because they are considered to be [wildcards](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#wildcards) when [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases). For example, trying to run only a test with name Example \* like `--test 'Example *'` will actually run any test starting with Example.
#### [Settings in the Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-278)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation).
\[Setup\], \[Teardown\]
Specify [test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown).
\[Tags\]
Used for [tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases).
\[Template\]
Specifies the [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) to use. The test itself will contain only data to use as arguments to that keyword.
\[Timeout\]
Used for setting a [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). [Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) are discussed in their own section.
Note
Setting names are case-insensitive, but the format used above is recommended. Settings used to be also space-insensitive, but that was deprecated in Robot Framework 3.1 and trying to use something like `[T a g s]` causes an error in Robot Framework 3.2. Possible spaces between brackets and the name (e.g. `[ Tags ]`) are still allowed.
Example test case with settings:
```
*** Test Cases ***
Test With Settings
[Documentation] Another dummy test
[Tags] dummy owner-johndoe
Log Hello, world!
```
#### [Test case related settings in the Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-279)
The Setting section can have the following test case related settings. These settings are mainly default values for the test case specific settings listed earlier.
Test Setup, Test Teardown
The default values for [test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown).
Test Tags
[Tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) all tests in the suite will get in addition to their possible own tags.
Test Template
The default [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) to use.
Test Timeout
The default value for [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). [Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) are discussed in their own section.
### [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-280)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool, but the same information is available on documentation generated by generic documentation tools such as pydoc.
#### [Positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-281)
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 . 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](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html), takes no arguments.
```
*** Test Cases ***
Example
Create Directory ${TEMPDIR}/stuff
Copy File ${CURDIR}/file.txt ${TEMPDIR}/stuff
No Operation
```
#### [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-282)
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 . 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 . Trying to use it without any arguments or more than three arguments would not work.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-283)
It is also possible that a keyword accepts any number of arguments. These so called *varargs* can be combined with mandatory arguments and arguments with default values, but they are always given after them. In the documentation they have an asterisk before the argument name like `*varargs`.
For example, Remove Files and Join Paths keywords from the [OperatingSystem](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) library 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.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-284)
The named argument syntax makes using arguments with [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) more flexible, and allows explicitly labeling what a certain argument value means. Technically named arguments work exactly like [keyword arguments](http://docs.python.org/tutorial/controlflow.html#keyword-arguments) in Python.
##### Basic syntax
It is possible to name an argument given to a keyword by prefixing the value with the name of the argument like `arg=value`. This is especially useful when multiple arguments have default values, as it is possible to name only some the arguments and let others use their defaults. For example, if a keyword accepts arguments `arg1=a, arg2=b, arg3=c`, and it is called with one argument `arg3=override`, arguments `arg1` and `arg2` get their default values, but `arg3` gets value `override`. If this sounds complicated, the [named arguments example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-example) below hopefully makes it more clear.
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 neither `Arg=value` nor `ARG=value` works. The latter means that spaces are not allowed before the `=` sign, and possible spaces after it are considered part of the given value.
When the named argument syntax is used with [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords), the argument names must be given without the `${}` decoration. For example, user keyword with arguments `${arg1}=first, ${arg2}=second` must be used like `arg2=override`.
Using normal positional arguments after named arguments like, for example, `| Keyword | arg=value | positional |`, does not work. The relative order of the named arguments does not matter.
##### Named arguments with variables
It is possible to use [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in both named argument names and values. If the value is a single [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable), it is passed to the keyword as-is. This allows using any objects, not only strings, as values also when using the named argument syntax. For example, calling a keyword like `arg=${object}` will pass the variable `${object}` to the keyword without converting it to a string.
If variables are used in named argument names, variables are resolved before matching them against argument names.
The named argument syntax requires the equal sign to be written literally in the keyword call. This means that variable alone can never trigger the named argument syntax, not even if it has a value like `foo=bar`. This is important to remember especially when wrapping keywords into other keywords. If, for example, a keyword takes a [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) like `@{args}` and passes all of them to another keyword using the same `@{args}` syntax, possible `named=arg` syntax used in the calling side is not recognized. This is illustrated by the example below.
```
*** Test Cases ***
Example
Run Program shell=True # This will not come as a named argument to Run Process
*** Keywords ***
Run Program
[Arguments] @{args}
Run Process program.py @{args} # Named arguments are not recognized from inside @{args}
```
If keyword needs to accept and pass forward any named arguments, it must be changed to accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments). See [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) for a wrapper keyword version that can pass both positional and named arguments forward.
##### Escaping named arguments syntax
The named argument syntax is used only when the part of the argument before the equal sign matches one of the keyword's arguments. It is possible that there is a positional argument with a literal value like `foo=quux`, and also an unrelated argument with name `foo`. In this case the argument `foo` either incorrectly gets the value `quux` or, more likely, there is a syntax error.
In these rare cases where there are accidental matches, it is possible to use the backslash character to [escape](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) the syntax like `foo\=quux`. Now the argument will get a literal value `foo=quux`. Note that escaping is not needed if there are no arguments with name `foo`, but because it makes the situation more explicit, it may nevertheless be a good idea.
##### Where named arguments are supported
As already explained, the named argument syntax works with keywords. In addition to that, it also works when [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries).
Naming arguments is supported by [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) and by most [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries). The only exceptions are Python keywords explicitly using [positional-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments).
##### Named arguments example
The following example demonstrates using the named arguments syntax with library keywords, user keywords, and when importing the [Telnet](https://robotframework.org/robotframework/latest/libraries/Telnet.html) test library.
```
*** Settings ***
Library Telnet prompt=$ default_log_level=DEBUG
*** Test Cases ***
Example
Open connection 10.0.0.42 port=${PORT} alias=example
List files options=-lh
List files path=/tmp options=-l
*** Keywords ***
List files
[Arguments] ${path}=. ${options}=
Execute command ls ${options} ${path}
```
#### [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-285)
Robot Framework supports *free named arguments*, often also called *free keyword arguments* or *kwargs*, similarly as [Python supports \*\*kwargs](http://docs.python.org/tutorial/controlflow.html#keyword-arguments). What this means is that a keyword can receive all arguments that use the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) (`name=value`) and do not match any arguments specified in the signature of the keyword.
Free named arguments are supported by same keyword types than [normal named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#where-named-arguments-are-supported). How keywords specify that they accept free named arguments depends on the keyword type. For example, [Python based keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-keyword-arguments-kwargs) simply use `**kwargs` and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords) use `&{kwargs}`.
Free named arguments support variables similarly as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-with-variables). In practice that means that variables can be used both in names and values, but the escape sign must always be visible literally. For example, both `foo=${bar}` and `${foo}=${bar}` are valid, as long as the variables that are used exist. An extra limitation is that free argument names must always be strings.
##### Examples
As the first example of using free named arguments, let's take a look at Run Process keyword in the [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library. It has a signature `command, *arguments, **configuration`, which means that it takes the command to execute (`command`), its arguments as [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) (`*arguments`) and finally optional configuration parameters as free named arguments (`**configuration`). The example below also shows that variables work with free keyword arguments exactly like when [using the named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-with-variables).
```
*** Test Cases ***
Free Named Arguments
Run Process program.py arg1 arg2 cwd=/home/user
Run Process program.py argument shell=True env=${ENVIRON}
```
See [Free keyword arguments (\*\*kwargs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-keyword-arguments-kwargs) section under [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) for more information about using the free named arguments syntax in your custom test libraries.
As the second example, let's create a wrapper [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) for running the `program.py` in the above example. The wrapper keyword Run Program accepts all positional and named arguments and passes them forward to Run Process along with the name of the command to execute.
```
*** Test Cases ***
Free Named Arguments
Run Program arg1 arg2 cwd=/home/user
Run Program argument shell=True env=${ENVIRON}
*** Keywords ***
Run Program
[Arguments] @{args} &{config}
Run Process program.py @{args} &{config}
```
#### [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-286)
Keywords can accept arguments that must always be named using the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). If, for example, a keyword would accept a single named-only argument `example`, it would always need to be used like `example=value` and using just `value` would not work. This syntax is inspired by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102) syntax.
For most parts named-only arguments work the same way as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments). The main difference is that libraries implemented with Python 2 using the [static library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords) [do not support this syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-only-arguments).
As an example of using the [named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords), here is a variation of the Run Program in the above [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) that only supports configuring `shell`:
```
*** Test Cases ***
Named-only Arguments
Run Program arg1 arg2 # 'shell' is False (default)
Run Program argument shell=True # 'shell' is True
*** Keywords ***
Run Program
[Arguments] @{args} ${shell}=False
Run Process program.py @{args} shell=${shell}
```
#### [Arguments embedded to keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-287)
A totally different approach to specify arguments is embedding them into keyword names. This syntax is supported by both [test library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names) and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
### [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-288)
#### [When test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-289)
A test case fails if any of the keyword it uses fails. Normally this means that execution of that test case is stopped, possible [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) is executed, and then execution continues from the next test case. It is also possible to use special [continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) if stopping test execution is not desired.
#### [Error messages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-290)
The error message assigned to a failed test case is got directly from the failed keyword. Often the error message is created by the keyword itself, but some keywords allow configuring them.
In some circumstances, for example when continuable failures are used, a test case can fail multiple times. In that case the final error message is got by combining the individual errors. Very long error messages are [automatically cut from the middle](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports) to keep [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) easier to read, but full error messages are always visible in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as messages of the failed keywords.
By default error messages are normal text, but they can [contain HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#html-in-error-messages). This is enabled by starting the error message with marker string `*HTML*`. This marker will be removed from the final error message shown in reports and logs. Using HTML in a custom message is shown in the second example below.
```
*** Test Cases ***
Normal Error
Fail This is a rather boring example...
HTML Error
${number} = Get Number
Should Be Equal ${number} 42 *HTML* Number is not my <b>MAGIC</b> number.
```
### [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-291)
The test case name comes directly from the Test Case section: 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatic-variables) `${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.
Starting from Robot Framework 3.2, possible [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in the test case name are resolved so that the final name will contain the variable value. If the variable does not exist, its name is left unchanged.
```
*** Variables ***
${MAX AMOUNT} ${5000000}
*** Test Cases ***
Amount cannot be larger than ${MAX AMOUNT}
# ...
```
The \[Documentation\] setting allows setting free form documentation for a test case. That text is shown in the command line output and in the resulting logs and reports. If documentation gets long, it can be [split into multiple rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows). It is possible to use simple [HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) and [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can be used to make the documentation dynamic. Possible non-existing variables are left unchanged.
```
*** Test Cases ***
Simple
[Documentation] Simple and short documentation.
No Operation
Multiple lines
[Documentation] First row of the documentation.
...
... Documentation continues here. These rows form
... a paragraph when shown in HTML outputs.
No Operation
Formatting
[Documentation]
... This list has:
... - *bold*
... - _italics_
... - 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases).
### [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-292)
Using tags in Robot Framework is a simple, yet powerful mechanism for classifying test cases and also [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). Tags are free text and Robot Framework itself has no special meaning for them except for the [reserved tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) discussed below. Tags can be used at least for the following purposes:
- They are shown in test [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file), [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) and, of course, in the test data, so they provide metadata to test cases.
- [Statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics) about test cases (total, passed, failed and skipped) are automatically collected based on them.
- They can be used to [include and exclude](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) as well as to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) test cases.
There are multiple ways how to specify tags for test cases explained below:
Test Tags setting in the Settings section
All tests in a test case file with this setting always get specified tags. If this setting is used in a [suite initialization file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files), all tests in child suites get these tags.
\[Tags\] setting with each test case
Tests get these tags in addition to tags specified using the Test Tags setting. The \[Tags\] setting also allows removing tags set with Test Tags by using the `-tag` syntax.
\--settag command line option
All tests get tags set with this option in addition to tags they got elsewhere.
Set Tags, Remove Tags, Fail and Pass Execution keywords
These [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords can be used to manipulate tags dynamically during the test execution.
Example:
```
*** Settings ***
Test Tags requirement: 42 smoke
*** Variables ***
${HOST} 10.0.1.42
*** Test Cases ***
No own tags
[Documentation] Test has tags 'requirement: 42' and 'smoke'.
No Operation
Own tags
[Documentation] Test has tags 'requirement: 42', 'smoke' and 'not ready'.
[Tags] not ready
No Operation
Own tags with variable
[Documentation] Test has tags 'requirement: 42', 'smoke' and 'host: 10.0.1.42'.
[Tags] host: ${HOST}
No Operation
Remove common tag
[Documentation] Test has only tag 'requirement: 42'.
[Tags] -smoke
No Operation
Remove common tag using a pattern
[Documentation] Test has only tag 'smoke'.
[Tags] -requirement: *
No Operation
Set Tags and Remove Tags keywords
[Documentation] This test has tags 'smoke', 'example' and 'another'.
Set Tags example another
Remove Tags requirement: *
```
As the example shows, tags can be created using variables, but otherwise they preserve the exact name used in the data. When tags are compared, for example, to collect statistics, to select test to be executed, or to remove duplicates, comparisons are case, space and underscore insensitive.
As demonstrated by the above examples, removing tags using `-tag` syntax supports [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) like `-requirement: *`. Tags starting with a hyphen have no special meaning otherwise than with the \[Tags\] setting. If there is a need to set a tag starting with a hyphen with \[Tags\], it is possible to use the [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) format like `\-tag`.
At the moment the `-tag` syntax can be used for removing tags only with the \[Tags\] setting, but the plan is to support this functionality also with the Test Tags setting in Robot Framework 8.0 ([\#5250](https://github.com/robotframework/robotframework/issues/5250)). Setting tags having a literal value that starts with a hyphen in Test Tags was deprecated in Robot Framework 7.2 ([\#5252](https://github.com/robotframework/robotframework/issues/5252)). The escaped format like `\-tag` can be used if tags with such values are needed.
Note
The Test Tags setting is new in Robot Framework 6.0. Earlier versions support Force Tags and Default Tags settings discussed in the next section.
Note
The `-tag` syntax for removing tags using the \[Tags\] setting is new in Robot Framework 7.0.
#### [Deprecation of Force Tags and Default Tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-293)
Prior to Robot Framework 6.0, tags could be specified to tests in the Setting section using two different settings:
Force Tags
All tests unconditionally get these tags. This is exactly the same as Test Tags nowadays.
Default Tags
All tests get these tags by default. If a test has \[Tags\], it will not get these tags.
Both of these settings still work, but they are considered deprecated. A visible deprecation warning will be added in the future, most likely in Robot Framework 8.0, and eventually these settings will be removed. Tools like [Tidy](https://robotidy.readthedocs.io/) can be used to ease transition.
Updating Force Tags requires only renaming it to Test Tags. The Default Tags setting will be removed altogether, but the `-tag` functionality introduced in Robot Framework 7.0 provides same underlying functionality. The following examples demonstrate the needed changes.
Old syntax:
```
*** Settings ***
Force Tags all
Default Tags default
*** Test Cases ***
Common only
[Documentation] Test has tags 'all' and 'default'.
No Operation
No default
[Documentation] Test has only tag 'all'.
[Tags]
No Operation
Own and no default
[Documentation] Test has tags 'all' and 'own'.
[Tags] own
No Operation
```
New syntax:
```
*** Settings ***
Test Tags all default
*** Test Cases ***
Common only
[Documentation] Test has tags 'all' and 'default'.
No Operation
No default
[Documentation] Test has only tag 'all'.
[Tags] -default
No Operation
Own and no default
[Documentation] Test has tags 'all' and 'own'.
[Tags] own -default
No Operation
```
#### [Reserved tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-294)
Users are generally free to use whatever tags that work in their context. There are, however, certain tags that have a predefined meaning for Robot Framework itself, and using them for other purposes can have unexpected results. All special tags Robot Framework has and will have in the future have the `robot:` prefix. To avoid problems, users should thus not use any tag with this prefixes unless actually activating the special functionality. The current reserved tags are listed below, but more such tags are likely to be added in the future.
`robot:continue-on-failure` and `robot:recursive-continue-on-failure`
Used for [enabling the continue-on-failure mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-continue-on-failure-using-tags).
`robot:stop-on-failure` and `robot:recursive-stop-on-failure`
Used for [disabling the continue-on-failure mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags).
`robot:exit-on-failure`
Stop the whole execution if a [test with this tag fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-using-robot-exit-on-failure-tag).
`robot:skip-on-failure`
Mark test to be [skipped if it fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-skipping-failed-tests).
`robot:skip`
Mark test to be [unconditionally skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipping-before-execution).
`robot:exclude`
Mark test to be [unconditionally excluded](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names).
`robot:private`
Mark keyword to be [private](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#private-user-keywords).
`robot:no-dry-run`
Mark keyword not to be executed in the [dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run) mode.
`robot:exit`
Added to tests automatically when [execution is stopped gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully).
`robot:flatten`
Enable [flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keyword-during-execution-time).
As of RobotFramework 4.1, reserved tags are suppressed by default in [tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics). They will be shown when they are explicitly included via the `--tagstatinclude robot:*` command line option.
### [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-295)
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.
A setup and a 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) for that purpose. An alternative solution is executing multiple keywords using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keywords.
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. In addition, all the keywords in the teardown are also executed even if one of them fails. This [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section. Individual test cases can also have their own setup or teardown. They are defined with the \[Setup\] or \[Teardown\] settings in the test case section 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. It is also possible to use value `NONE` to indicate that a test has no setup/teardown.
```
*** Settings ***
Test Setup Open Application App A
Test Teardown Close Application
*** Test Cases ***
Default values
[Documentation] Setup and teardown from setting section
Do Something
Overridden setup
[Documentation] Own setup, teardown from setting section
[Setup] Open Application App B
Do Something
No teardown
[Documentation] Default setup, no teardown at all
Do Something
[Teardown]
No teardown 2
[Documentation] Setup and teardown can be disabled also with special value NONE
Do Something
[Teardown] NONE
Using variables
[Documentation] Setup and teardown specified using variables
[Setup] ${SETUP}
Do Something
[Teardown] ${TEARDOWN}
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). 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.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-296)
Test templates convert normal [keyword-driven](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-driven-style) test cases into [data-driven](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) tests. Whereas the body of a keyword-driven test case is constructed from keywords and their possible arguments, test cases with template contain only the arguments for the template keyword. Instead of repeating the same keyword multiple times per test and/or with all tests in a file, it is possible to use it only per test or just once per file.
Template keywords can accept both normal positional and named arguments, as well as arguments embedded to the keyword name. Unlike with other settings, it is not possible to define a template using a variable.
#### [Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-297)
How a keyword accepting normal positional arguments can be used as a template is illustrated by the following example test cases. These two tests are functionally fully identical.
```
*** Test Cases ***
Normal test case
Example keyword first argument second argument
Templated test case
[Template] Example keyword
first argument second argument
```
As the example 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 section, 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 section, and an empty value for \[Template\] means that the test has no template even when Test Template is used. It is also possible to use value `NONE` to indicate that a test has no template.
Using keywords with [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) or accepting [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments), as well as using [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) and [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments), work with templates exactly like they work otherwise. Using [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in arguments is also supported normally.
#### [Templates with multiple iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-298)
If a templated test case has multiple data rows in its body, the template is applied for all the rows one by one. This means that the same keyword is executed multiple times, once with data on each row.
```
*** Settings ***
Test Template Example keyword
*** Test Cases ***
Templated test case
first round 1 first round 2
second round 1 second round 2
third round 1 third round 2
```
Templated tests are special so that all iterations are executed even if one or more of them is failed or skipped. The aggregated result of a templated test with multiple iterations is:
- FAIL if any of the iterations failed.
- PASS if there were no failures and at least one iteration passed.
- SKIP if all iterations were skipped.
Note
It is possible to use the [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) mode also with normal tests, but with the templated tests the mode is on automatically. If needed, the mode can also be [disabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags) with templates by using the `robot:stop-on-failure` tag.
Note
Running all iterations if one or more is skipped is new in Robot Framework 7.2. With earlier versions the execution stopped for the first skipped iteration and the test got the SKIP status regardless of the status of the earlier iterations.
#### [Templates with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-299)
Templates support a variation of the [embedded argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-argument-syntax). With templates this syntax works so that if the template keyword has variables in its name, they are considered placeholders for arguments and replaced with the actual arguments used with the template. The resulting keyword is then used without positional arguments. This is best illustrated with an example:
```
*** Test Cases ***
Normal test case with embedded arguments
The result of 1 + 1 should be 2
The result of 1 + 2 should be 3
Template with embedded arguments
[Template] The result of ${calculation} should be ${expected}
1 + 1 2
1 + 2 3
*** Keywords ***
The result of ${calculation} should be ${expected}
${result} = Calculate ${calculation}
Should Be Equal ${result} ${expected}
```
When embedded arguments are used with templates, the number of arguments in the template keyword name must match the number of arguments it is used with. The argument names do not need to match the arguments of the original keyword, though, and it is also possible to use different arguments altogether:
```
*** Test Cases ***
Different argument names
[Template] The result of ${foo} should be ${bar}
1 + 1 2
1 + 2 3
Only some arguments
[Template] The result of ${calculation} should be 3
1 + 2
4 - 1
New arguments
[Template] The ${meaning} of ${life} should be 42
result 21 * 2
```
The main benefit of using embedded arguments with templates is that argument names are specified explicitly. When using normal arguments, the same effect can be achieved by naming the columns that contain arguments. This is illustrated by the [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) example in the next section.
#### [Templates with `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-300)
If templates are used with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
Template with FOR loop
[Template] Example keyword
FOR ${item} IN @{ITEMS}
${item} 2nd arg
END
FOR ${index} IN RANGE 42
1st arg ${index}
END
```
#### [Templates with `IF/ELSE` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-301)
[IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) can be also used together with templates. This can be useful, for example, when used together with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) to filter executed arguments.
```
*** Test Cases ***
Template with FOR and IF
[Template] Example keyword
FOR ${item} IN @{ITEMS}
IF ${item} < 5
${item} 2nd arg
END
END
```
### [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-302)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-303)
Workflow tests, such as the Valid Login test described [earlier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-tests), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-304)
Another style to write test cases is the *data-driven* approach where test cases use only one higher-level keyword, often created as a [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) functionality allows specifying the keyword to use only once.
```
*** Settings ***
Test Template Login with invalid credentials should fail
*** Test Cases *** USERNAME PASSWORD
Invalid User Name invalid ${VALID PASSWORD}
Invalid Password ${VALID USER} invalid
Invalid User Name and Password invalid invalid
Empty User Name ${EMPTY} ${VALID PASSWORD}
Empty Password ${VALID USER} ${EMPTY}
Empty User Name and Password ${EMPTY} ${EMPTY}
```
Tip
Naming columns like in the example above makes tests easier to understand. This is possible because on the header row other cells except the first one [are ignored](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections).
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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}
```
#### [Behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-305)
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](https://en.wikipedia.org/wiki/Acceptance_test-driven_development) (ATDD) or [Specification by Example](http://en.wikipedia.org/wiki/Specification_by_example).
One way to write these requirements/tests is *Given-When-Then* style popularized by [Behavior Driven Development](http://en.wikipedia.org/wiki/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 or But may be used if a step has more than one action.
```
*** Test Cases ***
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/But prefixes
Prefixes Given, When, Then, And and But can be omitted when creating keywords. For example, Given login page is open in the above example is typically implemented without the word Given so that the name is just Login page is open. Omitting prefixes allows using the same keyword with different prefixes. For example, Welcome page should be open could be used as Then welcome page should be open or and welcome page should be open.
Note
These prefixes can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
##### Embedding data to keywords
When writing concrete examples it is useful to be able to pass actual data to keyword implementations. This can be done by [embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
## [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-251)
In addition to test automation, Robot Framework can be used for other automation purposes, including [robotic process automation](https://en.wikipedia.org/wiki/Robotic_process_automation) (RPA). It has always been possible, but Robot Framework 3.1 added official support for automating *tasks*, not only tests. For most parts creating tasks works the same way as [creating tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tests) and the only real difference is in terminology. Tasks can also be organized into [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites) exactly like test cases.
- [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-syntax)
- [2\.3.2 Task related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-settings)
### [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-306)
Tasks are created based on the available keywords exactly like test cases, and the task syntax is in general identical to the [test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax). The main difference is that tasks are created in Task sections instead of Test Case sections:
```
*** Tasks ***
Process invoice
Read information from PDF
Validate information
Submit information to backend system
Validate information is visible in web UI
```
It is an error to have both tests and tasks in same file.
### [2\.3.2 Task related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-307)
Settings that can be used in the task section are exactly the same as in the [test case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-test-case-section). In the [setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-related-settings-in-the-setting-section) it is possible to use Task Setup, Task Teardown, Task Template and Task Timeout instead of their Test variants.
## [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-252)
Robot Framework [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) are created in test case files, which can be organized into directories. These files and directories create a hierarchical test suite structure. Same concepts apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks), but the terminology differs.
- [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files)
- [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories)
- [Suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files)
- [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name)
- [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation)
- [2\.4.5 Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata)
- [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown)
### [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-308)
Robot Framework test cases [are created](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) using test case sections in suite files, also known as 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) is used, where one test case consists of only one high-level keyword.
The following settings in the Setting section can be used to customize the suite:
Name
Used for setting a custom [suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name). The default name is created based on the file or directory name.
Documentation
Used for specifying a [suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation).
Metadata
Used for setting [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) as name-value pairs.
Suite Setup, Suite Teardown
Specify [suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown).
Note
Setting names are case-insensitive, but the format used above is recommended.
### [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-309)
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 in [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) are processed.
- Other files are ignored.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)) and the processing continues.
#### [Suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-310)
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 suite initialization file. An initialization file name must always be of the format \_\_init\_\_.ext, where the extension must be one of the [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) (typically \_\_init\_\_.robot). The name format is borrowed from Python, where files named in this manner denote that a directory is a module.
Starting from Robot Framework 6.1, it is also possible to define a suite initialization file for automatically created suite when starting the test execution by giving multiple [paths](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-executed).
Initialization files have the same structure and syntax as test case files, except that they cannot have test case sections and not all settings are supported. Variables and keywords created or imported in initialization files *are not* available in the lower level suites. If you need to share variables or keywords, you can put them into [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) that can be imported both by initialization and test case files.
The main usage for initialization files is specifying suite related settings similarly as in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), but setting some [test case related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-related-settings-in-the-setting-section) is also possible. How to use different settings in the initialization files is explained below.
Name, Documentation, Metadata, Suite Setup, Suite Teardown
These suite specific settings work the same way in suite initialization files as in suite files.
Test Tags
Specified tags are unconditionally set to all tests in all suite files this directory contains, recursively. New in Robot Framework 6.1. The deprecated Force Tags needs to be used with older versions.
Test Setup, Test Teardown, Test Timeout
Set the default value for test setup/teardown or test timeout to all test cases this directory contains. Can be overridden on lower level. Notice that keywords used as setups and teardowns must be available in test case files where tests using them are. Defining keywords in the initialization file itself is not enough.
Task Setup, Task Teardown, Task Tags, Task Timeout
Aliases for Test Setup, Test Teardown, Test Tags and Test Timeout, respectively, that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks), not tests.
Test Template, Default Tags
Not supported in initialization files.
```
*** Settings ***
Documentation Example suite
Suite Setup Do Something ${MESSAGE}
Test Tags example
Library SomeLibrary
*** Variables ***
${MESSAGE} Hello, world!
*** Keywords ***
Do Something
[Arguments] ${args}
Some Keyword ${arg}
Another Keyword
```
Note
When you run a suite file or directory, possible suite initialization files in higher level directories are not taken into account. If that is not desired, run the appropriate higher level suite directory and use the [\--suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) option to select which child suite inside it is executed.
### [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-311)
The test suite name is constructed from the file or directory name by default. 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.robot becomes Some Tests and My\_test\_directory becomes My test directory.
The file or directory name can contain a prefix to control the [execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.robot and 02\_\_more\_tests.robot create test suites Some Tests and More Tests, respectively, and the former is executed before the latter.
Starting from Robot Framework 6.1, it is also possible to give a custom name to a suite by using the Name setting in the Setting section:
```
*** Settings ***
Name Custom suite name
```
The name of the top-level suite [can be overridden](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) from the command line with the \--name option.
### [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-312)
The documentation for a test suite is set using the Documentation setting in the Settings section. It can be used both in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and in [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files). Suite documentation has exactly the same characteristics regarding to where it is shown and how it can be created as [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). For details about the syntax see the [Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) appendix.
```
*** Settings ***
Documentation An example suite documentation with *some* _formatting_.
... Long documentation can be split into multiple lines.
```
The documentation of the top-level suite [can be overridden](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) from the command line with the \--doc option.
### [2\.4.5 Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-313)
In addition to documentation, suites can also have free metadata. This metadata is defined as name-value pairs in the Settings section using the Metadata setting. It is shown in reports and logs similarly as documentation.
Name of the metadata is the first argument given to the Metadata setting and the remaining arguments specify its value. The value is handled similarly as documentation, which means that it supports [HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) and [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), and that longer values can be [split into multiple rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows).
```
*** Settings ***
Metadata Version 2.0
Metadata Robot Framework http://robotframework.org
Metadata Platform ${PLATFORM}
Metadata Longer Value
... Longer metadata values can be split into multiple
... rows. Also *simple* _formatting_ is supported.
```
The free metadata of the top-level suite [can be set](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata) from the command line with the \--metadata option.
### [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-314)
Not only [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) 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 suite 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 [suite initialization file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files).
Similarly as with test cases, a suite setup and teardown are keywords that may take arguments. They are defined in the Setting section with Suite Setup and Suite Teardown settings, respectively. 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. Note that 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\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-253)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). This section explains how to take test libraries into use and how to use the keywords they provide. [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) is described in a separate section.
- [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries)
- [Using `Library` setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-library-setting)
- [Using `Import Library` keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-import-library-keyword)
- [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import)
- [Using library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-library-name)
- [Using physical path to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-physical-path-to-library)
- [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library)
- [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries)
- [Normal standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#normal-standard-libraries)
- [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library)
- [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries)
### [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-315)
Test libraries are typically imported using the Library setting, but it is also possible to use the Import Library keyword.
#### [Using `Library` setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-316)
Libraries are normally imported in the Settings section using the Library setting with the library name or path as its value. Unlike most of the other data, the library name or path is both case- and space-sensitive. If a library is in a package, the full name including the 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments). Both the library name and arguments can be set using variables.
```
*** Settings ***
Library OperatingSystem
Library path/to/MyLibrary.py
Library my.package.TestLibrary
Library LibraryAcceptingArguments arg1 arg2
Library ${LIBRARY}
```
It is possible to import test libraries in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-317)
Another possibility to take a test library into use is using the keyword Import Library from the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library. This keyword takes the library name or path 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.
```
*** Test Cases ***
Example
Do Something
Import Library MyLibrary arg1 arg2
KW From MyLibrary
```
### [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-318)
Libraries to import can be specified either by using the library name or the path to the library. These approaches work the same way regardless if the library is imported using the Library setting or the Import Library keyword.
#### [Using library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-319)
The most common way to specify a test library to import is using its name. In these cases Robot Framework tries to find the class or module implementing the library from the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). Libraries that are installed somehow ought to be in the module search path automatically, but with other libraries the search path may need to be configured separately.
```
*** Settings ***
Library OperatingSystem
Library CustomLibrary possible arguments
Library librarymodule.LibraryClass
```
The biggest benefit of this approach is that when the module search path has been configured, often using a custom [start-up script](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-320)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files). The main benefit of this approach is that there is no need to configure the module search path.
If the library is a file, the path to it must contain extension, i.e. .py. If a library is implemented as a directory, the path to it must have a trailing forward slash (`/`) if the path is relative. With absolute paths the trailing slash is optional. Following examples demonstrate these different usages.
```
*** Settings ***
Library PythonLibrary.py
Library relative/path/PythonDirLib/ possible arguments
Library ${RESOURCES}/Example.py
```
### [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-321)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names). 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.
- 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 `AS` (case-sensitive) after the library name and then having the new name after that. The specified name is shown in logs and must be used in the test data when using keywords' full name (LibraryName.Keyword Name).
```
*** Settings ***
Library packagename.TestLib AS TestLib
Library ${LIBRARY} AS MyName
```
Possible arguments to the library are placed between the original library name and the `AS` marker. The following example illustrates how the same library can be imported several times with different arguments:
```
*** Settings ***
Library SomeLibrary localhost 1234 AS LocalLib
Library SomeLibrary server.domain 8080 AS RemoteLib
*** Test Cases ***
Example
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 section and when using the Import Library keyword.
Note
Prior to Robot Framework 6.0 the marker to use when giving a custom name to a library was `WITH NAME` instead of `AS`. The old syntax continues to work, but it is considered deprecated and will eventually be removed.
### [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-322)
Some test libraries are distributed with Robot Framework and these libraries are called *standard libraries*. The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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.
#### [Normal standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-323)
The available normal standard libraries are listed below with links to their documentations:
> - [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html)
> - [Collections](https://robotframework.org/robotframework/latest/libraries/Collections.html)
> - [DateTime](https://robotframework.org/robotframework/latest/libraries/DateTime.html)
> - [Dialogs](https://robotframework.org/robotframework/latest/libraries/Dialogs.html)
> - [OperatingSystem](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html)
> - [Process](https://robotframework.org/robotframework/latest/libraries/Process.html)
> - [Screenshot](https://robotframework.org/robotframework/latest/libraries/Screenshot.html)
> - [String](https://robotframework.org/robotframework/latest/libraries/String.html)
> - [Telnet](https://robotframework.org/robotframework/latest/libraries/Telnet.html)
> - [XML](https://robotframework.org/robotframework/latest/libraries/XML.html)
#### [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-324)
In addition to the normal standard libraries listed above, there is also Remote library that 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface) section for more information about this concept.
### [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-325)
Any test library that is not one of the standard libraries is, by definition, *an external library*. The Robot Framework open source community has implemented several generic libraries, such as [SeleniumLibrary](https://github.com/robotframework/SeleniumLibrary) and [SwingLibrary](https://github.com/robotframework/SwingLibrary), which are not packaged with the core framework. A list of publicly available libraries can be found from <http://robotframework.org>.
Generic and custom libraries can obviously also be implemented by teams using Robot Framework. See [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) section for more information about that topic.
Different external libraries can have a totally different mechanism for installing them and taking them into use. Sometimes they may also require some other dependencies to be installed separately. All libraries should have clear installation and usage documentation and they should preferably automate the installation process.
## [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-254)
- [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-1)
- [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables)
- [Scalar variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable-syntax)
- [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable-syntax)
- [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable-syntax)
- [Accessing list and dictionary items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-list-and-dictionary-items)
- [Environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables)
- [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables)
- [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section)
- [Using variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variable-files)
- [Command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables)
- [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords)
- [`VAR` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax)
- [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords)
- [Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion)
- [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables)
- [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables)
- [Operating-system variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#operating-system-variables)
- [Number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#number-variables)
- [Boolean and None/null variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-and-none-null-variables)
- [Space and empty variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-and-empty-variables)
- [Automatic variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatic-variables)
- [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes)
- [Variable priorities](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities)
- [Variable scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-scopes)
- [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-variable-features)
- [Extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax)
- [Extended variable assignment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-assignment)
- [Variables inside variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables-inside-variables)
- [Inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation-1)
### [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-326)
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 and Keyword sections, but also all settings allow variables in their values. A normal keyword name *cannot* be specified with a variable, but the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword can be used to get the same effect.
Robot Framework has its own variables that can be used as [scalars](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) or [dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variables) using syntax `${SCALAR}`, `@{LIST}` and `&{DICT}`, respectively. In addition to this, [environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables) can be used directly with syntax `%{ENV_VAR}`.
Variables are useful, for example, in these cases:
- When values used in multiple places in the data change often. When using variables, you only need to make changes in one place where the variable is defined.
- When creating system-independent and operating-system-independent data. Using variables instead of hard-coded values 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) when tests are started, changing system-specific variables is easy (for example,
```
--variable RESOURCES:/opt/resources
--variable HOST:10.0.0.2:1234
```
). This also facilitates localization testing, which often involves running the same tests with different localized strings.
- When there is a need to have objects other than strings as arguments for keywords. This is not possible without variables, unless keywords themselves support argument conversion.
- When different keywords, even in different test libraries, need to communicate. You can assign a return value from one keyword to a variable and pass it as an argument to another.
- When values in the test data are long or otherwise complicated. For example, using `${URL}` is more convenient than using something like `http://long.domain.name:8080/path/to/service?foo=1&bar=2&zap=42`.
If a non-existent 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) as in `\${NAME}`.
### [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-327)
This section explains how to use variables using the normal scalar variable syntax `${var}`, how to expand lists and dictionaries like `@{var}` and `&{var}`, respectively, and how to use environment variables like `%{var}`. Different ways how to create variables are discussed in the next section.
Robot Framework variables, similarly as keywords, are case-insensitive, and also spaces and underscores are ignored. However, it is recommended to use capital letters with global variables (for example, `${PATH}` or `${TWO WORDS}`) and small letters with local variables that are only available in certain test cases or user keywords (for example, `${my var}`). Much more importantly, though, case should be used consistently.
A variable name, such as `${example}`, consists of the variable identifier (`$`, `@`, `&`, `%`), curly braces (`{`, `}`), and the base name between the braces. When creating variables, there may also be a [variable type definition](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) after the base name like `${example: int}`.
The variable base name can contain any characters. It is, however, highly recommended to use only alphabetic characters, numbers, underscores and spaces. That is a requirement for using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) already now and in the future that may be required with all variables.
#### [Scalar variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-328)
The most common way to use variables in Robot Framework test data is using the scalar variable syntax like `${var}`. When this syntax is used, the variable name is replaced with its value as-is. Most of the time variable values are strings, but variables can contain any object, including numbers, lists, dictionaries, or even custom objects.
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, these two example test cases are equivalent:
```
*** Test Cases ***
Constants
Log Hello
Log Hello, world!!
Variables
Log ${GREET}
Log ${GREET}, ${NAME}!!
```
When a scalar variable is used alone without any text or other variables around it, like in `${GREET}` above, the variable is replaced with its value as-is and the value can be any object. If the variable is not used alone, like `${GREER}, ${NAME}!!` above, its value is first converted into a string and then concatenated with the other data.
Note
Variable values are used as-is without string conversion also when passing arguments to keywords using the [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) syntax like `argname=${var}`.
The example below demonstrates the difference between having a variable in alone or with other content. First, let us assume that we have a variable `${STR}` set to a string and `${OBJ}` set to an instance of the following Python object:
```
class MyObj:
def __str__(self):
return "Hi, terra!"
```
With these two variables set, we then have the following test data:
```
*** Test Cases ***
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, terra!"`
##### Scalar variables containing bytes
Variables containing [bytes](https://docs.python.org/3/library/stdtypes.html#bytes-objects) or [bytearrays](https://docs.python.org/3/library/stdtypes.html#bytearray-objects) are handled slightly differently than other variables containing non-string values:
- If they are used alone, everything works exactly as with other objects and their values are passed to keywords as-is.
- If they are concatenated only with other variables that also contain bytes or bytearrays, the result is bytes instead of a string.
- If they are concatenated with strings or with variables containing other types than bytes or bytearrays, they are converted to strings like other objects, but they have a different string representation than they normally have in Python. With Python the string representation contains surrounding quotes and a `b` prefix like `b'\x00'`, but with Robot Framework quotes and the prefix are omitted, and each byte is mapped to a Unicode code point with the same ordinal. In practice this is same as converting bytes to strings using the Latin-1 encoding. This format has a big benefit that the resulting string can be converted back to bytes, for example, by using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Convert To Bytes or by automatic [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion).
The following examples demonstrates using bytes and bytearrays would work exactly the same way. Variable `${a}` is expected to contain bytes `\x00\x01` and variable `${b}` bytes `a\xe4`.
```
*** Test Cases ***
Bytes alone
[Documentation] Keyword gets bytes '\x00\x01'.
Keyword ${a}
Bytes concatenated with bytes
[Documentation] Keyword gets bytes '\x00\x01a\xe4'.
Keyword ${a}${b}
Bytes concatenated with others
[Documentation] Keyword gets string '=\x00\x01a\xe4='.
Keyword =${a}${b}=
```
Note
Getting bytes when variables containing bytes are concatenated is new in Robot Framework 7.2. With earlier versions the result was a string.
Note
All bytes being mapped to matching Unicode code points in string representation is new Robot Framework 7.2. With earlier versions, only bytes in the ASCII range were mapped directly to code points and other bytes were represented in an escaped format.
#### [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-329)
When a variable is used as a scalar like `${EXAMPLE}`, its value is be used as-is. If a variable value is a list or list-like, it is also possible to use it as a list variable like `@{EXAMPLE}`. In this case the list is expanded and individual items are passed in as separate arguments.
This is easiest to explain with an example. Assuming that a variable `${USER}` contains a list with two items `robot` and `secret`, the first two of these tests are equivalent:
```
*** Test Cases ***
Constants
Login robot secret
List variable
Login @{USER}
List as scalar
Keyword ${USER}
```
The third test above illustrates that a variable containing a list can be used also as a scalar. In that test the keyword gets the whole list as a single argument.
Starting from Robot Framework 4.0, list expansion can be used in combination with [list item access](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-sequence-items) making these usages possible:
```
*** Test Cases ***
Nested container
${nested} = Evaluate [['a', 'b', 'c'], {'key': ['x', 'y']}]
Log Many @{nested}[0] # Logs 'a', 'b' and 'c'.
Log Many @{nested}[1][key] # Logs 'x' and 'y'.
Slice
${items} = Create List first second third
Log Many @{items}[1:] # Logs 'second' and 'third'.
```
##### Using list variables with other data
It is possible to use list variables with other arguments, including other list variables.
```
*** Test Cases ***
Example
Keyword @{LIST} more args
Keyword ${SCALAR} @{LIST} constant
Keyword @{LIST} @{ANOTHER} @{ONE MORE}
```
##### Using list variables with settings
List variables can be used only with some of the [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-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.
```
*** Settings ***
Library ExampleLibrary @{LIB ARGS} # This works
Library ${LIBRARY} @{LIB ARGS} # This works
Library @{LIBRARY AND ARGS} # This does not work
Suite Setup Some Keyword @{KW ARGS} # This works
Suite Setup ${KEYWORD} @{KW ARGS} # This works
Suite Setup @{KEYWORD AND ARGS} # This does not work
Test Tags @{TAGS} # This works
```
#### [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-330)
As discussed above, a variable containing a list can be used as a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) to pass list items to a keyword as individual arguments. Similarly, a variable containing a Python dictionary or a dictionary-like object can be used as a dictionary variable like `&{EXAMPLE}`. In practice this means that the dictionary is expanded and individual items are passed as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) to the keyword. Assuming that a variable `&{USER}` has a value `{'name': 'robot', 'password': 'secret'}`, the first two test cases below are equivalent:
```
*** Test Cases ***
Constants
Login name=robot password=secret
Dictionary variable
Login &{USER}
Dictionary as scalar
Keyword ${USER}
```
The third test above illustrates that a variable containing a dictionary can be used also as a scalar. In that test the keyword gets the whole dictionary as a single argument.
Starting from Robot Framework 4.0, dictionary expansion can be used in combination with [dictionary item access](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-individual-dictionary-items) making usages like `&{nested}[key]` possible.
##### Using dictionary variables with other data
It is possible to use dictionary variables with other arguments, including other dictionary variables. Because [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) requires positional arguments to be before named argument, dictionaries can only be followed by named arguments or other dictionaries.
```
*** Test Cases ***
Example
Keyword &{DICT} named=arg
Keyword positional @{LIST} &{DICT}
Keyword &{DICT} &{ANOTHER} &{ONE MORE}
```
##### Using dictionary variables with settings
Dictionary variables cannot generally be used with settings. The only exception are imports, setups and teardowns where dictionaries can be used as arguments.
```
*** Settings ***
Library ExampleLibrary &{LIB ARGS}
Suite Setup Some Keyword &{KW ARGS} named=arg
```
#### [Accessing list and dictionary items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-331)
It is possible to access items of subscriptable variables, e.g. lists and dictionaries, using special syntax like `${var}[item]` or `${var}[nested][item]`. Starting from Robot Framework 4.0, it is also possible to use item access together with [list expansion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-expansion) and [dictionary expansion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-expansion) by using syntax `@{var}[item]` and `&{var}[item]`, respectively.
Note
Prior to Robot Framework 3.1, the normal item access syntax was `@{var}[item]` with lists and `&{var}[item]` with dictionaries. Robot Framework 3.1 introduced the generic `${var}[item]` syntax along with some other nice enhancements and the old item access syntax was deprecated in Robot Framework 3.2.
##### Accessing sequence items
It is possible to access a certain item of a variable containing a [sequence](https://docs.python.org/3/glossary.html#term-sequence) (e.g. list, string or bytes) with the syntax `${var}[index]`, where `index` is the index of the selected value. Indices start from zero, negative indices can be used to access items from the end, and trying to access an item with too large an index causes an error. Indices are automatically converted to integers, and it is also possible to use variables as indices.
```
*** Test Cases ***
Positive index
Login ${USER}[0] ${USER}[1]
Title Should Be Welcome ${USER}[0]!
Negative index
Keyword ${SEQUENCE}[-1]
Index defined as variable
Keyword ${SEQUENCE}[${INDEX}]
```
Sequence item access supports also the [same "slice" functionality as Python](https://docs.python.org/glossary.html#term-slice) with syntax like `${var}[1:]`. With this syntax, you do not get a single item, but a *slice* of the original sequence. Same way as with Python, you can specify the start index, the end index, and the step:
```
*** Test Cases ***
Start index
Keyword ${SEQUENCE}[1:]
End index
Keyword ${SEQUENCE}[:4]
Start and end
Keyword ${SEQUENCE}[2:-1]
Step
Keyword ${SEQUENCE}[::2]
Keyword ${SEQUENCE}[1:-1:10]
```
Note
Prior to Robot Framework 3.2, item and slice access was only supported with variables containing lists, tuples, or other objects considered list-like. Nowadays all sequences, including strings and bytes, are supported.
##### Accessing individual dictionary items
It is possible to access a certain value of a dictionary variable with the syntax `${NAME}[key]`, where `key` is the name of the selected value. Keys are considered to be strings, but non-strings keys can be used as variables. Dictionary values accessed in this manner can be used similarly as scalar variables.
If a dictionary is created in Robot Framework data, it is possible to access values also using the attribute access syntax like `${NAME.key}`. See the [Creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) section for more details about this syntax.
```
*** Test Cases ***
Dictionary variable item
Login ${USER}[name] ${USER}[password]
Title Should Be Welcome ${USER}[name]!
Key defined as variable
Log Many ${DICT}[${KEY}] ${DICT}[${42}]
Attribute access
Login ${USER.name} ${USER.password}
Title Should Be Welcome ${USER.name}!
```
##### Nested item access
Also nested subscriptable variables can be accessed using the same item access syntax like `${var}[item1][item2]`. This is especially useful when working with JSON data often returned by REST services. For example, if a variable `${DATA}` contains , this tests would pass:
```
*** Test Cases ***
Nested item access
Should Be Equal ${DATA}[0][name] Robot
Should Be Equal ${DATA}[1][id] ${2}
```
#### [Environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-332)
Robot Framework allows using environment variables in the test data using the syntax `%{ENV_VAR_NAME}`. They are limited to string values. It is possible to specify a default value, that is used if the environment variable does not exists, by separating the variable name and the default value with an equal sign like `%{ENV_VAR_NAME=default value}`.
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](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) 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.
```
*** Test Cases ***
Environment variables
Log Current user: %{USER}
Run %{JAVA_HOME}${/}javac
Environment variable with default
Set Port %{APPLICATION_PORT=8080}
```
Note
Support for specifying the default value is new in Robot Framework 3.2.
### [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-333)
Variables can be created using different approaches discussed in this section:
- In the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section)
- Using [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- On the [command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables)
- Based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords)
- Using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax)
- Using [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords)
In addition to this, there are various automatically available [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) and also [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) create variables. In most places where variables are created, it is possible to use [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) to easily create variables with non-string values. An important application for conversions is creating [secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables).
#### [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-334)
The most common source for variables are Variable sections in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files). Variable sections 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 variables cannot be created dynamically. If that is a problem, [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) can be used instead.
##### Creating scalar values
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 section 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.
```
*** Variables ***
${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.
```
*** Variables ***
${NAME} = Robot Framework
${VERSION} = 2.0
```
If a scalar variable has a long value, it can be [split into multiple rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) by using the `...` syntax. By default rows are concatenated together using a space, but this can be changed by using a `separator` configuration option after the last value:
```
*** Variables ***
${EXAMPLE} This value is joined
... together with a space.
${MULTILINE} First line.
... Second line.
... Third line.
... separator=\n
```
The `separator` option is new in Robot Framework 7.0, but also older versions support configuring the separator. With them the first value can contain a special `SEPARATOR` marker:
```
*** Variables ***
${MULTILINE} SEPARATOR=\n
... First line.
... Second line.
... Third line.
```
Both the `separator` option and the `SEPARATOR` marker are case-sensitive. Using the `separator` option is recommended, unless there is a need to support also older versions.
##### Creating lists
Creating lists is as easy as creating scalar values. Again, the variable name is in the first column of the Variable section and values in the subsequent columns, but this time the variable name must start with `@` instead of `$`. A list can have any number of items, including zero, and items can be [split into several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) if needed.
```
*** Variables ***
@{NAMES} Matti Teppo
@{NAMES2} @{NAMES} Seppo
@{NOTHING}
@{MANY} one two three four
... five six seven
```
Note
As discussed in the [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable-syntax) section, variables containing lists can be used as scalars like `${NAMES}` and by using the list expansion syntax like `@{NAMES}`.
##### Creating dictionaries
Dictionaries can be created in the Variable section similarly as lists. The differences are that the name must now start with `&` and that items need to be created using the `name=value` syntax or based on existing dictionary variables. If there are multiple items with same name, the last value has precedence. If a name contains a literal equal sign, it can be [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with a backslash like `\=`.
```
*** Variables ***
&{USER 1} name=Matti address=xxx phone=123
&{USER 2} name=Teppo address=yyy phone=456
&{MANY} first=1 second=${2} ${3}=third
&{EVEN MORE} &{MANY} first=override empty=
... =empty key\=here=value
```
Note
As discussed in the [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable-syntax) section, variables containing dictionaries can be used as scalars like `${USER 1}` and by using the dictionary expansion syntax like `&{USER 1}`.
Unlike with normal Python dictionaries, values of dictionaries created using this syntax can be accessed as attributes, which means that it is possible to use [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${VAR.key}`. This only works if the key is a valid attribute name and does not match any normal attribute Python dictionaries have, though. For example, individual value `${USER}[name]` can also be accessed like `${USER.name}`, but using `${MANY.3}` is not possible.
Tip
With nested dictionaries keys are accessible like `${DATA.nested.key}`.
Dictionaries are also ordered. This means that if they are iterated, their items always come in the order they are defined. This can be useful, for example, if dictionaries are used as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) or otherwise. When a dictionary is used as a list variable, the actual value contains dictionary keys. For example, `@{MANY}` variable would have a value .
##### Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the variable name dynamically based on another variable:
```
*** Variables ***
${X} Y
${${X}} Z # Name is created based on '${X}'.
*** Test Cases ***
Dynamically created name
Should Be Equal ${Y} Z
```
#### [Using variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-335)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files).
#### [Command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-336)
Variables can be set from the command line either individually with the \--variable (-v) option or using the aforementioned variable files 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 section and in variable files imported in the Setting section.
The syntax for setting individual variables is \--variable name:value, where `name` is the name of the variable without the `${}` decoration and `value` is its value. Several variables can be set by using this option several times.
```
--variable EXAMPLE:value
--variable HOST:localhost:7272 --variable USER:robot
```
In the examples above, variables are set so that:
- `${EXAMPLE}` gets value `value`, and
- `${HOST}` and `${USER}` get values `localhost:7272` and `robot`, respectively.
The basic syntax for taking [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) into use from the command line is \--variablefile path/to/variables.py and the [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use) section explains this more thoroughly. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes).
#### [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-337)
Return values from keywords can also be assigned into variables. This allows communication between different keywords even in different libraries by passing created variables forward as arguments to other keywords.
Variables set in this manner are otherwise similar to any other variables, but they are available only in the [local scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#local-scope) where they are created. Thus it is not possible, for example, to set a variable like this 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 the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords) as explained in the subsequent sections.
##### Assigning scalar variables
Any value returned by a keyword can be assigned to a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable). As illustrated by the example below, the required syntax is very simple:
```
*** Test Cases ***
Returning
${x} = Get X an argument
Log We got ${x}!
```
In the above example the value returned by the Get X keyword is first set into the variable `${x}` and then used by the Log keyword. Having the equals sign `=` after the name of the assigned variable is not obligatory, but it makes the assignment more explicit. Creating local variables like this works both in test case and user keyword level.
Notice that although a value is assigned to a scalar variable, it can be used as a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) if it has a list-like value and as a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) if it has a dictionary-like value.
```
*** Test Cases ***
List assigned to scalar variable
${list} = Create List first second third
Length Should Be ${list} 3
Log Many @{list}
```
##### Assigning variable items
Starting from Robot Framework 6.1, when working with variables that support item assignment such as lists or dictionaries, it is possible to set their values by specifying the index or key of the item using the syntax `${var}[item]` where the `item` part can itself contain a variable:
```
*** Test Cases ***
List item assignment
${list} = Create List one two three four
${list}[0] = Set Variable first
${list}[${1}] = Set Variable second
${list}[2:3] = Create List third
${list}[-1] = Set Variable last
Log Many @{list} # Logs 'first', 'second', 'third' and 'last'
Dictionary item assignment
${dict} = Create Dictionary first_name=unknown
${dict}[first_name] = Set Variable John
${dict}[last_name] = Set Variable Doe
Log ${dictionary} # Logs {'first_name': 'John', 'last_name': 'Doe'}
```
##### Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the name of the assigned variable dynamically based on another variable:
```
*** Test Cases ***
Dynamically created name
${x} = Set Variable y
${${x}} = Set Variable z # Name is created based on '${x}'.
Should Be Equal ${y} z
```
##### Assigning list variables
If a keyword returns a list or any list-like object, it is possible to assign it to a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable):
```
*** Test Cases ***
Assign to list variable
@{list} = Create List first second third
Length Should Be ${list} 3
Log Many @{list}
```
Because all Robot Framework variables are stored in the same namespace, there is not much difference between assigning a value to a scalar variable or a list variable. This can be seen by comparing the above example with the earlier example with the `List assigned to scalar variable` test case. The main differences are that when creating a list variable, Robot Framework automatically verifies that the value is a list or list-like, and the stored variable value will be a new list created from the return value. When assigning to a scalar variable, the return value is not verified and the stored value will be the exact same object that was returned.
##### Assigning dictionary variables
If a keyword returns a dictionary or any dictionary-like object, it is possible to assign it to a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable):
```
*** Test Cases ***
Assign to dictionary variable
&{dict} = Create Dictionary first=1 second=${2} ${3}=third
Length Should Be ${dict} 3
Do Something &{dict}
Log ${dict.first}
```
Because all Robot Framework variables are stored in the same namespace, it would also be possible to assign a dictionary into a scalar variable and use it later as a dictionary when needed. There are, however, some concrete benefits in creating a dictionary variable explicitly. First of all, Robot Framework verifies that the returned value is a dictionary or dictionary-like similarly as it verifies that list variables can only get a list-like value.
A bigger benefit is that the value is converted into a special dictionary that is used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Values in these dictionaries can be accessed using attribute access like `${dict.first}` in the above example.
##### Assigning multiple variables
If a keyword returns a list or a list-like object, it is possible to assign individual values into multiple scalar variables or into scalar variables and a list variable.
```
*** Test Cases ***
Assign multiple
${a} ${b} ${c} = Get Three
${first} @{rest} = Get Three
@{before} ${last} = Get Three
${begin} @{middle} ${end} = Get Three
```
Assuming that the keyword Get Three returns a list `[1, 2, 3]`, the following variables are created:
- `${a}`, `${b}` and `${c}` with values `1`, `2`, and `3`, respectively.
- `${first}` with value `1`, and `@{rest}` with value `[2, 3]`.
- `@{before}` with value `[1, 2]` and `${last}` with value `3`.
- `${begin}` with value `1`, `@{middle}` with value `[2]` and `${end}` with value `3`.
It is an error if the returned list has more or less values than there are scalar variables to assign. Additionally, only one list variable is allowed and dictionary variables can only be assigned alone.
##### Automatically logging assigned variable value
To make it easier to understand what happens during execution, the beginning of value that is assigned is automatically logged. The default is to show 200 first characters, but this can be changed by using the \--maxassignlength command line option when running tests. If the value is zero or negative, the whole assigned value is hidden.
```
--maxassignlength 1000
--maxassignlength 0
```
The reason the value is not logged fully is that it could be really big. If you always want to see a certain value fully, it is possible to use the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) Log keyword to log it after the assignment.
Note
The \--maxassignlength option is new in Robot Framework 5.0.
#### [`VAR` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-338)
Starting from Robot Framework 7.0, it is possible to create variables inside tests and user keywords using the `VAR` syntax. The `VAR` marker is case-sensitive and it must be followed by a variable name and value. Other than the mandatory `VAR`, the overall syntax is mostly the same as when creating variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section).
The new syntax aims to make creating variables simpler and more uniform. It is especially indented to replace the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Set Variable, Set Local Variable, Set Test Variable, Set Suite Variable and Set Global Variable, but it can be used instead of Catenate, Create List and Create Dictionary as well.
##### Creating scalar variables
In simple cases scalar variables are created by just giving a variable name and its value. The value can be a hard-coded string or it can itself contain a variable. If the value is long, it is possible to split it into multiple columns and rows. In that case parts are joined together with a space by default, but the separator to use can be specified with the `separator` configuration option. It is possible to have an optional `=` after the variable name the same way as when creating variables based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) and in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section).
```
*** Test Cases ***
Scalar examples
VAR ${simple} variable
VAR ${equals} = this works too
VAR ${variable} value contains ${simple}
VAR ${sentence} This is a bit longer variable value
... that is split into multiple rows.
... These parts are joined with a space.
VAR ${multiline} This is another longer value.
... This time there is a custom separator.
... As the result this becomes a multiline string.
... separator=\n
```
##### Creating lists and dictionaries
List and dictionary variables are created similarly as scalar variables, but the variable names must start with `@` and `&`, respectively. When creating dictionaries, items must be specified using the `name=value` syntax.
```
*** Test Cases ***
List examples
VAR @{two items} Robot Framework
VAR @{empty list}
VAR @{lot of stuff}
... first item
... second item
... third item
... fourth item
... last item
Dictionary examples
VAR &{two items} name=Robot Framework url=http://robotframework.org
VAR &{empty dict}
VAR &{lot of stuff}
... first=1
... second=2
... third=3
... fourth=4
... last=5
```
##### Scope
Variables created with the `VAR` syntax are are available only within the test or user keyword where they are created. That can, however, be altered by using the `scope` configuration option. Supported values are:
`LOCAL`
Make the variable available in the current local scope. This is the default.
`TEST`
Make the variable available within the current test. This includes all keywords called by the test. If used on the suite level, makes the variable available in suite setup and teardown, but not in tests or possible child suites. Prior to Robot Framework 7.2, using this scope on the suite level was an error.
`TASK`
Alias for `TEST` that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
`SUITE`
Make the variable available within the current suite. This includes all subsequent tests in that suite, but not tests in possible child suites.
`SUITES`
Make the variable available within the current suite and in its child suites. New in Robot Framework 7.1.
`GLOBAL`
Make the variable available globally. This includes all subsequent keywords and tests.
Although Robot Framework variables are case-insensitive, it is recommended to use capital letters with non-local variable names.
```
*** Variables ***
${SUITE} this value is overridden
*** Test Cases ***
Scope example
VAR ${local} local value
VAR ${TEST} test value scope=TEST
VAR ${SUITE} suite value scope=SUITE
VAR ${SUITES} nested suite value scope=SUITES
VAR ${GLOBAL} global value scope=GLOBAL
Should Be Equal ${local} local value
Should Be Equal ${TEST} test value
Should Be Equal ${SUITE} suite value
Should Be Equal ${SUITES} nested suite value
Should Be Equal ${GLOBAL} global value
Keyword
Should Be Equal ${TEST} new test value
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
Scope example, part 2
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
*** Keywords ***
Keyword
Should Be Equal ${TEST} test value
Should Be Equal ${SUITE} suite value
Should Be Equal ${SUITES} nested suite value
Should Be Equal ${GLOBAL} global value
VAR ${TEST} new ${TEST} scope=TEST
VAR ${SUITE} new ${SUITE} scope=SUITE
VAR ${SUITES} new ${SUITES} scope=SUITES
VAR ${GLOBAL} new ${GLOBAL} scope=GLOBAL
Should Be Equal ${TEST} new test value
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
```
##### Creating variables conditionally
The `VAR` syntax works with [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) which makes it easy to create variables conditionally. In simple cases using [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) can be convenient.
```
*** Test Cases ***
IF/ELSE example
IF "${ENV}" == "devel"
VAR ${address} 127.0.0.1
VAR ${name} demo
ELSE
VAR ${address} 192.168.1.42
VAR ${name} robot
END
Inline IF
IF "${ENV}" == "devel" VAR ${name} demo ELSE VAR ${name} robot
```
##### Creating variable name based on another variable
If there is a need, variable name can also be created dynamically based on another variable.
```
*** Test Cases ***
Dynamic name
VAR ${x} y # Normal assignment.
VAR ${${x}} z # Name created dynamically.
Should Be Equal ${y} z
```
#### [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-339)
Note
The `VAR` syntax is recommended over these keywords when using Robot Framework 7.0 or newer.
The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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. It is an error to call Set Test Variable outside the scope of a test (e.g. in a Suite Setup or Teardown).
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 section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) in the test data file or importing them from [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 variables on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) using the \--variable and \--variablefile options. Because this keyword can change variables everywhere, it should be used with care.
Note
Set Test/Suite/Global Variable keywords set named variables directly into [test, suite or global variable scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-scopes) and return nothing. On the other hand, another [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Set Variable sets local variables using [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords).
#### [Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-340)
Variable values are typically strings, but non-string values are often needed as well. Various ways how to create variables with non-string values has already been discussed:
- [Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) allow creating any kind of objects.
- [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) can contain any objects.
- Variables can be created based on existing variables that contain non-string values.
- `@{list}` and `&{dict}` syntax allows creating lists and dictionaries natively.
In addition to the above, it is possible to specify the variable type like `${name: int}` when creating variables, and the value is converted to the specified type automatically. This is called *variable type conversion* and how it works in practice is discussed in this section.
Note
Variable type conversion is new in Robot Framework 7.3.
##### Variable type syntax
The general variable types syntax is `${name: type}` [in the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-in-data) and `name: type:value` [on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-on-command-line). The space after the colon is mandatory in both cases. Although variable name can in some contexts be created dynamically based on another variable, the type and the type separator must be always specified as literal values.
Variable type conversion supports the same base types that the [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) supports with library keywords. For example, `${number: int}` means that the value of the variable `${number}` is converted to an integer.
Variable type conversion supports also [specifying multiple possible types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-multiple-possible-types) using the union syntax. For example, `${number: int | float}` means that the value is first converted to an integer and, if that fails, then to a floating point number.
Also [parameterized types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parameterized-types) are supported. For example, `${numbers: list[int]}` means that the value is converted to a list of integers.
The biggest limitations compared to the argument conversion with library keywords is that `Enum` and `TypedDict` conversions are not supported and that custom converters cannot be used. These limitations may be lifted in the future versions.
Note
Variable conversion is supported only when variables are created, not when they are used.
##### Variable conversion in data
In the data variable conversion works when creating variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section), with the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) and based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords):
```
*** Variables ***
${VERSION: float} 7.3
${CRITICAL: list[int]} [3278, 5368, 5417]
*** Test Cases ***
Variables section
Should Be Equal ${VERSION} ${7.3}
Should Be Equal ${CRITICAL} ${{[3278, 5368, 5417]}}
VAR syntax
VAR ${number: int} 42
Should Be Equal ${number} ${42}
Assignment
# In simple cases the VAR syntax is more convenient.
${number: int} = Set Variable 42
Should Be Equal ${number} ${42}
# In this case conversion is more useful.
${match} ${version: float} = Should Match Regexp RF 7.3 ^RF (\\d+\\.\\d+)$
Should Be Equal ${match} RF 7.3
Should Be Equal ${version} ${7.3}
```
Note
In addition to the above, variable type conversion works also with [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). See their documentation for more details.
Note
Variable type conversion *does not* work with [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords). The [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) needs to be used instead.
##### Conversion with `@{list}` and `&{dict}` variables
Type conversion works also when creating [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-lists) and [dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) using `@{list}` and `&{dict}` syntax. With lists the type is specified like `@{name: type}` and the type is the type of the list items. With dictionaries the type of the dictionary values can be specified like `&{name: type}`. If there is a need to specify also the key type, it is possible to use syntax `&{name: ktype=vtype}`.
```
*** Variables ***
@{NUMBERS: int} 1 2 3 4 5
&{DATES: date} rc1=2025-05-08 final=2025-05-30
&{PRIORITIES: int=str} 3278=Critical 4173=High 5334=High
```
An alternative way to create lists and dictionaries is creating `${scalar}` variables, using `list` and `dict` types, possibly parameterizing them, and giving values as Python list and dictionary literals:
```
*** Variables ***
${NUMBERS: list[int]} [1, 2, 3, 4, 5]
${DATES: list[date]} {'rc1': '2025-05-08', 'final': '2025-05-30'}
${PRIORITIES: dict[int, str]} {3278: 'Critical', 4173: 'High', 5334: 'High'}
```
Using Python list and dictionary literals can be somewhat complicated especially for non-programmers. The main benefit of this approach is that it supports also nested structures without needing to use temporary values. The following examples create the same `${PAYLOAD}` variable using different approaches:
```
*** Variables ***
@{CHILDREN: int} 2 13 15
&{PAYLOAD: dict} id=${1} name=Robot children=${CHILDREN}
```
```
*** Variables ***
${PAYLOAD: dict} {'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}
```
##### Variable conversion on command line
Variable conversion works also with the [command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) that are created using the `--variable` option. The syntax is `name: type:value` and, due to the space being mandatory, the whole option value typically needs to be quoted. Following examples demonstrate some possible usages for this functionality:
```
--variable "ITERATIONS: int:99"
--variable "PAYLOAD: dict:{'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}"
--variable "START_TIME: datetime:now"
```
##### Failing conversion
If type conversion fails, there is an error and the variable is not created. Conversion fails if the value cannot be converted to the specified type or if the type itself is not supported:
```
*** Test Cases ***
Invalid value
VAR ${example: int} invalid
Invalid type
VAR ${example: invalid} 123
```
#### [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-341)
An important usage for [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) is creating so called *secret variables*. These variables encapsulate their values so that the real values are [not logged even on the trace level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) when variables are passed between keywords as arguments and return values.
The actual value is available via the `value` attribute of a secret variable. It is mainly meant to be used by [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) that accept [secret values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-type), but it can be accessed also in the data using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${secret.value}`. Accessing the value in the data makes it visible in the log file similarly as if it was a normal variable, so that should only be done for debugging or testing purposes.
Warning
Secret variables do not hide or encrypt their values. The real values are thus available for all code that can access these variables directly or indirectly via Robot Framework APIs.
Note
Secret variables are new in Robot Framework 7.4.
##### Creating secrets in data
In the data secret variables can be created in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) and by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax). To avoid secret values being visible to everyone who has access to the data, it is not possible to create secret variables using literal values. Instead the value must be created using an existing secret variable or an [environment variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variable) like `%{NAME}`. In both cases joining a secret value with a literal value like `%{SECRET}123` is allowed as well.
If showing the secret variable in the data is not an issue, it is possible to use environment variable default values like `%{NAME=default}`. The name can even be left empty like `%{=secret}` to always use the default value.
```
*** Variables ***
${NORMAL: Secret} ${XXX} # ${XXX} must itself be a secret variable.
${ENVIRON: Secret} %{EXAMPLE} # Environment variables are supported directly.
${DEFAULT: Secret} %{=robot123} # Environment variable defaults work as well.
${JOIN: Secret} ${XXX}-123 # Joining secrets with literals is ok.
${LITERAL: Secret} robot123 # This fails.
```
Also list and dictionary variables support secret values:
```
*** Variables ***
@{LIST: Secret} ${XXX} %{EXAMPLE} %{=robot123} ${XXX}-123
&{DICT: Secret} normal=${XXX} env=%{EXAMPLE} env_default=%{=robot123} join=${XXX}-123
```
Note
The above examples utilize the Variable section, but the syntax to create secret variables is exactly the same when using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax).
##### Creating secrets on command line
[Command line variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-on-command-line) supports secret values directly:
```
--variable "PASSWORD: Secret:robot123"
```
Having the secret value directly visible on the command line history or in continuous integration system logs can be a security risk. One way to mitigate that is using environment variables:
```
--variable "PASSWORD: Secret:$PASSWORD"
```
Many systems running tests or tasks also support hiding secret values used on the command line.
##### Creating secrets programmatically
Secrets can be created programmatically by using the [robot.api.types.Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) class. This is most commonly done by [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) and [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files), but also [pre-run modifiers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data) and [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) can utilize secrets if needed.
The simplest possible example of the programmatic usage is a variable file:
```
from robot.api.types import Secret
USERNAME = "robot"
PASSWORD = Secret("robot123")
```
Creating a keyword returning a secret is not much more complicated either:
```
from robot.api.types import Secret
def get_token():
return Secret("e5805f56-92e1-11f0-a798-8782a78eb4b5")
```
Note
Both examples above have the actual secret value visible in the code. When working with real secret values, it is typically better to read secrets from environment variables, get them from external systems or generate them randomly.
### [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-342)
Robot Framework provides some built-in variables that are available automatically.
#### [Operating-system variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-343)
Built-in variables related to the operating system ease making the test data operating-system-agnostic.
| 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. |
| \${/} | The system directory path separator. `/` in UNIX-like systems and \\ in Windows. |
| \${:} | The system path element separator. `:` in UNIX-like systems and `;` in Windows. |
| \${\\n} | The system line separator. \\n in UNIX-like systems and \\r\\n in Windows. |
```
*** Test Cases ***
Example
Create Binary File ${CURDIR}${/}input.data Some text here${\n}on two lines
Set Environment Variable CLASSPATH ${TEMPDIR}${:}${CURDIR}${/}foo.jar
```
#### [Number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-344)
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.
```
*** Test Cases ***
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
```
It is possible to create integers also from binary, octal, and hexadecimal values using `0b`, `0o` and `0x` prefixes, respectively. The syntax is case insensitive.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-345)
Also Boolean values and Python `None` can be created using the variable syntax similarly as numbers.
```
*** Test Cases ***
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
```
These variables are case-insensitive, so for example `${True}` and `${true}` are equivalent. Keywords accepting Boolean values typically do automatic argument conversion and handle string values like `True` and `false` as expected. In such cases using the variable syntax is not required.
#### [Space and empty variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-346)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with a backslash. If more than one space is needed, it is possible to use the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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} \
```
There is also an empty [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) `@{EMPTY}` and an empty [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) `&{EMPTY}`. Because they have no content, they basically vanish when used somewhere in the test data. They are useful, for example, with [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) when the [template keyword is used without arguments](https://groups.google.com/group/robotframework-users/browse_thread/thread/ccc9e1cd77870437/4577836fe946e7d5?lnk=gst&q=templates#4577836fe946e7d5) or when overriding list or dictionary variables in different scopes. Modifying the value of `@{EMPTY}` or `&{EMPTY}` is not possible.
```
*** Test Cases ***
Template
[Template] Some keyword
@{EMPTY}
Override
Set Global Variable @{LIST} @{EMPTY}
Set Suite Variable &{DICT} &{EMPTY}
```
Note
`${SPACE}` represents the ASCII space (`\x20`) and [other spaces](http://jkorpela.fi/chars/spaces.html) should be specified using the [escape sequences](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) like `\xA0` (NO-BREAK SPACE) and `\u3000` (IDEOGRAPHIC SPACE).
#### [Automatic variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-347)
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. Altering the value of these variables does not affect the original values, but some values can be changed dynamically using keywords from the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library.
| 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. Can be modified dynamically using Set Tags and Remove Tags keywords. | Test case |
| \${TEST DOCUMENTATION} | The documentation of the current test case. Can be set dynamically using using Set Test Documentation keyword. | Test case |
| \${TEST STATUS} | The status of the current test case, either PASS or FAIL. | [Test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) |
| \${TEST MESSAGE} | The message of the current test case. | [Test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-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. | Everywhere |
| \${SUITE DOCUMENTATION} | The documentation of the current test suite. Can be set dynamically using using Set Suite Documentation keyword. | Everywhere |
| &{SUITE METADATA} | The free metadata of the current test suite. Can be set using Set Suite Metadata keyword. | Everywhere |
| \${SUITE STATUS} | The status of the current test suite, either PASS or FAIL. | [Suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) |
| \${SUITE MESSAGE} | The full message of the current test suite, including statistics. | [Suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) |
| \${KEYWORD STATUS} | The status of the current keyword, either PASS or FAIL. | [User keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) |
| \${KEYWORD MESSAGE} | The possible error message of the current keyword. | [User keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) |
| \${LOG LEVEL} | Current [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). | Everywhere |
| \${OUTPUT DIR} | An absolute path to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) as a string. | Everywhere |
| \${OUTPUT FILE} | An absolute path to the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) as a string or a string `NONE` if the output file is not created. | Everywhere |
| \${LOG FILE} | An absolute path to the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as a string or a string `NONE` if the log file is not created. | Everywhere |
| \${REPORT FILE} | An absolute path to the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) as a string or a string `NONE` if the report file is not created. | Everywhere |
| \${DEBUG FILE} | An absolute path to the [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) as a string or a string `NONE` if the debug file is not created. | Everywhere |
| &{OPTIONS} | A dictionary exposing command line options. The dictionary keys match the command line options and can be accessed both like `${OPTIONS}[key]` and `${OPTIONS.key}`. Available options: `${OPTIONS.exclude}` (\--exclude) `${OPTIONS.include}` (\--include) `${OPTIONS.skip}` (\--skip) `${OPTIONS.skip_on_failure}` (\--skip-on-failure) `${OPTIONS.console_width}` (integer, \--console-width) `${OPTIONS.rpa}` (boolean, \--rpa) `${OPTIONS}` itself was added in RF 5.0, `${OPTIONS.console_width}` in RF 7.1 and `${OPTIONS.rpa}` in RF 7.3. More options can be exposed later. | Everywhere |
Suite related variables `${SUITE SOURCE}`, `${SUITE NAME}`, `${SUITE DOCUMENTATION}` and `&{SUITE METADATA}` as well as options related to command line options like `${LOG FILE}` and `&{OPTIONS}` are available already when libraries and variable files are imported. Possible variables in these automatic variables are not yet resolved at the import time, though.
### [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-348)
Variables coming from different sources have different priorities and are available in different scopes.
#### [Variable priorities](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-349)
*Variables from the command line*
> Variables [set on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) have the highest priority of all variables that can be set before the actual test execution starts. They override possible variables created in Variable sections 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section in a test case file*
> Variables created using the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) 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 sections are available in all other sections in the file where they are created. This means that they can be used also in the Setting section, for example, for importing more variables from resource and variable files.
*Imported resource and variable files*
> Variables imported from the [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section 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 section of the file that imports them. This is due to the Variable section being processed before the Setting section where the resource files and variable files are imported.
*Variables set during test execution*
> Variables set during the test execution using [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords), [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) like `${TEMPDIR}` and `${TEST_NAME}` have the highest priority of all variables. They cannot be overridden using Variable section or from command line, but even they can be reset during the test execution. An exception to this rule are [number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-350)
Depending on where and how they are created, variables can have a global, test suite, test case or local scope.
##### Global scope
Global variables are available everywhere in the test data. These variables are normally [set from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) with the \--variable and \--variablefile options, but it is also possible to create new global variables or change the existing ones by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Global Variable keyword anywhere in the test data. Additionally also [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 sections, imported from [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files), or set during the test execution using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Suite Variable keyword.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 with the test case scope are visible in a test case and in all user keywords the test uses. Initially there are no variables in this scope, but it is possible to create them by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Test Variable keyword anywhere in a test case.
If a variable with the test scope is created in suite setup, the variable is available everywhere within that suite setup as well as in the corresponding suite teardown, but it is not seen by tests or possible child suites. If such a variable is created in a suite teardown, the variable is available only in that teardown.
Also variables in the test case scope are to some extend global. It is thus generally recommended to use capital letters with them too.
Note
Creating variables with the test scope in a suite setup or teardown caused an error prior to Robot Framework 7.2.
##### Local scope
Test cases and user keywords have a local variable scope that is not seen by other tests or keywords. Local variables can be created using [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) from executed keywords and with the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax), and user keywords also get them as [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments).
It is recommended to use lower-case letters with local variables.
### [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-351)
#### [Extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-352)
Extended variable syntax allows accessing attributes of an object assigned to a variable (for example, `${object.attribute}`) and even calling its methods (for example, `${obj.get_name()}`).
Extended variable syntax is a powerful feature, but it should be used with care. Accessing attributes is normally not a problem, on the contrary, because one variable containing an object with 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 pretty complicated to understand. If that happens, it is recommended to move the code into a library.
The most common usages of extended variable syntax are illustrated in the example below. First assume that we have the following [variable file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) and test case:
```
class MyObject:
def __init__(self, name):
self.name = name
def eat(self, what):
return f'{self.name} eats {what}'
def __str__(self):
return self.name
OBJECT = MyObject('Robot')
DICTIONARY = {1: 'one', 2: 'two', 3: 'three'}
```
```
*** Test Cases ***
Example
KW 1 ${OBJECT.name}
KW 2 ${OBJECT.eat('Cucumber')}
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 eats Cucumber`
- 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 name of the base variable is created. The body of the name consists of all the characters after the opening `{` until the first occurrence of a character that is not an alphanumeric character, an underscore or a space. For example, base variables of `${OBJECT.name}` and `${DICTIONARY[2]}`) are `OBJECT` and `DICTIONARY`, respectively.
3. A variable matching the base name 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.
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.
```
*** Test Cases ***
String
VAR ${string} abc
Log ${string.upper()} # Logs 'ABC'
Log ${string * 2} # Logs 'abcabc'
Number
VAR ${number} ${-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.
Extended variable syntax works also in [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) and [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) contexts. If, for example, an object assigned to a variable `${EXTENDED}` has an attribute `attribute` that contains a list as a value, it can be used as a list variable `@{EXTENDED.attribute}`.
#### [Extended variable assignment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-353)
It is possible to set attributes of objects stored to scalar variables using [keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) and a variation of the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax). Assuming we have variable `${OBJECT}` from the previous examples, attributes could be set to it like in the example below.
```
*** Test Cases ***
Example
${OBJECT.name} = Set Variable New name
${OBJECT.new_attr} = Set Variable New attribute
```
The extended variable assignment syntax is evaluated using the following rules:
1. The assigned variable must be a scalar variable and have at least one dot. Otherwise the extended assignment syntax is not used and the variable is assigned normally.
2. If there exists a variable with the full name (e.g. `${OBJECT.name}` in the example above) that variable will be assigned a new value and the extended syntax is not used.
3. The name of the base variable is created. The body of the name consists of all the characters between the opening `${` and the last dot, for example, `OBJECT` in `${OBJECT.name}` and `foo.bar` in `${foo.bar.zap}`. As the second example illustrates, the base name may contain normal extended variable syntax.
4. The name of the attribute to set is created by taking all the characters between the last dot and the closing `}`, for example, `name` in `${OBJECT.name}`. If the name does not start with a letter or underscore and contain only these characters and numbers, the attribute is considered invalid and the extended syntax is not used. A new variable with the full name is created instead.
5. A variable matching the base name is searched. If no variable is found, the extended syntax is not used and, instead, a new variable is created using the full variable name.
6. If the found variable is a string or a number, the extended syntax is ignored and a new variable created using the full name. This is done because you cannot add new attributes to Python strings or numbers, and this way the syntax is also less backwards-incompatible.
7. If all the previous rules match, the attribute is set to the base variable. If setting fails for any reason, an exception is raised and the test fails.
Note
Unlike when assigning variables normally using [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords), changes to variables done using the extended assign syntax are not limited to the current scope. Because no new variable is created but instead the state of an existing variable is changed, all tests and keywords that see that variable will also see the changes.
#### [Variables inside variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-354)
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.
```
*** Variables ***
${JOHN HOME} /home/john
${JANE HOME} /home/jane
*** Test Cases ***
Example
${name} = Get Name
Do X ${${name} HOME}
```
#### [Inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-355)
Variable syntax can also be used for evaluating Python expressions. The basic syntax is `${{expression}}` i.e. there are double curly braces around the expression. The `expression` can be any valid Python expression such as `${{1 + 2}}` or `${{['a', 'list']}}`. Spaces around the expression are allowed, so also `${{ 1 + 2 }}` and `${{ ['a', 'list'] }}` are valid. In addition to using normal [scalar variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), also [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) and [dictionary variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variables) support `@{{expression}}` and `&{{expression}}` syntax, respectively.
Main usages for this pretty advanced functionality are:
- Evaluating Python expressions involving Robot Framework's variables (`${{len('${var}') > 3}}`, `${{$var[0] if $var is not None else None}}`).
- Creating values that are not Python base types (`${{decimal.Decimal('0.11')}}`, `${{datetime.date(2019, 11, 5)}}`).
- Creating values dynamically (`${{random.randint(0, 100)}}`, `${{datetime.date.today()}}`).
- Constructing collections, especially nested collections (`${{[1, 2, 3, 4]}}`, `${{ {'id': 1, 'name': 'Example', 'children': [7, 9]} }}`).
- Accessing constants and other useful attributes in Python modules (`${{math.pi}}`, `${{platform.system()}}`).
This is somewhat similar functionality than the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) discussed earlier. As the examples above illustrate, this syntax is even more powerful as it provides access to Python built-ins like `len()` and modules like `math`. In addition to being able to use variables like `${var}` in the expressions (they are replaced before evaluation), variables are also available using the special `$var` syntax during evaluation. The whole expression syntax is explained in the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix.
Tip
Instead of creating complicated expressions, it is often better to move the logic into a [custom library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries). That eases maintenance, makes test data easier to understand and can also enhance execution speed.
Note
The inline Python evaluation syntax is new in Robot Framework 3.2.
## [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-255)
Keyword sections 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\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-syntax)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax-2)
- [Settings in the Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-keyword-section)
- [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation)
- [2\.7.3 User keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags)
- [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments)
- [Positional arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords)
- [Default values with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values-with-user-keywords)
- [Variable number of arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords)
- [Free named arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords)
- [Named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords)
- [Argument conversion with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-user-keywords)
- [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax-3)
- [Embedded arguments matching wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-arguments-matching-wrong-values)
- [Resolving conflicts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resolving-conflicts)
- [Using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions)
- [Argument conversion with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-embedded-arguments)
- [Behavior-driven development example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-development-example)
- [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values)
- [Using `RETURN` statement](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-return-statement)
- [Using \[Return\] setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-return-setting)
- [Using special keywords to return](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-special-keywords-to-return)
- [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown)
- [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#private-user-keywords)
- [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#recursion)
### [2\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-356)
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-357)
In many ways, the overall user keyword syntax is identical to the [test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax). User keywords are created in Keyword sections which differ from Test Case sections 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.
```
*** Keywords ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments), similarly as [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values).
User keywords can be created in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files), and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-358)
User keywords can have similar settings as [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-test-case-section), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation).
\[Tags\]
Sets [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) for the keyword.
\[Arguments\]
Specifies [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments).
\[Setup\], \[Teardown\]
Specify [user keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown). \[Setup\] is new in Robot Framework 7.0.
\[Timeout\]
Sets the possible [user keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout). [Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) are discussed in a section of their own.
\[Return\]
Specifies [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values). Deprecated in Robot Framework 7.0, the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement should be used instead.
Note
The format used above is recommended, but setting names are case-insensitive and spaces are allowed between brackets and the name. For example, `[ TAGS ]`:setting is valid.
### [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-359)
The user keyword name is defined in the first column of the Keyword section. 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. It supports same formatting, splitting to multiple lines, and other features as [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). This setting documents the user keyword in the test data. It is also shown in a more formal keyword documentation, which the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool can create from [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files). Finally, the first logical row of the documentation, until the first empty row, is shown as a keyword documentation in [test logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).
```
*** Keywords ***
One line documentation
[Documentation] One line documentation.
No Operation
Multiline documentation
[Documentation] The first line creates the short doc.
...
... This is the body of the documentation.
... It is not shown in Libdoc outputs but only
... the short doc is shown in logs.
No Operation
Short documentation in multiple lines
[Documentation] If the short doc gets longer, it can span
... multiple physical lines.
...
... The body is separated from the short doc with
... an empty line.
No Operation
```
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 keyword is used. For more information, see the [Deprecating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecating-keywords) section.
Note
Prior to Robot Framework 3.1, the short documentation contained only the first physical line of the keyword documentation.
### [2\.7.3 User keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-360)
Both user keywords and [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) can have tags. Similarly as when [tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases), there are two settings affecting user keyword tags:
Keyword Tags setting in the Settings section
All keywords in a file with this setting always get specified tags.
\[Tags\] setting with each keyword
Keywords get these tags in addition to possible tags specified using the Keyword Tags setting. The \[Tags\] setting also allows removing tags set with Keyword Tags by using the `-tag` syntax.
```
*** Settings ***
Keyword Tags gui html
*** Keywords ***
No own tags
[Documentation] Keyword has tags 'gui' and 'html'.
No Operation
Own tags
[Documentation] Keyword has tags 'gui', 'html', 'own' and 'tags'.
[Tags] own tags
No Operation
Remove common tag
[Documentation] Test has tags 'gui' and 'own'.
[Tags] own -html
No Operation
```
Keyword tags can be specified using variables, the `-tag` syntax supports patterns, and so on, exactly as [test case tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-tags).
In addition to using the dedicated settings, keyword tags can be specified on the last line of the documentation with `Tags:` prefix so that tags are separated with a comma. For example, following two keywords get same three tags:
```
*** Keywords ***
Settings tags using separate setting
[Tags] my fine tags
No Operation
Settings tags using documentation
[Documentation] I have documentation. And my documentation has tags.
... Tags: my, fine, tags
No Operation
```
Keyword tags are shown in logs and in documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc), where the keywords can also be searched based on tags. The [\--removekeywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) and [\--flattenkeywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keywords) commandline options also support selecting keywords by tag, and new usages for keywords tags are possibly added in later releases.
Similarly as with [test case tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-tags), user keyword tags with the `robot:` prefix are [reserved](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) for special features by Robot Framework itself. Users should thus not use any tag with these prefixes unless actually activating the special functionality. Starting from Robot Framework 6.1, [flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keyword-during-execution-time) can be taken into use using reserved tag `robot:flatten`.
Note
Keyword Tags is new in Robot Framework 6.0. With earlier versions all keyword tags need to be specified using the \[Tags\] setting.
Note
The `-tag` syntax for removing common tags is new in Robot Framework 7.0.
### [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-361)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), for example `${arg}`.
#### [Positional arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-362)
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 be as descriptive as possible. It is recommended to use lower-case letters in variable names, either as `${my_arg}`, `${my arg}` or `${myArg}`.
```
*** Keywords ***
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 with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-363)
When creating user keywords, positional arguments are sufficient in most situations. It is, however, sometimes useful that keywords have [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) for some or all of their arguments. Also user keywords support default values, 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. The default value can contain a [variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) created on [test, suite or global scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes), but local variables of the keyword executor cannot be used. Default value can also be defined based on earlier arguments accepted by the keyword.
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.
```
*** Keywords ***
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}=${VARIABLE}
[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}
Default Based On Earlier Argument
[Arguments] ${a} ${b}=${a} ${c}=${a} and ${b}
Should Be Equal ${a} ${b}
Should Be Equal ${c} ${a} and ${b}
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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 with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-364)
Sometimes even default values are not enough and there is a need for a keyword accepting [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments). User keywords support also this feature. All that is needed is having [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) such as `@{varargs}` after possible positional arguments in the keyword signature. This syntax can be combined with the previously described 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.
```
*** Keywords ***
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}
END
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). This combination of two rather advanced functions can sometimes be very useful.
The keywords in the examples above could be used, for example, like this:
```
*** Test Cases ***
Varargs with user keywords
Any Number Of Arguments
Any Number Of Arguments arg
Any Number Of Arguments arg1 arg2 arg3 arg4
One Or More Arguments required
One Or More Arguments arg1 arg2 arg3 arg4
Required, Default, Varargs required
Required, Default, Varargs required optional
Required, Default, Varargs arg1 arg2 arg3 arg4 arg5
```
Again, Pythonistas probably notice that the variable number of arguments syntax is very close to the one in Python.
#### [Free named arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-365)
User keywords can also accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) by having a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) like `&{named}` as the absolutely last argument. When the keyword is called, this variable will get all [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) that do not match any [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords) or [named-only argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords) in the keyword signature.
```
*** Keywords ***
Free Named Only
[Arguments] &{named}
Log Many &{named}
Positional And Free Named
[Arguments] ${required} &{extra}
Log Many ${required} &{extra}
Run Program
[Arguments] @{args} &{config}
Run Process program.py @{args} &{config}
```
The last example above shows how to create a wrapper keyword that accepts any positional or named argument and passes them forward. See [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) for a full example with same keyword.
Free named arguments support with user keywords works similarly as kwargs work in Python. In the signature and also when passing arguments forward, `&{kwargs}` is pretty much the same as Python's `**kwargs`.
#### [Named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-366)
User keywords support [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) that are inspired by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102). This syntax is typically used by having normal arguments *after* [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords) (`@{varargs}`). If the keywords does not use varargs, it is possible to use just `@{}` to denote that the subsequent arguments are named-only:
```
*** Keywords ***
With Varargs
[Arguments] @{varargs} ${named}
Log Many @{varargs} ${named}
Without Varargs
[Arguments] @{} ${first} ${second}
Log Many ${first} ${second}
```
Named-only arguments can be used together with [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords) as well as with [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords). When using free named arguments, they must be last:
```
*** Keywords ***
With Positional
[Arguments] ${positional} @{} ${named}
Log Many ${positional} ${named}
With Free Named
[Arguments] @{varargs} ${named only} &{free named}
Log Many @{varargs} ${named only} &{free named}
```
When passing named-only arguments to keywords, their order does not matter other than they must follow possible positional arguments. The keywords above could be used, for example, like this:
```
*** Test Cases ***
Example
With Varargs named=value
With Varargs positional second positional named=foobar
Without Varargs first=1 second=2
Without Varargs second=toka first=eka
With Positional foo named=bar
With Positional named=2 positional=1
With Free Named positional named only=value x=1 y=2
With Free Named foo=a bar=b named only=c quux=d
```
Named-only arguments can have default values similarly as [normal user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values-with-user-keywords). A minor difference is that the order of arguments with and without default values is not important.
```
*** Keywords ***
With Default
[Arguments] @{} ${named}=default
Log Many ${named}
With And Without Defaults
[Arguments] @{} ${optional}=default ${mandatory} ${mandatory 2} ${optional 2}=default 2 ${mandatory 3}
Log Many ${optional} ${mandatory} ${mandatory 2} ${optional 2} ${mandatory 3}
```
#### [Argument conversion with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-367)
User keywords support automatic argument conversion based on explicitly specified types. The type syntax `${name: type}` is the same, and the supported conversions are the same, as when [creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-syntax).
The basic usage with normal arguments is very simple. You only need to specify the type like `${count: int}` and the used value is converted automatically. If an argument has a default value like `${count: int}=1`, also the default value will be converted. If conversion fails, calling the keyword fails with an informative error message.
```
*** Test Cases ***
Move around
Move 3
Turn LEFT
Move 2.3 log=True
Turn right
Failing move
Move bad
Failing turn
Turn oops
*** Keywords ***
Move
[Arguments] ${distance: float} ${log: bool}=False
IF ${log}
Log Moving ${distance} meters.
END
Turn
[Arguments] ${direction: Literal["LEFT", "RIGHT"]}
Log Turning ${direction}.
```
Tip
Using `Literal`, like in the above example, is a convenient way to limit what values are accepted.
When using [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords), the type is specified like `@{numbers: int}` and is applied to all arguments. If arguments may have different types, it is possible to use an union like `@{numbers: float | int}`. With [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords) the type is specified like `&{named: int}` and it is applied to all argument values. Converting argument names is not supported.
```
*** Test Cases ***
Varargs
Send bytes Hello! Hyvä! \x00\x00\x07
Free named
Log releases rc 1=2025-05-08 rc 2=2025-05-19 rc 3=2025-05-21 final=2025-05-30
*** Keywords ***
Send bytes
[Arguments] @{data: bytes}
FOR ${value} IN @{data}
Log ${value} formatter=repr
END
Log releases
[Arguments] &{releases: date}
FOR ${version} ${date} IN &{releases}
Log RF 7.3 ${version} was released on ${date.day}.${date.month}.${date.year}.
END
```
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
### [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-368)
The previous section explained how to pass arguments to keywords so that they are listed separately after the keyword name. Robot Framework has also another approach to pass arguments, embedding them directly to the keyword name, used by the second test below:
```
*** Test Cases ***
Normal arguments
Select from list cat
Embedded arguments
Select cat from list
```
As the example illustrates, embedding arguments to keyword names can make the data easier to read and understand even for people without any Robot Framework experience.
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-369)
The previous example showed how using a keyword Select cat from list is more fluent than using Select from list so that `cat` is passed to it as an argument. We obviously could implement Select cat from list as a normal keyword accepting no arguments, but then we needed to implement various other keywords like Select dog from list for other animals. Embedded arguments simplify this and we can instead implement just one keyword with name Select \${animal} from list and use it with any animal:
```
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
*** Keywords ***
Select ${animal} from list
Open Page Pet Selection
Select Item From List animal_list ${animal}
```
As the above example shows, embedded arguments are specified simply by using variables in keyword names. The arguments used in the name are naturally available inside the keyword and they have different values depending on how the keyword is called. In the above example, `${animal}` has value `cat` when the keyword is used for the first time and `dog` when it is used for the second time.
Starting from Robot Framework 6.1, it is possible to create user keywords that accept both embedded and "normal" arguments:
```
*** Test Cases ***
Embedded and normal arguments
Number of cats should be 2
Number of dogs should be count=3
*** Keywords ***
Number of ${animals} should be
[Arguments] ${count}
Open Page Pet Selection
Select Items From List animal_list ${animals}
Number of Selected List Items Should Be ${count}
```
Other than the special name, keywords with embedded arguments are created just like other user keywords. They are also used the same way as other keywords except that spaces and underscores are not ignored in their names when keywords are matched. They are, however, case-insensitive like other keywords. For example, the Select \${animal} from list keyword could be used like select cow from list, but not like Select cow fromlist.
Embedded arguments do not support default values or variable number of arguments like normal arguments do. If such functionality is needed, normal arguments should be used instead. Passing embedded arguments as variables is possible, but that can reduce readability:
```
*** Variables ***
${SELECT} cat
*** Test Cases ***
Embedded arguments with variable
Select ${SELECT} from list
*** Keywords ***
Select ${animal} from list
Open Page Pet Selection
Select Item From List animal_list ${animal}
```
#### [Embedded arguments matching wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-370)
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, Select Los Angeles Lakers in the following example matches Select \${city} \${team} so that `${city}` contains `Los` and `${team}` contains `Angeles Lakers`:
```
*** Test Cases ***
Example
Select Chicago Bulls
Select Los Angeles Lakers
*** Keywords ***
Select ${city} ${team}
Log Selected ${team} from ${city}.
```
An easy solution to this problem is surrounding arguments with double quotes or other characters not used in the actual values. This fixed example works so that cities and teams match correctly:
```
*** Test Cases ***
Example
Select "Chicago" "Bulls"
Select "Los Angeles" "Lakers"
*** Keywords ***
Select "${city}" "${team}"
Log Selected ${team} from ${city}.
```
This approach is not enough to resolve all conflicts, but it helps in common cases and is generally recommended. Another benefit is that it makes arguments stand out from rest of the keyword.
Prior to Robot Framework 7.1, embedded arguments starting the keyword name also matched possible [given/when/then/and/but prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignoring-given-when-then-and-but-prefixes) typically used in Behavior Driven Development (BDD). For example, \${name} goes home matched Given Janne goes home so that `${name}` got value `Given Janne`. Nowadays the prefix is ignored and `${name}` will be `Janne` as expected. If older Robot Framework versions need to be supported, it is easiest to quote the argument like in "\${name}" goes home to get consistent behavior.
An alternative solution for limiting what values arguments match is [using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions).
#### [Resolving conflicts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-371)
When using embedded arguments, it is pretty common that there are multiple keyword implementations that match the keyword that is used. For example, Execute "ls" with "lf" in the example below matches both of the keywords. It matching Execute "\${cmd}" with "\${opts}" is pretty obvious and what we want, but it also matches Execute "\${cmd}" so that `${cmd}` matches `ls" with "-lh`.
```
*** Settings ***
Library Process
*** Test Cases ***
Automatic conflict resolution
Execute "ls"
Execute "ls" with "-lh"
*** Keywords ***
Execute "${cmd}"
Run Process ${cmd} shell=True
Execute "${cmd}" with "${opts}"
Run Process ${cmd} ${opts} shell=True
```
When this kind of conflicts occur, Robot Framework tries to automatically select the best match and use that. In the above example, Execute "\${cmd}" with "\${opts}" is considered a better match than the more generic Execute "\${cmd}" and running the example thus succeeds without conflicts.
It is not always possible to find a single match that is better than others. For example, the second test below fails because Robot Framework matches both of the keywords equally well. This kind of conflicts need to be resolved manually either by renaming keywords or by [using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions).
```
*** Test Cases ***
No conflict
Automation framework
Robot uprising
Unresolvable conflict
Robot Framework
*** Keywords ***
${type} Framework
Should Be Equal ${type} Automation
Robot ${action}
Should Be Equal ${action} uprising
```
Keywords that accept only "normal" arguments or no arguments at all are considered to match better than keywords accepting embedded arguments. For example, if the following keyword is added to the above example, Robot Framework used by the latter test matches it and the test succeeds:
```
*** Keywords ***
Robot Framework
No Operation
```
Before looking which match is best, Robot Framework checks are some of the matching keywords implemented in the same file as the caller keyword. If there are such keywords, they are given precedence over other keywords. Alternatively, [library search order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-search-order) can be used to control the order in which Robot Framework looks for keywords in resources and libraries.
Note
Automatically resolving conflicts if multiple keywords with embedded arguments match is a new feature in Robot Framework 6.0. With older versions custom regular expressions explained below can be used instead.
#### [Using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-372)
When keywords with embedded arguments are called, the values are matched internally using [regular expressions](http://en.wikipedia.org/wiki/Regular_expression) (regexps for short). The default logic goes so that every argument in the name is replaced with a pattern `.*?` that matches any string and tries to match as little as possible. This logic works fairly well normally, but as discussed above, sometimes keywords [match wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-arguments-matching-wrong-values) and sometimes there are [conflicts that cannot be resolved](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resolving-conflicts) . A solution in these cases is specifying 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+}`. If needed, custom patterns can be prefixed with [inline flags](https://docs.python.org/3/library/re.html#regular-expression-syntax) such as `(?i)` for case-insensitivity.
Using custom regular expressions is illustrated by the following examples. The first one shows how the earlier problem with Select \${city} \${team} not matching Select Los Angeles Lakers properly can be resolved without quoting by implementing the keyword so that `${team}` can only contain non-whitespace characters.
```
*** Test Cases ***
Do not match whitespace characters
Select Chicago Bulls
Select Los Angeles Lakers
Match numbers and characters from set
1 + 2 = 3
53 - 11 = 42
Match either date or literal 'today'
Deadline is 2022-09-21
Deadline is today
Case-insensitive match
Select dog
Select CAT
*** Keywords ***
Select ${city} ${team:\S+}
Log Selected ${team} from ${city}.
${number1:\d+} ${operator:[+-]} ${number2:\d+} = ${expected:\d+}
${result} = Evaluate ${number1} ${operator} ${number2}
Should Be Equal As Integers ${result} ${expected}
Deadline is ${deadline: date:\d{4}-\d{2}-\d{2}|today}
# The ': date' part of the above argument specifies the argument type.
# See the separate section about argument conversion for more information.
Log Deadline is ${deadline.day}.${deadline.month}.${deadline.year}.
Select ${animal:(?i)cat|dog}
[Documentation] Inline flag `(?i)` makes the pattern case-insensitive.
Log Selected ${animal}!
```
Note
Support for inline flags is new in Robot Framework 7.2.
##### Supported regular expression syntax
Being implemented with Python, Robot Framework naturally uses Python's [re module](http://docs.python.org/library/re.html) that has pretty standard regular expressions syntax. This syntax is otherwise fully supported with embedded arguments, but regexp extensions in format `(?...)` cannot be used. If the regular expression syntax is invalid, creating the keyword fails with an error visible in [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution).
##### Escaping special characters
Regular expressions use the backslash character (\\) heavily both to form special sequences (e.g. `\d`) and to escape characters that have a special meaning in regexps (e.g. `\$`). Typically in Robot Framework data backslash characters [need to be escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with another backslash, but that is not required in this context. If there is a need to have a literal backslash in the pattern, then the backslash must be escaped like `${path:c:\\temp\\.*}`.
Possible lone opening and closing curly braces in the pattern must be escaped like `${open:\{}` and `${close:\}}` or otherwise Robot Framework is not able to parse the variable syntax correctly. If there are matching braces like in `${digits:\d{2}}`, escaping is not needed.
Note
Prior to Robot Framework 3.2, it was mandatory to escape all closing curly braces in the pattern like `${digits:\d{2\}}`. This syntax is unfortunately not supported by Robot Framework 3.2 or newer and keywords using it must be updated when upgrading.
Note
Prior to Robot Framework 6.0, using literal backslashes in the pattern required double escaping them like `${path:c:\\\\temp\\\\.*}`. Patterns using literal backslashes need to be updated when upgrading.
##### Using variables with custom embedded argument regular expressions
When using embedded arguments with custom regular expressions, specifying values using variables works only if variables match the whole embedded argument, not if there is any additional content with the variable. For example, the first test below succeeds because the variable `${DATE}` is used on its own, but the last test fails because `${YEAR}-${MONTH}-${DAY}` is not a single variable.
```
*** Variables ***
${DATE} 2011-06-27
${YEAR} 2011
${MONTH} 06
${DAY} 27
*** Test Cases ***
Succeeds
Deadline is ${DATE}
Succeeds without variables
Deadline is 2011-06-27
Fails
Deadline is ${YEAR}-${MONTH}-${DAY}
*** Keywords ***
Deadline is ${deadline:\d{4}-\d{2}-\d{2}}
Should Be Equal ${deadline} 2011-06-27
```
Another limitation of using variables is that their actual values are not matched against custom regular expressions. As the result keywords may be called with values that their custom regexps would not allow. This behavior is deprecated starting from Robot Framework 6.0 and values will be validated in the future. For more information see issue [\#4462](https://github.com/robotframework/robotframework/issues/4462).
#### [Argument conversion with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-373)
User keywords accepting embedded arguments support argument conversion with type syntax `${name: type}` similarly as [normal user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-user-keywords). If a [custom pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions) is needed, it can be separated with an additional colon like `${name: type:pattern}`.
```
*** Test Cases ***
Example
Buy 3 books
Deadline is 2025-05-30
*** Keywords ***
Buy ${quantity: int} books
Should Be Equal ${quantity} ${3}
Deadline is ${deadline: date:\d{4}-\d{2}-\d{2}}
Should Be Equal ${deadline.year} ${2025}
Should Be Equal ${deadline.month} ${5}
Should Be Equal ${deadline.day} ${30}
```
Because the type separator is a colon followed by a space (e.g. `${arg: int}`) and the pattern separator is just a colon (e.g. `${arg:\d+}`), there typically are no conflicts when using only a type or only a pattern. The only exception is using a pattern starting with a space, but in that case the space can be escaped like `${arg:\ abc}` or a type added like `${arg: str: abc}`.
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
#### [Behavior-driven development example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-374)
A big benefit of having arguments as part of the keyword name is that it makes it easier to use higher-level sentence-like keywords when using the [behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) to write tests. As the example below shows, this support is typically used in combination with the possibility to [omit Given, When and Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignoring-given-when-then-and-but-prefixes) in keyword definitions:
```
*** Test Cases ***
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
*** Keywords ***
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 the popular BDD tool [Cucumber](https://cucumber.io/).
### [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-375)
Similarly as library keywords, also user keywords can return values. When using Robot Framework 5.0 or newer, the recommended approach is using the native [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement. The old \[Return\] setting was deprecated in Robot Framework 7.0 and also [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Return From Keyword and Return From Keyword If are considered deprecated.
Regardless how values are returned, they can be [assigned to variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) in test cases and in other user keywords.
#### [Using `RETURN` statement](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-376)
The recommended approach to return values is using the `RETURN` statement. It accepts optional return values and can be used with [IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if) and [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) structures. Its usage is easiest explained with examples:
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
[Documentation] Return a value unconditionally.
... Notice that keywords after RETURN are not executed.
${value} = Convert To Upper Case ${arg}
RETURN ${value}
Fail Not executed
Return Three Values
[Documentation] Return multiple values.
RETURN a b c
Conditional Return
[Arguments] ${arg}
[Documentation] Return conditionally.
Log Before
IF ${arg} == 1
Log Returning!
RETURN
END
Log After
Find Index
[Arguments] ${test} ${items}
[Documentation] Advanced example involving FOR loop, inline IF and @{list} variable syntax.
FOR ${index} ${item} IN ENUMERATE @{items}
IF $item == $test RETURN ${index}
END
RETURN ${-1}
```
If you want to test the above examples yourself, you can use them with these test cases:
```
*** Settings ***
Library String
*** Test Cases ***
One return value
${ret} = Return One Value argument
Should Be Equal ${ret} ARGUMENT
Multiple return values
${a} ${b} ${c} = Return Three Values
Should Be Equal ${a}, ${b}, ${c} a, b, c
Conditional return
Conditional Return 1
Conditional Return 2
Advanced
@{list} = Create List foo bar baz
${index} = Find Index bar ${list}
Should Be Equal ${index} ${1}
${index} = Find Index non existing ${list}
Should Be Equal ${index} ${-1}
```
Note
`RETURN` syntax is case-sensitive similarly as [IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if) and [FOR](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for).
Note
`RETURN` is new in Robot Framework 5.0. Use approaches explained below if you need to support older versions.
#### [Using \[Return\] setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-377)
The \[Return\] setting defines what the keyword should return after it has been executed. Although it is recommended to have it at the end of keyword where it logically belongs, its position does not affect how it is used.
An inherent limitation of the \[Return\] setting is that cannot be used conditionally. Thus only the first two earlier `RETURN` statement examples can be created using it.
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
${value} = Convert To Upper Case ${arg}
[Return] ${value}
Return Three Values
[Return] a b c
```
Note
The \[Return\] setting was deprecated in Robot Framework 7.0 and the `RETURN` statement should be used instead. If there is a need to support older Robot Framework versions that do not support `RETURN`, it is possible to use the special keywords discussed in the next section.
#### [Using special keywords to return](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-378)
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Return From Keyword and Return From Keyword If allow returning from a user keyword conditionally in the middle of the keyword. Both of them also accept optional return values that are handled exactly like with the `RETURN` statement and the \[Return\] setting discussed above.
The introduction of the `RETURN` statement makes these keywords redundant. Examples below contain same keywords as earlier `RETURN` examples but these ones are more verbose:
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
${value} = Convert To Upper Case ${arg}
Return From Keyword ${value}
Fail Not executed
Return Three Values
Return From Keyword a b c
Conditional Return
[Arguments] ${arg}
Log Before
IF ${arg} == 1
Log Returning!
Return From Keyword
END
Log After
Find Index
[Arguments] ${test} ${items}
FOR ${index} ${item} IN ENUMERATE @{items}
Return From Keyword If $item == $test ${index}
END
Return From Keyword ${-1}
```
Note
These keywords are effectively deprecated and the `RETURN` statement should be used unless there is a need to support also older versions than Robot Framework 5.0. There is no visible deprecation warning when using these keywords yet, but they will be loudly deprecated and eventually removed in the future.
### [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-379)
A user keyword can have a setup and a teardown similarly as [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). They are specified using \[Setup\] and \[Teardown\] settings, respectively, directly to the keyword having them. Unlike with tests, it is not possible to specify a common setup or teardown to all keywords in a certain file.
A setup and a teardown are always a single keyword, but they can themselves be user keywords executing multiple keywords internally. It is possible to specify them as variables, and using a special `NONE` value (case-insensitive) is the same as not having a setup or a teardown at all.
User keyword setup is not much different to the first keyword inside the created user keyword. The only functional difference is that a setup can be specified as a variable, but it can also be useful to be able to explicitly mark a keyword to be a setup.
User keyword teardowns are, exactly as test teardowns, executed also if the user keyword fails. They are thus very useful when needing to do something at the end of the keyword regardless of its status. To ensure that all cleanup activities are done, the [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) mode is enabled by default with user keyword teardowns the same way as with test teardowns.
```
*** Keywords ***
Setup and teardown
[Setup] Log New in RF 7!
Do Something
[Teardown] Log Old feature.
Using variables
[Setup] ${SETUP}
Do Something
[Teardown] ${TEARDOWN}
```
Note
User keyword setups are new in Robot Framework 7.0.
### [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-380)
User keywords can be [tagged](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) with a special `robot:private` tag to indicate that they should only be used in the file where they are created:
```
*** Keywords ***
Public Keyword
Private Keyword
Private Keyword
[Tags] robot:private
No Operation
```
Using the `robot:private` tag does not outright prevent using the keyword outside the file where it is created, but such usages will cause a warning. If there is both a public and a private keyword with the same name, the public one will be used but also this situation causes a warning.
Private keywords are included in spec files created by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) but not in its HTML output files.
Note
Private user keywords are new in Robot Framework 6.0.
### [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-381)
User keywords can call themselves either directly or indirectly. This kind of recursive usage is fine as long as the recursion ends, typically based on some condition, before the recursion limit is exceeded. The limit exists because otherwise infinite recursion would crash the execution.
Robot Framework's recursion detection works so, that it checks is the current recursion level close to the recursion limit of the underlying Python process. If it is close enough, no more new started keywords or control structures are allowed and execution fails.
Python's default recursion limit is 1000 stack frames, which in practice means that it is possible to start approximately 140 keywords or control structures. If that is not enough, Python's recursion limit can be raised using the [sys.setrecursionlimit()](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit) function. As the documentation of the function explains, this should be done with care, because a too-high level can lead to a crash.
Note
Prior to Robot Framework 7.2, the recursion limit was hard-coded to 100 started keywords or control structures.
## [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-256)
User keywords and variables in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) can only be used in files where they are created, but *resource files* provide a mechanism for sharing them. The high level syntax for creating resource files is exactly the same as when creating suite files and [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) are the same as well. The main difference is that resource files cannot have tests.
*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 or YAML, which also makes them somewhat more complicated than [Variable sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-sections).
- [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files)
- [Taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use)
- [Resource file structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-structure)
- [Documenting resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-resource-files)
- [Example resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-resource-file)
- [Resource files using reStructured text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format)
- [Resource files using JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format)
- [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use)
- [Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module)
- [Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function)
- [Implementing variable file as a class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implementing-variable-file-as-a-class)
- [Variable file as YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-yaml)
- [Variable file as JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-json)
### [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-382)
Resource files are typically created using the plain text format, but also [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format) and [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format) are supported.
#### [Taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-383)
Resource files are imported using the Resource setting in the Settings section so that the path to the resource file is given as an argument to the setting. The recommended extension for resource files is .resource. For backwards compatibility reasons also .robot, .txt and .tsv work, but using .resource may be mandated in the future.
If the resource file path is absolute, it is used directly. Otherwise, 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 Python's [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). Searching resource files from the module search path makes it possible to bundle them into Python packages as [package data](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#package-data) and importing them like package/example.resource.
The resource file path can contain variables, and it is recommended to use them to make paths system-independent (for example, \${RESOURCES}/login.resource or just \${RESOURCE\_PATH}). Additionally, forward slashes (`/`) in the path are automatically changed to backslashes (\\) on Windows.
```
*** Settings ***
Resource example.resource
Resource ../resources/login.resource
Resource package/example.resource
Resource ${RESOURCES}/common.resource
```
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.
Note
The .resource extension is new in Robot Framework 3.1.
#### [Resource file structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-384)
The higher-level structure of resource files is the same as that of suite files otherwise, but they cannot contain tests or tasks. Additionally, the Setting section in resource files can contain only imports (Library, Resource, Variables), Documentation and Keyword Tags. The Variable section and Keyword section are used exactly the same way as in suite 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-385)
Keywords created in a resource file can be [documented](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation) using \[Documentation\] setting. The resource file itself can have Documentation in the Setting section similarly as [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name).
[Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) and various editors use these documentations, and they are naturally available for anyone opening resource files. The first logical line of the documentation of a keyword, until the first empty line, is logged when the keyword is run, but otherwise resource file documentation is ignored during the test execution.
#### [Example resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-386)
```
*** Settings ***
Documentation An example resource file
Library SeleniumLibrary
Resource ${RESOURCES}/common.resource
*** Variables ***
${HOST} localhost:7272
${LOGIN URL} http://${HOST}/
${WELCOME URL} http://${HOST}/welcome.html
${BROWSER} Firefox
*** Keywords ***
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}
```
#### [Resource files using reStructured text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-387)
The [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format) that can be used with [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) works also with resource files. Such resource files can use either .rst or .rest extension and they are otherwise imported exactly as normal resource files:
```
*** Settings ***
Resource example.rst
```
When parsing resource files using the reStructuredText format, Robot Framework ignores all data outside code blocks containing Robot Framework data exactly the same way as when parsing [reStructuredText suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format). For example, the following resource file imports OperatingSystem library, defines `${MESSAGE}` variable and creates My Keyword keyword:
```
Resource file using reStructuredText
------------------------------------
This text is outside code blocks and thus ignored.
.. code:: robotframework
*** Settings ***
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
.. code:: robotframework
# Both space and pipe separated formats are supported.
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
```
#### [Resource files using JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-388)
Resource files can be created using [JSON](https://json.org/) the [same way as suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format). Such JSON resource files must use either the standard .json extension or the custom .rsrc extension. They are otherwise imported exactly as normal resource files:
```
*** Settings ***
Resource example.rsrc
```
Resource files can be converted to JSON using [ResourceFile.to\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.ResourceFile.to_json) and recreated using [ResourceFile.from\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.ResourceFile.from_json):
```
from robot.running import ResourceFile
# Create resource file based on data on the file system.
resource = ResourceFile.from_file_system('example.resource')
# Save JSON data to a file.
resource.to_json('example.rsrc')
# Recreate resource from JSON data.
resource = ResourceFile.from_json('example.rsrc')
```
### [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-389)
Variable files contain [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) that can be used in the test data. Variables can also be created using [Variable sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-sections) or [set from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables), but variable files allow creating them dynamically and also make it easy to create other variable values than strings.
Variable files are typically implemented as modules and there are two different approaches for creating variables:
[Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module)
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 its value. One limitation of this approach is that it does not allow using arguments.
[Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function)
Variable files can have a special `get_variables` (or `getVariables`) method that returns variables as a mapping. Because the method can take arguments this approach is very flexible.
Alternatively variable files can be implemented as [classes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implementing-variable-file-as-a-class) that the framework will instantiate. Also in this case it is possible to create variables as attributes or get them dynamically from the `get_variables` method. Variable files can also be created as [YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-yaml) and [JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-json).
#### [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-390)
##### Setting section
All test data files can import variable files using the Variables setting in the Setting section. Variable files are typically imported using a path to the file same way as [resource files are imported](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use) 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 directories in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). The path can also contain variables, and slashes are converted to backslashes on Windows.
Examples:
```
*** Settings ***
Variables myvariables.py
Variables ../data/variables.py
Variables ${RESOURCES}/common.yaml
```
Starting from Robot Framework 5.0, variable files implemented using Python can also be imported using the module name [similarly as libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import). When using this approach, the module needs to be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
Examples:
```
*** Settings ***
Variables myvariables
Variables rootmodule.Variables
```
If a [variable file accepts arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function), they are specified after the path or name of the variable file to import:
```
*** Settings ***
Variables arguments.py arg1 ${ARG2}
Variables arguments argument
```
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 sections 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 or module name similarly as when importing them using the Variables setting. Possible arguments are joined to the path with a colon (`:`):
```
--variablefile myvariables.py
--variablefile path/variables.py
--variablefile /absolute/path/common.py
--variablefile variablemodule
--variablefile arguments.py:arg1:arg2
--variablefile rootmodule.Variables:arg1:arg2
```
Variable files taken into use from the command line are also searched from the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) similarly as variable files imported in the Setting section. Relative paths are considered relative to the directory where execution is started from.
If a variable file is given as an absolute Windows path, the colon after the drive letter is not considered a separator:
```
--variablefile C:\path\variables.py
```
It is also possible to use a semicolon (`;`) as an argument separator. This is useful if variable file arguments themselves contain colons, but requires surrounding the whole value with quotes on UNIX-like operating systems:
```
--variablefile C:\path\variables.py;D:\data.xls
--variablefile "myvariables.py;argument:with:colons"
```
Variables in variable files taken use on the command line are globally available in all test data files, similarly as [individual variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-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.
#### [Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-391)
##### Basic syntax
When variable files are taken into use, they are imported as Python modules and all their module level attributes that do not start with an underscore (`_`) are, by default, 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]
MAPPING = {"one": 1, "two": 2, "three": 3}
```
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, then there are two lists, and the final value is a dictionary. All these variables can be used as a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable), lists and the dictionary also a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) like `@{STRINGS}` (in the dictionary's case that variable would only contain keys), and the dictionary also as a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) like `&{MAPPING}`.
To make creating a list variable or a dictionary variable more explicit, it is possible to prefix the variable name with `LIST__` or `DICT__`, respectively:
```
from collections import OrderedDict
LIST__ANIMALS = ["cat", "dog"]
DICT__FINNISH = OrderedDict([("cat", "kissa"), ("dog", "koira")])
```
These prefixes will not be part of the final variable name, but they cause Robot Framework to validate that the value actually is list-like or dictionary-like. With dictionaries the actual stored value is also turned into a special dictionary that is used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Values of these dictionaries are accessible as attributes like `${FINNISH.cat}`. These dictionaries are also ordered, but preserving the source order requires also the original dictionary to be ordered.
The variables in both the examples above could be created also using the Variable section below.
```
*** Variables ***
${VARIABLE} An example string
${ANOTHER VARIABLE} This is pretty easy!
${INTEGER} ${42}
@{STRINGS} one two kolme four
@{NUMBERS} ${1} ${INTEGER} ${3.14}
&{MAPPING} one=${1} two=${2} three=${3}
@{ANIMALS} cat dog
&{FINNISH} cat=kissa dog=koira
```
Note
Variables are not replaced in strings got from variable files. For example, `VAR = "an ${example}"` would create variable `${VAR}` with a literal string value `an ${example}` regardless would variable `${example}` exist or not.
##### Using objects as values
Variables in variable files are not limited to having only strings or other base types as values like Variable sections. Instead, their variables can contain any objects. In the example below, the variable `${MAPPING}` contains 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 *`.
The third option to select what variables are actually created is using a special `get_variables` function discussed below.
#### [Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-392)
An alternative approach for getting variables is having a special `get_variables` function (also camelCase syntax `getVariables` is possible) in a variable file. If such a function exists, Robot Framework calls it and expects to receive variables as a Python dictionary with variable names as keys and variable values as values. Created variables can be used as scalars, lists, and dictionaries exactly like when [getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module), and it is possible to use `LIST__` and `DICT__` prefixes to make creating list and dictionary variables more explicit. The example below is functionally identical to the first example related to [getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module).
```
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],
"MAPPING": {"one": 1, "two": 2, "three": 3}}
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use), arguments are specified after the path to the variable file, and in the command line they are separated from the path with a colon or a semicolon.
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
```
Starting from Robot Framework 7.0, arguments to variable files support automatic argument conversion as well as named argument syntax. For example, a variable file with `get_variables(first: int = 0, second: str = '')` could be imported like this:
```
*** Settings ***
Variables example.py 42 # Converted to integer.
Variables example.py second=value # Named argument syntax.
```
#### [Implementing variable file as a class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-393)
It is possible to implement variables files also as a class.
##### Implementation
Because variable files are always imported using a file system path, the class must have the same name as the module it is located in.
The framework will create an instance of the class using no arguments and variables will be gotten from the instance. Similarly as with modules, variables can be defined as attributes directly in the instance or gotten from a special `get_variables` method.
When variables are defined directly in an instance, all attributes containing callable values are ignored to avoid creating variables from possible methods the instance has. If you would actually need callable variables, you need to use other approaches to create variable files.
##### Examples
The first examples create variables from attributes. It creates variables `${VARIABLE}` and `@{LIST}` from class attributes and `${ANOTHER VARIABLE}` from an instance attribute.
```
class StaticExample:
variable = 'value'
LIST__list = [1, 2, 3]
_not_variable = 'starts with an underscore'
def __init__(self):
self.another_variable = 'another value'
```
The second examples utilizes dynamic approach for getting variables. It creates only one variable `${DYNAMIC VARIABLE}`.
```
class DynamicExample:
def get_variables(self, *args):
return {'dynamic variable': ' '.join(args)}
```
#### [Variable file as YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-394)
Variable files can also be implemented as [YAML](https://yaml.org/) files. YAML is a data serialization language with a simple and human-friendly syntax that is nevertheless easy for machines to parse. The following example demonstrates a simple YAML file:
```
string: Hello, world!
integer: 42
list:
- one
- two
dict:
one: yksi
two: kaksi
with spaces: kolme
```
YAML variable files can be used exactly like normal variable files from the command line using \--variablefile option, in the Settings section using Variables setting, and dynamically using the Import Variables keyword. They are automatically recognized by their extension that must be either .yaml or .yml. If the above YAML file is imported, it will create exactly the same variables as this Variable section:
```
*** Variables ***
${STRING} Hello, world!
${INTEGER} ${42}
@{LIST} one two
&{DICT} one=yksi two=kaksi with spaces=kolme
```
YAML files used as variable files must always be mappings on the top level. As the above example demonstrates, keys and values in the mapping become variable names and values, respectively. Variable values can be any data types supported by YAML syntax. If names or values contain non-ASCII characters, YAML variables files must be UTF-8 encoded.
Mappings used as values are automatically converted to special dictionaries that are used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Most importantly, values of these dictionaries are accessible as attributes like `${DICT.one}`, assuming their names are valid as Python attribute names. If the name contains spaces or is otherwise not a valid attribute name, it is always possible to access dictionary values using syntax like `${DICT}[with spaces]` syntax.
Note
Using YAML files with Robot Framework requires [PyYAML](http://pyyaml.org/) module to be installed. You can typically install it with [pip](https://pip.pypa.io/) like `pip install pyyaml`.
#### [Variable file as JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-395)
Variable files can also be implemented as [JSON](https://json.org/) files. Similarly as YAML discussed in the previous section, JSON is a data serialization format targeted both for humans and machines. It is based on JavaScript syntax and it is not as human-friendly as YAML, but it still relatively easy to understand and modify. The following example contains exactly the same data as the earlier YAML example:
```
{
"string": "Hello, world!",
"integer": 42,
"list": [
"one",
"two"
],
"dict": {
"one": "yksi",
"two": "kaksi",
"with spaces": "kolme"
}
}
```
JSON variable files are automatically recognized by their .json extension and they can be used exactly like YAML variable files. They also have exactly same requirements for structure, encoding, and so on. Unlike YAML, Python supports JSON out-of-the-box so no extra modules need to be installed.
Note
Support for JSON variable files is new in Robot Framework 6.1.
## [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-257)
This section describes various structures that can be used to control the test execution flow. These structures are familiar from most programming languages and they allow conditional execution, repeatedly executing a block of keywords and fine-grained error handling. For readability reasons these structures should be used judiciously, and more complex use cases should be preferably implemented in [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries).
- [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops)
- [Simple `FOR` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-for-loop)
- [Old `FOR` loop syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#old-for-loop-syntax)
- [Nesting `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nesting-for-loops)
- [Using several loop variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-several-loop-variables)
- [`FOR-IN-RANGE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-range-loop)
- [`FOR-IN-ENUMERATE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-enumerate-loop)
- [`FOR-IN-ZIP` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-zip-loop)
- [Dictionary iteration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-iteration)
- [Loop variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-variable-conversion)
- [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-unnecessary-keywords-from-outputs)
- [Repeating single keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#repeating-single-keyword)
- [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops)
- [Basic `WHILE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-while-syntax)
- [Limiting `WHILE` loop iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-while-loop-iterations)
- [Nesting `WHILE` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nesting-while-loops)
- [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-unnecessary-keywords-from-outputs-1)
- [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-control-using-break-and-continue)
- [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-syntax)
- [Basic `IF` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-if-syntax)
- [`ELSE` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#else-branches)
- [`ELSE IF` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#else-if-branches)
- [Inline `IF`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if-1)
- [Nested `IF` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nested-if-structures)
- [Other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-execute-keywords-conditionally)
- [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax)
- [Catching exceptions with `EXCEPT`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#catching-exceptions-with-except)
- [Matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#matching-errors-using-patterns)
- [Capturing error message](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#capturing-error-message)
- [Using `ELSE` to execute keywords when there are no errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-else-to-execute-keywords-when-there-are-no-errors)
- [Using `FINALLY` to execute keywords regardless are there errors or not](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-finally-to-execute-keywords-regardless-are-there-errors-or-not)
- [Other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-handle-errors)
- [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-syntax)
- [`GROUP` with templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-with-templates)
- [Programmatic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-usage)
### [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-396)
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 supported also by various other programming languages.
#### [Simple `FOR` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-397)
In a normal `FOR` loop, one variable is assigned based on a list of values, one value per iteration. The syntax starts with `FOR` (case-sensitive) as a marker, then the loop variable, then a mandatory `IN` (case-sensitive) as a separator, and finally the values to iterate. These values can contain [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), including [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables).
The keywords used in the `FOR` loop are on the following rows and the loop ends with `END` (case-sensitive) on its own row. Keywords inside the loop do not need to be indented, but that is highly recommended to make the syntax easier to read.
```
*** Test Cases ***
Example
FOR ${animal} IN cat dog
Log ${animal}
Log 2nd keyword
END
Log Outside loop
Second Example
FOR ${var} IN one two ${3} four ${five}
... kuusi 7 eight nine ${last}
Log ${var}
END
```
The `FOR` loop in Example 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 two rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) and the loop is run altogether ten times.
It is often convenient to use `FOR` loops with [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables). This is illustrated by the example below, where `@{ELEMENTS}` contains an arbitrarily long list of elements and keyword Start Element is used with all of them one by one.
```
*** Test Cases ***
Example
FOR ${element} IN @{ELEMENTS}
Start Element ${element}
END
```
#### [Old `FOR` loop syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-398)
Prior to Robot Framework 3.1, the `FOR` loop syntax was different than nowadays. The marker to start the loop was `:FOR` instead of `FOR` and loop contents needed to be explicitly marked with a backslash instead of using the `END` marker to end the loop. The first example above would look like this using the old syntax:
```
*** Test Cases ***
Example
:FOR ${animal} IN cat dog
\ Log ${animal}
\ Log 2nd keyword
Log Outside loop
```
The old syntax was deprecated in Robot Framework 3.2 and the support for it was removed altogether in Robot Framework 4.0.
#### [Nesting `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-399)
Starting from Robot Framework 4.0, it is possible to use nested `FOR` loops simply by adding a loop inside another loop:
```
*** Keywords ***
Handle Table
[Arguments] @{table}
FOR ${row} IN @{table}
FOR ${cell} IN @{row}
Handle Cell ${cell}
END
END
```
There can be multiple nesting levels and loops can also be combined with other control structures:
```
*** Test Cases ***
Multiple nesting levels
FOR ${root} IN r1 r2
FOR ${child} IN c1 c2 c3
FOR ${grandchild} IN g1 g2
Log Many ${root} ${child} ${grandchild}
END
END
FOR ${sibling} IN s1 s2 s3
IF '${sibling}' != 's2'
Log Many ${root} ${sibling}
END
END
END
```
#### [Using several loop variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-400)
It is possible to iterate over multiple values in one iteration by using multiple loop variables between the `FOR` and `IN` markers. There can be any number of loop variables, but the number of values must be evenly dividable by the number of variables. Each iteration consumes as many values as there are variables.
If there are lot of values to iterate, it is often convenient to organize them below the loop variables, as in the first loop of the example below:
```
*** Test Cases ***
Multiple loop variables
FOR ${index} ${english} ${finnish} IN
... 1 cat kissa
... 2 dog koira
... 3 horse hevonen
Add Translation ${english} ${finnish} ${index}
END
FOR ${name} ${id} IN @{EMPLOYERS}
Create ${name} ${id}
END
```
#### [`FOR-IN-RANGE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-401)
All `FOR` loops in the previous section iterated over a sequence. That is the most common use case, but sometimes it is convenient to have a loop that is executed a certain number of times. For this purpose Robot Framework has a special `FOR index IN RANGE limit` loop syntax that is derived from the similar Python idiom using the [built-in range() function](http://docs.python.org/library/functions.html#func-range).
Similarly as other `FOR` loops, the `FOR-IN-RANGE` loop starts with `FOR` that is followed by a loop variable. In this format there can be only one loop variable and it contains the current loop index. After the variable there must be `IN RANGE` marker (case-sensitive) that is followed by loop limits.
In the simplest case, only the upper limit of the loop is specified. In this case, loop indices 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 indices 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.
It is possible to use simple arithmetic such as addition and subtraction with the range limits. This is especially useful when the limits are specified with variables. Start, end and step are typically given as integers, but using float values is possible as well.
```
*** Test Cases ***
Only upper limit
[Documentation] Loops over values from 0 to 9.
FOR ${index} IN RANGE 10
Log ${index}
END
Start and end
[Documentation] Loops over values from 1 to 10.
FOR ${index} IN RANGE 1 11
Log ${index}
END
Also step given
[Documentation] Loops over values 5, 15, and 25.
FOR ${index} IN RANGE 5 26 10
Log ${index}
END
Negative step
[Documentation] Loops over values 13, 3, and -7.
FOR ${index} IN RANGE 13 -13 -10
Log ${index}
END
Arithmetic
[Documentation] Arithmetic with variable.
FOR ${index} IN RANGE ${var} + 1
Log ${index}
END
Float parameters
[Documentation] Loops over values 3.14, 4.34, and 5.54.
FOR ${index} IN RANGE 3.14 6.09 1.2
Log ${index}
END
```
#### [`FOR-IN-ENUMERATE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-402)
Sometimes it is useful to loop over a list and also keep track of your location inside the list. Robot Framework has a special `FOR index ... IN ENUMERATE ...` syntax for this situation. This syntax is derived from the [Python built-in enumerate() function](http://docs.python.org/library/functions.html#enumerate).
`FOR-IN-ENUMERATE` loops syntax is just like the regular `FOR` loop syntax, except that the separator between variables and values is `IN ENUMERATE` (case-sensitive). Typically they are used so that there is an additional index variable before any other loop-variables. By default the index has a value `0` on the first iteration, `1` on the second, and so on.
For example, the following two test cases do the same thing:
```
*** Variables ***
@{LIST} a b c
*** Test Cases ***
Manage index manually
${index} = Set Variable -1
FOR ${item} IN @{LIST}
${index} = Evaluate ${index} + 1
My Keyword ${index} ${item}
END
FOR-IN-ENUMERATE
FOR ${index} ${item} IN ENUMERATE @{LIST}
My Keyword ${index} ${item}
END
```
Starting from Robot Framework 4.0, it is possible to specify a custom start index by using `start=<index>` syntax as the last item of the `FOR ... IN ENUMERATE ...` header:
```
*** Variables ***
@{LIST} a b c
${START} 10
*** Test Cases ***
FOR-IN-ENUMERATE with start
FOR ${index} ${item} IN ENUMERATE @{LIST} start=1
My Keyword ${index} ${item}
END
Start as variable
FOR ${index} ${item} IN ENUMERATE @{LIST} start=${start}
My Keyword ${index} ${item}
END
```
The `start=<index>` syntax must be explicitly used in the `FOR` header and it cannot itself come from a variable. If the last actual item to enumerate would start with `start=`, it needs to be escaped like `start\=`.
Just like with regular `FOR` loops, you can loop over multiple values per loop iteration as long as the number of values in your list is evenly divisible by the number of loop-variables (excluding the index variable):
```
*** Test Cases ***
FOR-IN-ENUMERATE with two values per iteration
FOR ${index} ${en} ${fi} IN ENUMERATE
... cat kissa
... dog koira
... horse hevonen
Log "${en}" in English is "${fi}" in Finnish (index: ${index})
END
```
If you only use one loop variable with `FOR-IN-ENUMERATE` loops, that variable will become a Python tuple containing the index and the iterated value:
```
*** Test Cases ***
FOR-IN-ENUMERATE with one loop variable
FOR ${x} IN ENUMERATE @{LIST}
Length Should Be ${x} 2
Log Index is ${x}[0] and item is ${x}[1].
END
```
Note
`FOR-IN-ENUMERATE` loops with only one loop variable is a new feature in Robot Framework 3.2.
#### [`FOR-IN-ZIP` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-403)
Some tests build up several related lists, then loop over them together. Robot Framework has a shortcut for this case: `FOR ... IN ZIP ...`, which is derived from the [Python built-in zip() function](http://docs.python.org/library/functions.html#zip).
This may be easiest to show with an example:
```
*** Variables ***
@{NUMBERS} ${1} ${2} ${5}
@{NAMES} one two five
*** Test Cases ***
Iterate over two lists manually
${length}= Get Length ${NUMBERS}
FOR ${index} IN RANGE ${length}
Log Many ${NUMBERS}[${index}] ${NAMES}[${index}]
END
FOR-IN-ZIP
FOR ${number} ${name} IN ZIP ${NUMBERS} ${NAMES}
Log Many ${number} ${name}
END
```
As the example above illustrates, `FOR-IN-ZIP` loops require their own custom separator `IN ZIP` (case-sensitive) between loop variables and values. Values used with `FOR-IN-ZIP` loops must be lists or list-like objects.
Items to iterate over must always be given either as [scalar variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables) like `${items}` or as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) like `@{lists}` that yield the actual iterated lists. The former approach is more common and it was already demonstrated above. The latter approach works like this:
```
*** Variables ***
@{NUMBERS} ${1} ${2} ${5}
@{NAMES} one two five
@{LISTS} ${NUMBERS} ${NAMES}
*** Test Cases ***
FOR-IN-ZIP with lists from variable
FOR ${number} ${name} IN ZIP @{LISTS}
Log Many ${number} ${name}
END
```
The number of lists to iterate over is not limited, but it must match the number of loop variables. Alternatively, there can be just one loop variable that then becomes a Python tuple getting items from all lists.
```
*** Variables ***
@{ABC} a b c
@{XYZ} x y z
@{NUM} 1 2 3
*** Test Cases ***
FOR-IN-ZIP with multiple lists
FOR ${a} ${x} ${n} IN ZIP ${ABC} ${XYZ} ${NUM}
Log Many ${a} ${x} ${n}
END
FOR-IN-ZIP with one variable
FOR ${items} IN ZIP ${ABC} ${XYZ} ${NUM}
Length Should Be ${items} 3
Log Many ${items}[0] ${items}[1] ${items}[2]
END
```
Starting from Robot Framework 6.1, it is possible to configure what to do if lengths of the iterated items differ. By default, the shortest item defines how many iterations there are and values at the end of longer ones are ignored. This can be changed by using the `mode` option that has three possible values:
- `STRICT`: Items must have equal lengths. If not, execution fails. This is the same as using `strict=True` with Python's [zip](https://docs.python.org/library/functions.html#zip) function.
- `SHORTEST`: Items in longer items are ignored. Infinite iterators are supported in this mode as long as one of the items is exhausted. This is the default behavior.
- `LONGEST`: The longest item defines how many iterations there are. Missing values in shorter items are filled-in with value specified using the `fill` option or `None` if it is not used. This is the same as using Python's [zip\_longest](https://docs.python.org/library/itertools.html#itertools.zip_longest) function except that it has `fillvalue` argument instead of `fill`.
All these modes are illustrated by the following examples:
```
*** Variables ***
@{CHARACTERS} a b c d f
@{NUMBERS} 1 2 3
*** Test Cases ***
STRICT mode
[Documentation] This loop fails due to lists lengths being different.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=STRICT
Log ${c}: ${n}
END
SHORTEST mode
[Documentation] This loop executes three times.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=SHORTEST
Log ${c}: ${n}
END
LONGEST mode
[Documentation] This loop executes five times.
... On last two rounds `${n}` has value `None`.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=LONGEST
Log ${c}: ${n}
END
LONGEST mode with custom fill value
[Documentation] This loop executes five times.
... On last two rounds `${n}` has value `0`.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=LONGEST fill=0
Log ${c}: ${n}
END
```
Note
The behavior if list lengths differ will change in the future so that the `STRICT` mode will be the default. If that is not desired, the `SHORTEST` mode needs to be used explicitly.
#### [Dictionary iteration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-404)
Normal `FOR` loops and `FOR-IN-ENUMERATE` loops support iterating over keys and values in dictionaries. This syntax requires at least one of the loop values to be a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable). It is possible to use multiple dictionary variables and to give additional items in `key=value` syntax. Items are iterated in the order they are defined and if same key gets multiple values the last value will be used.
```
*** Variables ***
&{DICT} a=1 b=2 c=3
*** Test Cases ***
Dictionary iteration with FOR loop
FOR ${key} ${value} IN &{DICT}
Log Key is '${key}' and value is '${value}'.
END
Dictionary iteration with FOR-IN-ENUMERATE loop
FOR ${index} ${key} ${value} IN ENUMERATE &{DICT}
Log On round ${index} key is '${key}' and value is '${value}'.
END
Multiple dictionaries and extra items in 'key=value' syntax
&{more} = Create Dictionary e=5 f=6
FOR ${key} ${value} IN &{DICT} d=4 &{more} g=7
Log Key is '${key}' and value is '${value}'.
END
```
Typically it is easiest to use the dictionary iteration syntax so that keys and values get separate variables like in the above examples. With normal `FOR` loops it is also possible to use just a single variable that will become a tuple containing the key and the value. If only one variable is used with `FOR-IN-ENUMERATE` loops, it becomes a tuple containing the index, the key and the value. Two variables with `FOR-IN-ENUMERATE` loops means assigning the index to the first variable and making the second variable a tuple containing the key and the value.
```
*** Test Cases ***
One loop variable
FOR ${item} IN &{DICT}
Log Key is '${item}[0]' and value is '${item}[1]'.
END
One loop variable with FOR-IN-ENUMERATE
FOR ${item} IN ENUMERATE &{DICT}
Log On round ${item}[0] key is '${item}[1]' and value is '${item}[2]'.
END
Two loop variables with FOR-IN-ENUMERATE
FOR ${index} ${item} IN ENUMERATE &{DICT}
Log On round ${index} key is '${item}[0]' and value is '${item}[1]'.
END
```
In addition to iterating over names and values in dictionaries, it is possible to iterate over keys and then possibly fetch the value based on it. This syntax requires using dictionaries as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables):
```
*** Test Cases ***
Iterate over keys
FOR ${key} IN @{DICT}
Log Key is '${key}' and value is '${DICT}[${key}]'.
END
```
Note
Iterating over keys and values in dictionaries is a new feature in Robot Framework 3.2. With earlier version it is possible to iterate over dictionary keys like the last example above demonstrates.
#### [Loop variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-405)
[Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) works also with FOR loop variables. The desired type can be added to any loop variable by using the familiar `${name: type}` syntax.
```
*** Test Cases ***
Variable conversion
FOR ${value: bytes} IN Hello! Hyvä! \x00\x00\x07
Log ${value} formatter=repr
END
FOR ${index} ${date: date} IN ENUMERATE 2023-06-15 2025-05-30 today
Log ${date} formatter=repr
END
FOR ${item: tuple[str, date]} IN ENUMERATE 2023-06-15 2025-05-30 today
Log ${item} formatter=repr
END
```
Note
Variable type conversion is new in Robot Framework 7.3.
#### [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-406)
`FOR` loops with multiple iterations often create lots of output and considerably increase the size of the generated [output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) files. It is possible to [remove or flatten unnecessary keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) using \--removekeywords and \--flattenkeywords command line options.
#### [Repeating single keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-407)
`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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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.
```
*** Test Cases ***
Example
Repeat Keyword 5 Some Keyword arg1 arg2
Repeat Keyword 42 times My Keyword
Repeat Keyword ${var} Another Keyword argument
```
### [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-408)
`WHILE` loops combine features of [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) and [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures). They specify a condition and repeat the loop body as long as the condition remains true. This can be utilised, for example, to repeat a nondeterministic sequence until the desired outcome happens, or in some cases they can be used as an alternative to [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops).
Note
`WHILE` loops are new in Robot Framework 5.0.
#### [Basic `WHILE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-409)
```
*** Test Cases ***
Example
VAR ${rc} 1
WHILE ${rc} != 0
${rc} = Keyword that returns zero on success
END
```
The `WHILE` loop condition is evaluated in Python so that Python builtins like `len()` are available and modules are imported automatically to support usages like `math.pi * math.pow(${radius}, 2) < 10`. Normal variables like `${rc}` in the above example are replaced before evaluation, but variables are also available in the evaluation namespace using the special `$rc` syntax. The latter approach is handy when the string representation of the variable cannot be used in the condition directly. For example, strings require quoting and multiline strings and string themselves containing quotes cause additional problems. See the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix for more information and examples related to the evaluation syntax.
Starting from Robot Framework 6.1, the condition in a `WHILE` statement can be omitted. This is interpreted as the condition always being true, which may be useful with the `limit` option described below.
#### [Limiting `WHILE` loop iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-410)
With `WHILE` loops, there is always a possibility to achieve an infinite loop, either by intention or by mistake. This happens when the loop condition never becomes false. While infinite loops have some utility in application programming, in automation an infinite loop is rarely a desired outcome. If such a loop occurs with Robot Framework, the execution must be forcefully stopped and no log or report can be created. For this reason, `WHILE` loops in Robot Framework have a default limit of 10 000 iterations. If the limit is exceeded, the loop fails.
The limit can be set with the `limit` configuration parameter either as a maximum iteration count or as a maximum time for the whole loop. When the limit is an iteration count, it is possible to use just integers like `100` and to add `times` or `x` suffix after the value like `100 times`. When the limit is a timeout, it is possible to use [time strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format) like `10 s` or `1 hour 10 minutes`. The limit can also be disabled altogether by using `NONE` (case-insensitive). All these options are illustrated by the examples below.
```
*** Test Cases ***
Limit as iteration count
WHILE True limit=100
Log This is run 100 times.
END
WHILE True limit=10 times
Log This is run 10 times.
END
WHILE True limit=42x
Log This is run 42 times.
END
Limit as time
WHILE True limit=10 seconds
Log This is run 10 seconds.
END
No limit
WHILE True limit=NONE
Log This runs forever.
END
```
Note
Support for using `times` and `x` suffixes with iteration counts is new in Robot Framework 7.0.
Keywords in a loop are not forcefully stopped if the limit is exceeded. Instead the loop is exited similarly as if the loop condition would have become false. A major difference is that the loop status will be `FAIL` in this case.
Starting from Robot Framework 6.1, it is possible to use `on_limit` parameter to configure the behaviour when the limit is exceeded. It supports two values `pass` and `fail`, case insensitively. If the value is `pass`, the execution will continue normally when the limit is reached and the status of the `WHILE` loop will be `PASS`. The value `fail` works similarly as the default behaviour, e.g. the loop and the test will fail if the limit is exceeded.
```
*** Test Cases ***
Continue when iteration limit is reached
WHILE True limit=5 on_limit=pass
Log Loop will be executed five times
END
Log This will be executed normally.
Continue when time limit is reached
WHILE True limit=10s on_limit=pass
Log Loop will be executed for 10 seconds.
Sleep 0.5s
END
Log This will be executed normally.
```
By default, the error message raised when the limit is reached is . Starting from Robot Framework 6.1, the error message can be changed with the `on_limit_message` configuration parameter.
```
*** Test Cases ***
Limit as iteration count
WHILE True limit=0.5s on_limit_message=Custom While loop error message
Log This is run 0.5 seconds.
END
```
Note
`on_limit_message` configuration parameter is new in Robot Framework 6.1.
#### [Nesting `WHILE` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-411)
`WHILE` loops can be nested and also combined with other control structures:
```
*** Test Cases ***
Nesting WHILE
VAR ${x} 10
WHILE ${x} > 0
VAR ${y} ${x}
WHILE ${y} > 0
${y} = Evaluate ${y} - 1
END
IF ${x} > 5
${x} = Evaluate ${x} - 1
ELSE
${x} = Evaluate ${x} - 2
END
END
```
#### [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-412)
`WHILE` loops with multiple iterations often create lots of output and considerably increase the size of the generated [output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) files. It is possible to [remove or flatten unnecessary keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) using \--removekeywords and \--flattenkeywords command line options.
### [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-413)
Both [FOR](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for) and [WHILE](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while) loop execution can be controlled with `BREAK` and `CONTINUE` statements. The former exits the whole loop prematurely and the latter stops executing the current loop iteration and continues to the next one. In practice they have the same semantics as `break` and `continue` statements in Python, Java, and many other programming languages.
Both `BREAK` and `CONTINUE` are typically used conditionally with [IF/ELSE](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else) or [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except) structures, and especially the [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) syntax is often convenient with them. These statements must be used in the loop body, possibly inside the aforementioned control structures, and using them in keyword called in the loop body is invalid.
```
*** Test Cases ***
BREAK with FOR
${text} = Set Variable zero
FOR ${var} IN one two three
IF '${var}' == 'two' BREAK
${text} = Set Variable ${text}-${var}
END
Should Be Equal ${text} zero-one
CONTINUE with FOR
${text} = Set Variable zero
FOR ${var} IN one two three
IF '${var}' == 'two' CONTINUE
${text} = Set Variable ${text}-${var}
END
Should Be Equal ${text} zero-one-three
CONTINUE and BREAK with WHILE
WHILE True
TRY
${value} = Do Something
EXCEPT
CONTINUE
END
Do something with value ${value}
BREAK
END
Invalid BREAK usage
[Documentation] BREAK and CONTINUE can only be used in the loop body,
... not in keywords used in the loop.
FOR ${var} IN one two three
Invalid BREAK
END
*** Keywords ***
Invalid BREAK
[Documentation] This keyword fails due to invalid syntax.
BREAK
```
Note
`BREAK` and `CONTINUE` statements are new in Robot Framework 5.0 similarly as `WHILE`. Earlier versions supported controlling `FOR` loops using [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Exit For Loop, Exit For Loop If, Continue For Loop and Continue For Loop If. These keywords still continue to work, but they will be deprecated and removed in the future.
Note
Also the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement can be used to a exit loop. It only works when loops are used inside a [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords).
### [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-414)
Sometimes there is a need to execute some keywords conditionally. Starting from Robot Framework 4.0 there is a separate `IF/ELSE` syntax, but there are also [other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-execute-keywords-conditionally). Notice that if the logic gets complicated, it is typically better to move it into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries).
#### [Basic `IF` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-415)
Robot Framework's native `IF` syntax starts with `IF` (case-sensitive) and ends with `END` (case-sensitive). The `IF` marker requires exactly one value that is the condition to evaluate. Keywords to execute if the condition is true are on their own rows between the `IF` and `END` markers. Indenting keywords in the `IF` block is highly recommended but not mandatory.
In the following example keywords Some keyword and Another keyword are executed if `${rc}` is greater than zero:
```
*** Test Cases ***
Example
IF ${rc} > 0
Some keyword
Another keyword
END
```
The condition is evaluated in Python so that Python builtins like `len()` are available and modules are imported automatically to support usages like `platform.system() == 'Linux'` and `math.ceil(${x}) == 1`. Normal variables like `${rc}` in the above example are replaced before evaluation, but variables are also available in the evaluation namespace using the special `$rc` syntax. The latter approach is handy when the string representation of the variable cannot be used in the condition directly. For example, strings require quoting and multiline strings and string themselves containing quotes cause additional problems. For more information and examples related the evaluation syntax see the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix.
#### [`ELSE` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-416)
Like most other languages supporting conditional execution, Robot Framework `IF` syntax also supports `ELSE` branches that are executed if the `IF` condition is not true.
In this example Some keyword is executed if `${rc}` is greater than zero and Another keyword is executed otherwise:
```
*** Test Cases ***
Example
IF ${rc} > 0
Some keyword
ELSE
Another keyword
END
```
#### [`ELSE IF` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-417)
Robot Framework also supports `ELSE IF` branches that have their own condition that is evaluated if the initial condition is not true. There can be any number of `ELSE IF` branches and they are gone through in the order they are specified. If one of the `ELSE IF` conditions is true, the block following it is executed and remaining `ELSE IF` branches are ignored. An optional `ELSE` branch can follow `ELSE IF` branches and it is executed if all conditions are false.
In the following example different keyword is executed depending on is `${rc}` positive, negative, zero, or something else like a string or `None`:
```
*** Test Cases ***
Example
IF $rc > 0
Positive keyword
ELSE IF $rc < 0
Negative keyword
ELSE IF $rc == 0
Zero keyword
ELSE
Fail Unexpected rc: ${rc}
END
```
Notice that this example uses the `${rc}` variable in the special `$rc` format to avoid evaluation failures if it is not a number. See the aforementioned [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix for more information about this syntax.
#### [Inline `IF`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-418)
Normal `IF/ELSE` structure is a bit verbose if there is a need to execute only a single statement. An alternative to it is using inline `IF` syntax where the statement to execute follows the `IF` marker and condition directly and no `END` marker is needed. For example, the following two keywords are equivalent:
```
*** Keywords ***
Normal IF
IF $condition1
Keyword argument
END
IF $condition2
RETURN
END
Inline IF
IF $condition1 Keyword argument
IF $condition2 RETURN
```
The inline `IF` syntax supports also `ELSE` and `ELSE IF` branches:
```
*** Keywords ***
Inline IF/ELSE
IF $condition Keyword argument ELSE Another Keyword
Inline IF/ELSE IF/ELSE
IF $cond1 Keyword 1 ELSE IF $cond2 Keyword 2 ELSE IF $cond3 Keyword 3 ELSE Keyword 4
```
As the latter example above demonstrates, inline `IF` with several `ELSE IF` and `ELSE` branches starts to get hard to understand. Long inline `IF` structures can be [split into multiple lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) using the common `...` continuation syntax, but using a normal `IF/ELSE` structure or moving the logic into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) is probably a better idea. Each inline `IF` branch can contain only one statement. If more statements are needed, normal `IF/ELSE` structure needs to be used instead.
If there is a need for an assignment with inline `IF`, the variable or variables to assign must be before the starting `IF`. Otherwise the logic is exactly the same as when [assigning variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) based on keyword return values. If assignment is used and no branch is run, the variable gets value `None`.
```
*** Keywords ***
Inline IF/ELSE with assignment
${var} = IF $condition Keyword argument ELSE Another Keyword
Inline IF/ELSE with assignment having multiple variables
${host} ${port} = IF $production Get Production Config ELSE Get Testing Config
```
Note
Inline `IF` syntax is new in Robot Framework 5.0.
#### [Nested `IF` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-419)
`IF` structures can be nested with each others and with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). This is illustrated by the following example using advanced features such as [FOR-IN-ENUMERATE loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-enumerate-loop), [named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords) and [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) syntax (`${{len(${items})}}`):
```
*** Keywords ***
Log items
[Arguments] @{items} ${log_values}=True
IF not ${items}
Log to console No items.
ELSE IF len(${items}) == 1
IF ${log_values}
Log to console One item: ${items}[0]
ELSE
Log to console One item.
END
ELSE
Log to console ${{len(${items})}} items.
IF ${log_values}
FOR ${index} ${item} IN ENUMERATE @{items} start=1
Log to console Item ${index}: ${item}
END
END
END
*** Test Cases ***
No items
Log items
One item without logging value
Log items xxx log_values=False
Multiple items
Log items a b c
```
#### [Other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-420)
There are also other methods to execute keywords conditionally:
- The name of the keyword used as a setup or a teardown with [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown), [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown) can be specified using a variable. This facilitates changing them, for example, from the command line.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Run Keyword If and Run Keyword Unless execute a named keyword only if a certain expression is true or false, respectively. The new `IF/ELSE` syntax explained above is generally recommended, though.
- Another [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword, Set Variable If, can be used to set variables dynamically based on a given expression.
- There are several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords that allow executing a named keyword only if a test case or test suite has failed or passed.
### [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-421)
When a keyword fails, Robot Framework's default behavior is to stop the current test and executes its possible [teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). There can, however, be needs to handle these failures during execution as well. Robot Framework 5.0 introduces native `TRY/EXCEPT` syntax for this purpose, but there also [other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-handle-errors).
Robot Framework's `TRY/EXCEPT` syntax is inspired by Python's [exception handling](https://docs.python.org/tutorial/errors.html#handling-exceptions) syntax. It has same `TRY`, `EXCEPT`, `ELSE` and `FINALLY` branches as Python and they also mostly work the same way. A difference is that Python uses lower case `try`, `except`, etc. but with Robot Framework all this kind of syntax must use upper case letters. A bigger difference is that with Python exceptions are objects and with Robot Framework you are dealing with error messages as strings.
Note
It is not possible to catch errors caused by invalid syntax or errors that [stop the whole execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully).
#### [Catching exceptions with `EXCEPT`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-422)
The basic `TRY/EXCEPT` syntax can be used to handle failures based on error messages:
```
*** Test Cases ***
First example
TRY
Some Keyword
EXCEPT Error message
Error Handler Keyword
END
Keyword Outside
```
In the above example, if `Some Keyword` passes, the `EXCEPT` branch is not run and execution continues after the `TRY/EXCEPT` structure. If the keyword fails with a message `Error message` (case-sensitive), the `EXCEPT` branch is executed. If the `EXCEPT` branch succeeds, execution continues after the `TRY/EXCEPT` structure. If it fails, the test fails and remaining keywords are not executed. If `Some Keyword` fails with any other exception, that failure is not handled and the test fails without executing remaining keywords.
There can be more than one `EXCEPT` branch. In that case they are matched one by one and the first matching branch is executed. One `EXCEPT` can also have multiple messages to match, and such a branch is executed if any of its messages match. In all these cases messages can be specified using variables in addition to literal strings.
```
*** Test Cases ***
Multiple EXCEPT branches
TRY
Some Keyword
EXCEPT Error message # Try matching this first.
Error Handler 1
EXCEPT Another error # Try this if above did not match.
Error Handler 2
EXCEPT ${message} # Last match attempt, this time using a variable.
Error Handler 3
END
Multiple messages with one EXCEPT
TRY
Some Keyword
EXCEPT Error message Another error ${message} # Match any of these.
Error handler
END
```
It is also possible to have an `EXCEPT` without messages, in which case it matches any error. There can be only one such `EXCEPT` and it must follow possible other `EXCEPT` branches:
```
*** Test Cases ***
Match any error
TRY
Some Keyword
EXCEPT # Match any error.
Error Handler
END
Match any after testing more specific errors
TRY
Some Keyword
EXCEPT Error message # Try matching this first
Error Handler 1
EXCEPT # Match any that did not match the above.
Error Handler 2
END
```
#### [Matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-423)
By default matching an error using `EXCEPT` requires an exact match. That can be changed using a configuration option `type=` as an argument to the except clause. Valid values for the option are `GLOB`, `REGEXP` or `START` (case-insensitive) to make the match a [glob pattern match](https://en.wikipedia.org/wiki/Glob_\(programming\)), a [regular expression match](https://en.wikipedia.org/wiki/Regular_expression), or to match only the beginning of the error, respectively. Using value `LITERAL` has the same effect as the default behavior. If an `EXCEPT` has multiple messages, this option applies to all of them. The value of the option can be defined with a variable as well.
```
*** Variables ***
${MATCH TYPE} regexp
*** Test Cases ***
Glob pattern
TRY
Some Keyword
EXCEPT ValueError: * type=GLOB
Error Handler 1
EXCEPT [Ee]rror ?? occurred ${pattern} type=glob
Error Handler 2
END
Regular expression
TRY
Some Keyword
EXCEPT ValueError: .* type=${MATCH TYPE}
Error Handler 1
EXCEPT [Ee]rror \\d+ occurred type=Regexp # Backslash needs to be escaped.
Error Handler 2
END
Match start
TRY
Some Keyword
EXCEPT ValueError: ${beginning} type=start
Error Handler
END
Explicit exact match
TRY
Some Keyword
EXCEPT ValueError: invalid literal for int() with base 10: 'ooops' type=LITERAL
Error Handler
EXCEPT Error 13 occurred type=LITERAL
Error Handler 2
END
```
Note
Remember that the backslash character often used with regular expressions is an [escape character](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) in Robot Framework data. It thus needs to be escaped with another backslash when using it in regular expressions.
#### [Capturing error message](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-424)
When [matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#matching-errors-using-patterns) and when using `EXCEPT` without any messages to match any error, it is often useful to know the actual error that occurred. Robot Framework supports that by making it possible to capture the error message into a variable by adding `AS ${var}` at the end of the `EXCEPT` statement:
```
*** Test Cases ***
Capture error
TRY
Some Keyword
EXCEPT ValueError: * type=GLOB AS ${error}
Error Handler 1 ${error}
EXCEPT [Ee]rror \\d+ (Invalid|Bad) usage type=REGEXP AS ${error}
Error Handler 2 ${error}
EXCEPT AS ${error}
Error Handler 3 ${error}
END
```
#### [Using `ELSE` to execute keywords when there are no errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-425)
Optional `ELSE` branches make it possible to execute keywords if there is no error. There can be only one `ELSE` branch and it is allowed only after one or more `EXCEPT` branches:
```
*** Test Cases ***
ELSE branch
TRY
Some Keyword
EXCEPT X
Log Error 'X' occurred!
EXCEPT Y
Log Error 'Y' occurred!
ELSE
Log No error occurred!
END
Keyword Outside
```
In the above example, if `Some Keyword` passes, the `ELSE` branch is executed, and if it fails with message `X` or `Y`, the appropriate `EXCEPT` branch run. In all these cases execution continues after the whole `TRY/EXCEPT/ELSE` structure. If `Some Keyword` fail any other way, `EXCEPT` and `ELSE` branches are not run and the `TRY/EXCEPT/ELSE` structure fails.
To handle both the case when there is any error and when there is no error, it is possible to use an `EXCEPT` without any message in combination with an `ELSE`:
```
*** Test Cases ***
Handle everything
TRY
Some Keyword
EXCEPT AS ${err}
Log Error occurred: ${err}
ELSE
Log No error occurred!
END
```
#### [Using `FINALLY` to execute keywords regardless are there errors or not](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-426)
Optional `FINALLY` branches make it possible to execute keywords both when there is an error and when there is not. They are thus suitable for cleaning up after a keyword execution somewhat similarly as [teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). There can be only one `FINALLY` branch and it must always be last. They can be used in combination with `EXCEPT` and `ELSE` branches and having also `TRY/FINALLY` structure is possible:
```
*** Test Cases ***
TRY/EXCEPT/ELSE/FINALLY
TRY
Some keyword
EXCEPT
Log Error occurred!
ELSE
Log No error occurred.
FINALLY
Log Always executed.
END
TRY/FINALLY
Open Connection
TRY
Use Connection
FINALLY
Close Connection
END
```
#### [Other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-427)
There are also other methods to execute keywords conditionally:
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Expect Error executes a named keyword and expects that it fails with a specified error message. It is basically the same as using `TRY/EXCEPT` with a specified message. The syntax to specify the error message is also identical except that this keyword uses glob pattern matching, not exact match, by default. Using the native `TRY/EXCEPT` functionality is generally recommended unless there is a need to support older Robot Framework versions that do not support it.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Ignore Error executes a named keyword and returns its status as string `PASS` or `FAIL` along with possible return value or error message. It is basically the same as using `TRY/EXCEPT/ELSE` so that `EXCEPT` catches all errors. Using the native syntax is recommended unless old Robot Framework versions need to be supported.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Return Status executes a named keyword and returns its status as a Boolean true or false. It is a wrapper for the aforementioned Run Keyword And Ignore Error. The native syntax is nowadays recommended instead.
- [Test teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [keyword teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) can be used for cleaning up activities similarly as `FINALLY` branches.
- When keywords are implemented in Python based [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries), all Python's error handling features are readily available. This is the recommended approach especially if needed logic gets more complicated.
### [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-428)
The `GROUP` syntax allows grouping related keywords and control structures together:
```
*** Test Cases ***
Valid login
GROUP Open browser to login page
Open Browser ${LOGIN URL}
Title Should Be Login Page
END
GROUP Submit credentials
Input Username username_field demo
Input Password password_field mode
Click Button login_button
END
GROUP Login should have succeeded
Title Should Be Welcome Page
END
Anonymous group
GROUP
Log Group name is optional.
END
Nesting
GROUP
GROUP Nested group
Log Groups can be nested.
END
IF True
GROUP
Log Groups can also be nested with other control structures.
END
END
END
```
As the above examples demonstrates, groups can have a name, but the name is optional. Groups can also be nested freely with each others and with other control structures.
[User keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) are in general recommended over the `GROUP` syntax, because they are reusable and because they simplify tests or keywords where they are used by hiding and encapsulating lower level details. In the log file user keywords and groups look the same, though, except that instead of a `KEYWORD` label there is a `GROUP` label.
All groups within a test or a keyword share the same variable namespace. This means that, unlike when using keywords, there is no need to use arguments or return values for sharing values. This can be a benefit in simple cases, but if there are lot of variables, the benefit can turn into a problem and cause a huge mess.
Note
The `GROUP` syntax is new in Robot Framework 7.2.
#### [`GROUP` with templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-429)
The `GROUP` syntax can be used for grouping iterations with [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates):
```
*** Settings ***
Library String
Test Template Upper case should be
*** Test Cases ***
Template example
GROUP ASCII characters
a A
z Z
END
GROUP Latin-1 characters
ä Ä
ß SS
END
GROUP Numbers
1 1
9 9
END
*** Keywords ***
Upper case should be
[Arguments] ${char} ${expected}
${actual} = Convert To Upper Case ${char}
Should Be Equal ${actual} ${expected}
```
#### [Programmatic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-430)
One of the primary usages for groups is making it possible to create structured tests and user keywords programmatically. For example, the following [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) adds a group with two keywords at the end of each modified test. Groups can be added also by [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) that use the [listener API version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
```
from robot.api import SuiteVisitor
class GroupAdder(SuiteVisitor):
def start_test(self, test):
group = test.body.create_group(name='Example')
group.body.create_keyword(name='Log', args=['Hello, world!'])
group.body.create_keyword(name='No Operation')
```
## [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-258)
- [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names)
- [Keyword scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-scopes)
- [Specifying a keyword explicitly](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-a-keyword-explicitly)
- [Specifying explicit priority between libraries and resources](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-explicit-priority-between-libraries-and-resources)
- [2\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts)
- [Test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout)
- [User keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout)
- [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parallel-execution-of-keywords)
### [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-431)
Keywords that are used with Robot Framework are either [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) or [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). The former come from [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) or [external libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries), and the latter are either created in the same file where they are used or then imported from [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-432)
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 currently executed [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-433)
Scopes do not help if keywords with same names exists in two different libraries or in two different resource files. In addition to that, scopes do not help if a keyword in library should be used instead of a keyword with the same name in a resource file. In such cases, it is possible to use *the full keyword name*, where the keyword name is prefixed with the name of a library or a resource and a dot is used as a separator.
With library keywords, the full name means using format LibraryName.Keyword Name. For example, the keyword Get File from the [OperatingSystem](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) library can be used as OperatingSystem.Get File, even if there was another Get File keyword somewhere else. If the library is implemented in a nested module, the full name must contain the full module name like root.sub.Library.Keyword. If a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) is given to a library when importing it, the specified name must be used also in the full keyword name.
With user keywords in resource files the full name is constructed the same way as with library keywords. The name of the resource is derived from the basename of the resource file without the file extension. For example, a keyword Some Keyword in a resource file example.resource can be used like example.Some Keyword. Note that this syntax does not work if several resource files have the same basename. In such cases, either resource files or keywords must be renamed.
With user keywords in a [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), the full name contains only the keyword name without any prefix.
When comparing full keyword names, the library/resource part is case and space-insensitive and the keyword part is case, space and underscore-insensitive.
#### [Specifying explicit priority between libraries and resources](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-434)
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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library.
Note
Although the keyword has the word *library* in its name, it works also with resource files. 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\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-435)
Sometimes keywords may take exceptionally long time to execute or just hang endlessly. Robot Framework allows you to set timeouts both for [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-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, the test environment or the 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.
#### [Test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-436)
The test case timeout can be set either by using the Test Timeout setting in the Setting section or the \[Timeout\] setting with individual test cases. Test Timeout defines a default timeout for all the test cases in that suite, whereas \[Timeout\] applies a timeout to a particular 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. It is also possible to use explicit `NONE` value for this purpose. The timeout is effectively ignored also if its value is zero or negative.
Regardless of where the test timeout is defined, the value given to it contains the duration of the timeout. The duration must be given in Robot Framework's [time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format), that is, either directly in seconds like `10` or in a format like `1 minute 30 seconds`. Timeouts can also be specified as [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) making it possible to give them, for example, from the command line.
If there is a timeout and it expires, the keyword that is currently running is stopped and the test case fails. Keywords executed as part of [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) are not interrupted if a test timeout occurs, though, but the test is nevertheless marked failed. If a keyword in teardown may hang, it can be stopped by using [user keyword timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout).
```
*** Settings ***
Test Timeout 2 minutes
*** Test Cases ***
Default timeout
[Documentation] Default timeout from Settings is used.
Some Keyword argument
Override
[Documentation] Override default, use 10 seconds timeout.
[Timeout] 10
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] Disabling timeout with NONE works too and is more explicit.
[Timeout] NONE
Some Keyword argument
```
#### [User keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-437)
Timeouts can be set for user keywords using the \[Timeout\] setting. The syntax is exactly the same as with [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout), but user keyword timeouts do not have any default value. If a user keyword timeout is specified using a variable, the value can be given also as a keyword argument.
```
*** Keywords ***
Hardcoded
[Arguments] ${arg}
[Timeout] 1 minute 42 seconds
Some Keyword ${arg}
Configurable
[Arguments] ${arg} ${timeout}
[Timeout] ${timeout}
Some Keyword ${arg}
Run Keyword with Timeout
[Arguments] ${keyword} @{args} &{kwargs} ${timeout}=1 minute
[Documentation] Wrapper that runs another keyword with a configurable timeout.
[Timeout] ${timeout}
Run Keyword ${keyword} @{args} &{kwargs}
```
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.
Note
With earlier Robot Framework versions it was possible to specify a custom error message to use if a timeout expires. This functionality was deprecated in Robot Framework 3.0.1 and removed in Robot Framework 3.2.
### [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-438)
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 [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library keywords Start Process and Wait For Process for an example.
# [3 Executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-80)
- [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage-1)
- [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-execution)
- [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution)
- [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs)
- [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution)
- [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-files)
## [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-439)
Robot Framework test cases are executed from the command line, and the end result is, by default, an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) in XML format and an HTML [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). After the execution, output files can be combined and otherwise [post-processed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs) with the Rebot tool.
- [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution)
- [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#synopsis)
- [Specifying test data to be executed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-executed)
- [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-command-line-options)
- [Using options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-options)
- [Short and long options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#short-and-long-options)
- [Setting option values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-option-values)
- [Disabling options accepting no values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-options-accepting-no-values)
- [Simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns)
- [Tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns)
- [ROBOT\_OPTIONS and REBOT\_OPTIONS environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-options-and-rebot-options-environment-variables)
- [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-results)
- [Command line output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-output)
- [Generated output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generated-output-files)
- [Return codes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes)
- [Errors and warnings during execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution)
- [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files)
- [Argument file syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-file-syntax)
- [Expanding environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#expanding-environment-variables)
- [Using argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-argument-files)
- [Reading argument files from standard input](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reading-argument-files-from-standard-input)
- [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information)
- [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-start-up-scripts)
- [Shell script example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#shell-script-example)
- [Batch file example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#batch-file-example)
- [Python example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-example)
- [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#making-robot-files-executable)
- [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems)
- [Using the Python debugger (pdb)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-the-python-debugger-pdb)
### [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-445)
#### [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-446)
```
robot [options] data
python -m robot [options] data
python path/to/robot/ [options] data
```
Execution is normally started using the robot command created as part of [installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions). Alternatively it is possible to execute the installed robot module using the selected Python interpreter. This is especially convenient if Robot Framework has been installed under multiple Python versions. Finally, if you know where the installed robot directory exists, it can be executed using Python as well.
Regardless of execution approach, the path (or paths) to the test data to be executed is given as an argument after the command. Additionally, different command line options can be used to alter the test execution or generated outputs in many ways.
#### [Specifying test data to be executed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-447)
Robot Framework test cases are created in [files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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, by default, gets its name from the [file or directory name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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 robot script is used, but other execution approaches could be used similarly.
```
robot tests.robot
robot path/to/my_tests/
robot c:\robot\tests.robot
```
Note
When executing a [directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories), all files and directories starting with a dot (.) or an underscore (\_) are ignored and, by default, only files with the .robot extension executed. See the [Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) section for more details.
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 concatenating 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:
```
robot my_tests.robot your_tests.robot
robot --name Example path/to/tests/pattern_*.robot
```
Starting from Robot Framework 6.1, it is also possible to define a [test suite initialisation file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) for the automatically created top-level suite. The path to the init file is given similarly to the test case files:
```
robot __init__.robot my_tests.robot other_tests.robot
```
### [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-448)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-449)
When options are used, they must always be given between the runner script and the data sources. For example:
```
robot -L debug my_tests.robot
robot --include smoke --variable HOST:10.0.0.42 path/to/tests/
```
#### [Short and long options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-450)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-scripts), because they are easier to understand.
The long option names are case-insensitive and hyphen-insensitive, which facilitates writing option names in an easy-to-read format. For example, \--SuiteStatLevel and \--suite-stat-level are equivalent to, but easier to read than, \--suitestatlevel.
Note
Long options being hyphen-insensitive is new in Robot Framework 6.1.
#### [Setting option values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-451)
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.
#### [Disabling options accepting no values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-452)
Options accepting no values can be disabled by using the same option again with `no` prefix added or dropped. The last option has precedence regardless of how many times options are used. For example, would not activate the dry-run mode and would return normal status rc.
#### [Simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-453)
Many command line options take arguments as *simple patterns*. These [glob-like patterns](http://en.wikipedia.org/wiki/Glob_\(programming\)) are matched according to the following rules:
- `*` matches any string, even an empty string.
- `?` matches any single character.
- `[abc]` matches one character in the bracket.
- `[!abc]` matches one character not in the bracket.
- `[a-z]` matches one character from the range in the bracket.
- `[!a-z]` matches one character not from the range in the bracket.
- Unlike with glob patterns normally, path separator characters `/` and \\ and the newline character `\n` are matches by the above wildcards.
- Unless noted otherwise, pattern matching is case, space, and underscore insensitive.
Examples:
```
--test Example* # Matches tests with name starting 'Example'.
--test Example[1-2] # Matches tests 'Example1' and 'Example2'.
--include f?? # Matches tests with a tag that starts with 'f' is three characters long.
```
All matching in above examples is case, space and underscore insensitive. For example, the second example would also match test named `example 1`.
If the matched text happens to contain some of the wildcard characters and they need to be matched literally, it is possible to do that by using the `[...]` syntax. The pattern `[*]` matches the literal `*` character, `[?]` matches `?`, and `[[]` matches `[`. Lone `[` and `]` do not need to be escaped.
Note
Support for brackets like `[abc]` and `[!a-z]` is new in Robot Framework 3.1.
#### [Tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-454)
Most tag related options accept arguments as *tag patterns*. They support same wildcards as [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) (e.g. `examp??`, `ex*le`), but they also support `AND`, `OR` and `NOT` operators explained below. These operators can be used for combining two or more individual tags or patterns together.
`AND` or `&`
The whole pattern matches if all individual patterns match. `AND` and `&` are equivalent:
```
--include fooANDbar # Matches tests containing tags 'foo' and 'bar'.
--exclude xx&yy&zz # Matches tests containing tags 'xx', 'yy', and 'zz'.
```
`OR`
The whole pattern matches if any individual pattern matches:
```
--include fooORbar # Matches tests containing either tag 'foo' or tag 'bar'.
--exclude xxORyyORzz # Matches tests containing any of tags 'xx', 'yy', or 'zz'.
```
`NOT`
The whole pattern matches if the pattern on the left side matches but the one on the right side does not. If used multiple times, none of the patterns after the first `NOT` must not match:
```
--include fooNOTbar # Matches tests containing tag 'foo' but not tag 'bar'.
--exclude xxNOTyyNOTzz # Matches tests containing tag 'xx' but not tag 'yy' or tag 'zz'.
```
The pattern can also start with `NOT` in which case the pattern matches if the pattern after `NOT` does not match:
```
--include NOTfoo # Matches tests not containing tag 'foo'
--include NOTfooANDbar # Matches tests not containing tags 'foo' and 'bar'
```
The above operators can also be used together. The operator precedence, from highest to lowest, is `AND`, `OR` and `NOT`:
```
--include xANDyORz # Matches tests containing either tags 'x' and 'y', or tag 'z'.
--include xORyNOTz # Matches tests containing either tag 'x' or 'y', but not tag 'z'.
--include xNOTyANDz # Matches tests containing tag 'x', but not tags 'y' and 'z'.
```
Although tag matching itself is case-insensitive, all operators are case-sensitive and must be written with upper case letters. If tags themselves happen to contain upper case `AND`, `OR` or `NOT`, they need to specified using lower case letters to avoid accidental operator usage:
```
--include port # Matches tests containing tag 'port', case-insensitively
--include PORT # Matches tests containing tag 'P' or 'T', case-insensitively
--exclude handoverORportNOTnotification
```
#### [ROBOT\_OPTIONS and REBOT\_OPTIONS environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-455)
Environment variables ROBOT\_OPTIONS and REBOT\_OPTIONS can be used to specify default options for [test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) and [result post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs), respectively. The options and their values must be defined as a space separated list and they are placed in front of any explicit options on the command line. The main use case for these environment variables is setting global default values for certain options to avoid the need to repeat them every time tests are run or Rebot used.
```
export ROBOT_OPTIONS="--outputdir results --tagdoc 'mytag:Example doc with spaces'"
robot tests.robot
export REBOT_OPTIONS="--reportbackground blue:red:yellow"
rebot --name example output.xml
```
### [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-456)
#### [Command line output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-457)
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 tests, 1 passed, 1 failed
==============================================================================
Output: /path/to/output.xml
Report: /path/to/report.html
Log: /path/to/log.html
```
There is also a notification on the console whenever a top-level keyword in a test case ends. A green dot is used if a keyword passes and a red F if it fails. These markers are written to the end of line and they are overwritten by the test status when the test itself ends. Writing the markers is disabled if console output is redirected to a file.
#### [Generated output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-458)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files).
#### [Return codes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-459)
Runner scripts communicate the overall execution status to the system running them using return codes. When the execution starts successfully and no tests fail, the return code is zero. All possible return codes are explained in the table below.
| RC | Explanation |
|---|---|
| 0 | All tests passed. |
| 1-249 | Returned number of tests failed. |
| 250 | 250 or more failures. |
| 251 | Help or version information printed. |
| 252 | Invalid data or command line option. |
| 253 | 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 the Bash shell the return code is in the `$?` variable, and in Windows it is in the `%ERRORLEVEL%` variable. If you use some external tool for running tests, consult its documentation for how to get the return code.
The return code can be set to zero regardless the execution status by 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 execution can be determined.
Note
Same return codes are also used with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot).
Note
When [getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information), the \--nostatusrc option has an effect only with Robot Framework 7.4 and newer.
#### [Errors and warnings during execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-460)
During the test execution there can be unexpected problems like failing to import a library or a resource file or a keyword being [deprecated](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecating-keywords). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log). Normally these errors and warnings are generated by Robot Framework itself, but libraries can also log [errors and warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-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.robot' in table 'Setting' in element on row 2: Resource file 'resource.robot' does not exist |
| 20090322 19:58:43.931 | WARN | Keyword 'SomeLibrary.Example Keyword' is deprecated. Use keyword \`Other Keyword\` instead. |
### [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-461)
Argument files allow placing all or some command line options and arguments into an external file where they will be read. This avoids the problems with characters that are problematic on the command line. If lot of options or arguments are needed, argument files also prevent the command that is used on the command line growing too long.
Argument files are taken into use with \--argumentfile (-A) option along with possible other command line options.
Note
Unlike other [long command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#short-and-long-options), \--argumentfile cannot be given in shortened format like \--argumentf.
#### [Argument file syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-462)
Argument files can contain both command line options and paths to the executed data, one option or a data source per line. Both short and long options are supported, but the latter are recommended in this context because they are easier to understand. 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 NAME:Hello, world!
# This is a comment
path/to/my/tests
```
In the above example the separator between options and their values is a single space. It is possible to use either an equal sign (=) or any number of spaces. As an example, the following three lines are identical:
```
--name An Example
--name=An Example
--name An Example
```
If argument files contain non-ASCII characters, they must be saved using the UTF-8 encoding. Argument files can use any extension. Typically .txt works fine, but a custom extension like .args can be used to separate argument files from normal text files.
#### [Expanding environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-463)
Starting from Robot Framework 7.4, it is possible to use environment variables in argument files and get them replaced *before* files are processed otherwise. For backwards compatibility reasons, this functionality is not enabled by default, but it is easy to opt-in by starting an argument file with a line `# expandvars: true`. The functionality may be enabled by default in the future, and it is possible to opt-out already now by using `# expandvars: false`.
Environment variables can be used in format `$NAME` and `${NAME}`. In addition to that, default values are supported like `${NAME=default}`. If a literal dollar sign is needed, it can be escaped by doubling it like `$$not_var`:
```
# expandvars: true
--name $NAME
--doc ${NAME}v${VERSION}
--metadata Default:${META=default value}
--metadata Escape:$$100
```
Environment variables are not limited to option values. They can also contain option names, both names and values, and using the comment character even enables conditional options:
```
# expandvars: true
--${NAME} ${VALUE}
${NAME_AND_VALUE}
${COND1=} --metadata COND1:This is enabled by default. Set 'COND1' to '#' to disable.
${COND2=#} --metadata COND2:This is disabled by default. Set 'COND2' to '' to enable.
```
Environment variable names are case-sensitive, limited to ASCII letters, numbers and underscores, and they cannot start with a number. Using a non-existing variable or an invalid variable name causes an error.
#### [Using argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-464)
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. When an argument file is used with other arguments, its contents are placed into the original list of arguments to the same place where the argument file option was. This means that options in argument files can override options before it, and its options can be overridden by options after it. It is possible to use \--argumentfile option multiple times or even recursively:
```
robot --argumentfile all_options_and_arguments.txt
robot --argumentfile defaults.args --name Example tests.robot
robot -A first.txt -A second.txt -A third.txt tests.robot
```
#### [Reading argument files from standard input](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-465)
Special argument file name `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 | robot --argumentfile STDIN
generate_arguments.sh | robot --name Example --argumentfile STDIN tests.robot
```
### [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-466)
Both when executing tests and when post-processing outputs, it is possible to get command line help with the option \--help (-h). This help text provides version information, a short general introduction and explanation of the available command line options.
It is also possible to get just the version information with the option \--version. This information also contains Python version and the platform type:
```
$ robot --version
Robot Framework 7.4 (Python 3.14.0 on linux)
C:\>rebot --version
Rebot 7.3.1 (Python 3.13.7 on win32)
```
When help or version information is printed to the console, the execution exits with a special [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) 251 by default. Starting from Robot Framework 7.4, the return code can be changed to zero by using the \--nostatusrc option like `robot --version --nostatusrc`.
### [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-467)
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.
#### [Shell script example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-468)
In this example, the same web tests in the login directory are executed with different browsers and the results combined afterwards using [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). The script also accepts command line options itself and simply forwards them to the robot command using the handy \$\* variable:
```
#!/bin/bash
robot --name Firefox --variable BROWSER:Firefox --output out/fx.xml --log none --report none $* login
robot --name IE --variable BROWSER:IE --output out/ie.xml --log none --report none $* login
rebot --name Login --outputdir out --output login.xml out/fx.xml out/ie.xml
```
#### [Batch file example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-469)
Implementing the above shell script example using batch files is not very complicated either. Notice that arguments to batch files can be forwarded to executed commands using %\*:
```
@echo off
robot --name Firefox --variable BROWSER:Firefox --output out\fx.xml --log none --report none %* login
robot --name IE --variable BROWSER:IE --log none --output out\ie.xml --report none %* login
rebot --name Login --outputdir out --output login.xml out\fx.xml out\ie.xml
```
Note
Prior to Robot Framework 3.1 robot and rebot commands were implemented as batch files on Windows and using them in another batch file required prefixing the whole command with call.
#### [Python example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-470)
When start-up scripts gets more complicated, implementing them using shell scripts or batch files is not that convenient. This is especially true if both variants are needed and same logic needs to be implemented twice. In such situations it is often better to switch to Python. It is possible to execute Robot Framework from Python using the [subprocess module](https://docs.python.org/library/subprocess.html), but often using Robot Framework's own [programmatic API](https://robot-framework.readthedocs.io/) is more convenient. The easiest APIs to use are robot.run\_cli and robot.rebot\_cli that accept same command line arguments than the robot and rebot commands.
The following example implements the same logic as the earlier shell script and batch file examples. In Python arguments to the script itself are available in sys.argv:
```
#!/usr/bin/env python
import sys
from robot import run_cli, rebot_cli
common = ['--log', 'none', '--report', 'none'] + sys.argv[1:] + ['login']
run_cli(['--name', 'Firefox', '--variable', 'BROWSER:Firefox', '--output', 'out/fx.xml'] + common, exit=False)
run_cli(['--name', 'IE', '--variable', 'BROWSER:IE', '--output', 'out/ie.xml'] + common, exit=False)
rebot_cli(['--name', 'Login', '--outputdir', 'out', 'out/fx.xml', 'out/ie.xml'])
```
Note
exit=False is needed because by default run\_cli exits to system with the correct [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes). rebot\_cli does that too, but in the above example that is fine.
### [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-471)
On UNIX-like operating systems it is possible to make \*.robot files executable by giving them execution permission and adding a [shebang](https://en.wikipedia.org/wiki/Shebang_\(Unix\)) like in this example:
```
#!/usr/bin/env robot
*** Test Cases ***
Example
Log to console Executing!
```
If the above content would be in a file example.robot and that file would be executable, it could be executed from the command line like below. Starting from Robot Framework 3.2, individually executed files can have any extension, or no extension at all, so the same would work also if the file would be named just example.
```
./example.robot
```
This trick does not work when executing a directory but can be handy when executing a single file. It is probably more often useful when [automating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) than when automating tests.
### [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-472)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-output) and in the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file), and sometimes the error message alone is enough to pinpoint the problem. More often that not, however, [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#communicating-with-robot-framework) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). 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 library keyword.
Logged tracebacks do not contain information about methods inside Robot Framework itself. If you suspect an error is caused by a bug in the framework, you can enable showing internal traces by setting environment variable ROBOT\_INTERNAL\_TRACES to any non-empty value.
If the log file still does not have enough information, it is a good idea to enable the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Log and Log Variables are useful. If nothing else works, it is always possible to search help from [mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists) or elsewhere.
#### [Using the Python debugger (pdb)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-473)
It is also possible to use the [pdb](http://docs.python.org/library/pdb.html) module from the Python standard library to set a break point and interactively debug a running test. The typical way of invoking pdb by inserting:
```
import pdb; pdb.set_trace()
```
at the location you want to break into debugger will not work correctly with Robot Framework, as the standard output stream is redirected during keyword execution. Instead, you can use the following:
```
import sys, pdb; pdb.Pdb(stdout=sys.__stdout__).set_trace()
```
from within a python library or alternatively:
```
Evaluate pdb.Pdb(stdout=sys.__stdout__).set_trace() modules=sys, pdb
```
can be used directly in a test case.
## [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-440)
This section describes how the test suite structure created from the parsed test data is executed, how test status is determined, and how to continue executing a test case if there are failures, and how to stop the whole test execution gracefully.
- [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-flow)
- [Executed suites and tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executed-suites-and-tests)
- [Setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns)
- [Execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-order)
- [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-and-suite-statuses)
- [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pass)
- [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#fail)
- [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip)
- [Migrating from criticality to SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#migrating-from-criticality-to-skip)
- [Suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-status)
- [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuing-on-failure)
- [Execution continues on teardowns automatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-continues-on-teardowns-automatically)
- [All top-level keywords are executed when tests have templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#all-top-level-keywords-are-executed-when-tests-have-templates)
- [Special failures from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#special-failures-from-keywords)
- [Run Keyword And Continue On Failure keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#run-keyword-and-continue-on-failure-keyword)
- [Enabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-continue-on-failure-using-tags)
- [Disabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags)
- [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-1)
- [BuiltIn keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#builtin-keywords)
- [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully)
- [Pressing `Ctrl-C`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pressing-ctrl-c)
- [Using signals](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-signals)
- [Using keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-keywords)
- [Stopping when first test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-when-first-test-case-fails)
- [Stopping using `robot:exit-on-failure` tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-using-robot-exit-on-failure-tag)
- [Stopping on parsing or execution error](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error)
- [Handling teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-teardowns)
### [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-474)
#### [Executed suites and tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-475)
Test cases are always executed within a test suite. A test suite created from a [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) has tests directly, whereas suites created from [directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). The exact [execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-order) and how possible [setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns) affect the execution are discussed in the following sections.
#### [Setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-476)
Setups and teardowns can be used on [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown), [test case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown) levels.
##### 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 contain are marked 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) 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 test setup 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.
##### User keyword setup
User keyword setup is executed before the keyword body. If the setup fails, the body is not executed. There is not much difference between the keyword setup and the first keyword in the body.
Note
User keyword setups are new in Robot Framework 7.0.
##### User keyword teardown
User keyword teardown is run after the keyword is executed otherwise, regardless the status. User keyword teardowns are executed fully even if some of their keywords would fail.
#### [Execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-477)
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.robot -> My Suite
02__another_suite.robot -> 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) allow listing files nicely one file per line.
It is also possible to [randomize the execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order) using the \--randomize option.
### [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-478)
This section explains how tests can get [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pass), [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#fail) or [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) status and how the [suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-status) is determined based on test statuses.
Note
The SKIP status is new in Robot Framework 4.0.
#### [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-479)
A test gets the PASS status if it is executed and none of the keywords it contains fails.
##### Prematurely passing tests
Normally all keywords are executed, but it is also possible to use [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Pass Execution and Pass Execution If to stop execution with the PASS status and not run the remaining keywords.
How Pass Execution and Pass Execution If behave in different situations is explained below:
- When used in any [setup or teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns) (suite, test or keyword), these keywords pass that setup or teardown. Possible teardowns of the started keywords are executed. Test execution or statuses are not affected otherwise.
- When used in a test case outside setup or teardown, the keywords pass that particular test case. Possible test and keyword teardowns are executed.
- Possible [continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) that occur before these keyword are used, as well as failures in teardowns executed afterwards, will fail the execution.
- It is mandatory to give an explanation message why execution was interrupted, and it is also possible to modify test case tags. For more details, and usage examples, see the [documentation of these keywords](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html).
Passing execution in the middle of a test, setup or teardown should be used with care. In the worst case it leads to tests that skip all the parts that could actually uncover problems in the tested application. In cases where execution cannot continue do to external factors, it is often safer to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) the test.
#### [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-480)
The most common reason for a test to get the FAIL status is that one of the keywords it contains fails. The keyword itself can fail by [raising an exception](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) or the keyword can be called incorrectly. Other reasons for failures include syntax errors and the test being empty.
If a [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) fails, tests in that suite are marked failed without running them. If a [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) fails, tests are marked failed retroactively.
#### [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-481)
Starting from Robot Framework 4.0, tests can get also SKIP status in addition to PASS and FAIL. There are many different ways to get this status.
##### Skipping before execution
The command line option \--skip can be used to skip specified tests without running them at all. It works based on [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) and supports [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) like `examp??` and `tagANDanother`. If it is used multiple times, all tests matching any of specified tags or tag patterns are skipped:
```
--skip require-network
--skip windowsANDversion9?
--skip python2.* --skip python3.[0-6]
```
Tests can also be skipped by tagging the test with the `robot:skip` [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags). This tag can also be set using a variable, which allows skipping test dynamically during execution.
```
*** Variables ***
${SKIP} robot:skip
*** Test Cases ***
Literal
[Documentation] Unconditionally skipped.
[Tags] robot:skip
Log This is not executed
As variable
[Documentation] Skipped unless ${SKIP} is set to a different value.
[Tags] ${SKIP}
Log This is not executed by default
```
The difference between \--skip and \--exclude is that with the latter tests are [omitted from the execution altogether](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) and they will not be shown in logs and reports. With the former they are included, but not actually executed, and they will be visible in logs and reports.
Note
`robot:skip` is new in Robot Framework 5.0.
Note
Support for using variables with tags used for skipping is new in Robot Framework 7.2.
##### Skipping dynamically during execution
Tests can get the skip status during execution in various ways:
- Using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Skip anywhere in the test case, including setup or teardown. Using Skip keyword has two effects: the test gets the SKIP status and rest of the test is not executed. However, if the test has a teardown, it will be run.
- Using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Skip If which takes a condition and skips the test if the condition is true.
- [Library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) may also trigger skip behavior by using a special exceptions. This is explained the [Skipping tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipping-tests) section in the [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) chapter.
- If [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) is skipped using any of the above means, all tests in the suite are skipped without executing them.
- If [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) is skipped, all tests will be marked skipped retroactively.
##### Automatically skipping failed tests
The command line option \--skiponfailure can be used to automatically mark failed tests skipped. It works based on [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) and supports [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) like the \--skip option discussed above:
```
--skiponfailure not-ready
--skiponfailure experimentalANDmobile
```
Starting from RF 5.0, the reserved tag `robot:skip-on-failure` can alternatively be used to achieve the same effect as above:
```
*** Test Cases ***
Example
[Tags] robot:skip-on-failure
Fail this test will be marked as skipped instead of failed
```
The motivation for this functionality is allowing execution of tests that are not yet ready or that are testing a functionality that is not yet ready. Instead of such tests failing, they will be marked skipped and their tags can be used to separate them from possible other skipped tests.
#### [Migrating from criticality to SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-482)
Earlier Robot Framework versions supported criticality concept that allowed marking tests critical or non-critical. By default all tests were critical, but the \--critical and \--noncritical options could be used to configure that. The difference between critical and non-critical tests was that non-critical tests were not included when determining the final status for an executed test suite or for the whole test run. In practice the test status was two dimensional having PASS and FAIL in one axis and criticality on the other.
Non-critical failed tests were in many ways similar to the current skipped tests. Because these features are similar and having both SKIP and criticality would have created strange test statuses like non-critical SKIP, the criticality concept was removed in Robot Framework 4.0 when the SKIP status was introduced. The problems with criticality are explained in more detail in the [issue that proposed removing it](https://github.com/robotframework/robotframework/issues/3624).
The main use case for the criticality concept was being able to run tests that are not yet ready or that are testing a functionality that is not yet ready. This use case is nowadays covered by the skip-on-failure functionality discussed in the previous section.
To ease migrating from criticality to skipping, the old \--noncritical option worked as an alias for the new \--skiponfailure in Robot Framework 4.0 and also the old \--critical option was preserved. Both old options were deprecated and they were removed in Robot Framework 5.0.
#### [Suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-483)
Suite status is determined solely based on statuses of the tests it contains:
- If any test has failed, suite status is FAIL.
- If there are no failures but at least one test has passed, suite status is PASS.
- If all tests have been skipped or the are no tests at all, suite status is SKIP.
### [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-484)
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 a drawback that often subsequent keywords would give more information about the state of the system, though, and in some cases those subsequent keywords would actually take care of the needed cleanup activities. Hence Robot Framework offers several features to continue even if there are failures.
#### [Execution continues on teardowns automatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-485)
To make it sure that all the cleanup activities are taken care of, the continue-on-failure mode is automatically enabled in [suite, test and keyword teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns). In practice this means that in teardowns all the keywords in all levels are always executed.
If this behavior is not desired, the special `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags can be used to [disable it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags).
#### [All top-level keywords are executed when tests have templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-486)
When using [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates), all the top-level keywords are executed to make it sure that all the different combinations are covered. In this usage continuing is limited to the top-level keywords, and inside them the execution ends normally if there are non-continuable failures.
```
*** Test Cases ***
Continue with templates
[Template] Should be Equal
this fails
this is run
```
If this behavior is not desired, the special `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags can be used to [disable it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags).
#### [Special failures from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-487)
[Library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) report failures using exceptions, and it is possible to use special exceptions to tell Robot Framework that execution can continue regardless the failure. How these exceptions can be created is explained in the [Continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuable-failures) section in the [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) section.
When a test ends and there have been continuable failures, 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 a continuable failure. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-488)
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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 discussed above.
```
*** Test Cases ***
Example
Run Keyword and Continue on Failure Should be Equal 1 2
Log This is executed but test fails in the end
```
#### [Enabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-489)
All keywords executed as part of test cases or user keywords which are tagged with the `robot:continue-on-failure` tag are considered continuable by default. For example, the following two tests behave identically:
```
*** Test Cases ***
Test 1
Run Keyword and Continue on Failure Should be Equal 1 2
User Keyword 1
Test 2
[Tags] robot:continue-on-failure
Should be Equal 1 2
User Keyword 2
*** Keywords ***
User Keyword 1
Run Keyword and Continue on Failure Should be Equal 3 4
Log This is executed
User Keyword 2
[Tags] robot:continue-on-failure
Should be Equal 3 4
Log This is executed
```
These tags also affect the continue-on-failure mode with different [control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#control-structures). For example, the below test case will execute the Do Something keyword ten times regardless does it succeed or not:
```
*** Test Cases ***
Example
[Tags] robot:continue-on-failure
FOR ${index} IN RANGE 10
Do Something
END
```
Setting `robot:continue-on-failure` within a test case or a user keyword will not propagate the continue-on-failure behavior into user keywords they call. If such recursive behavior is needed, the `robot:recursive-continue-on-failure` tag can be used. For example, all keywords in the following example are executed:
```
*** Test Cases ***
Example
[Tags] robot:recursive-continue-on-failure
Should be Equal 1 2
User Keyword 1
Log This is executed
*** Keywords ***
User Keyword 1
Should be Equal 3 4
User Keyword 2
Log This is executed
User Keyword 2
Should be Equal 5 6
Log This is executed
```
Setting `robot:continue-on-failure` or `robot:recursive-continue-on-failure` in a test case does NOT alter the behaviour of a failure in the keyword(s) executed as part of the \[Setup\]: The test case is marked as failed and no test case keywords are executed.
Note
The `robot:continue-on-failure` and `robot:recursive-continue-on-failure` tags are new in Robot Framework 4.1. They do not work properly with `WHILE` loops prior to Robot Framework 6.0.
#### [Disabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-490)
Special tags `robot:stop-on-failure` and `robot:recursive-stop-on-failure` can be used to disable the continue-on-failure mode if needed. They work when [continue-on-failure has been enabled using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-continue-on-failure-using-tags) and also with [teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-continues-on-teardowns-automatically) and [templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#all-top-level-keywords-are-executed-when-tests-have-templates):
```
*** Test Cases ***
Disable continue-in-failure set using tags
[Tags] robot:recursive-continue-on-failure
Keyword
Keyword # This is executed
Disable continue-in-failure in teardown
No Operation
[Teardown] Keyword
Disable continue-in-failure with templates
[Tags] robot:stop-on-failure
[Template] Should be Equal
this fails
this is not run
*** Keywords ***
Keyword
[Tags] robot:stop-on-failure
Should be Equal this fails
Should be Equal this is not run
```
The `robot:stop-on-failure` tag affects only test cases and user keywords where it is used and does not propagate to user keywords they call nor to their own teardowns. If recursive behavior affecting all called user keywords and teardowns is desired, the `robot:recursive-stop-on-failure` tag can be used instead. If there is a need, its effect can again be disabled in lower level keywords by using `robot:continue-on-failure` or `robot:recursive-continue-on-failure` tags.
The `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags do not alter the behavior of continuable failures caused by [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#special-failures-from-keywords) or by [Run Keyword And Continue On Failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#run-keyword-and-continue-on-failure-keyword). For example, both keywords in this example are run even though `robot:stop-on-failure` is used:
```
*** Test Cases ***
Example
[Tags] robot:stop-on-failure
Run Keyword and Continue on Failure Should be Equal 1 2
Log This is executed regardless the tag
```
If `robot:recursive-stop-on-failure` and `robot:continue-on-failure` are used together in the same test or keyword, execution is stopped in called keywords if there are failures, but continues in the test or keyword using these tags. If `robot:recursive-continue-on-failure` and `robot:stop-on-failure` are used together in the same test or keyword, execution is continued in called keywords if there are failures, but stopped in the test or keyword using these tags.
Note
The `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags are new in Robot Framework 6.0.
Note
Using recursive and non-recursive tags together in same test or keyword is new in Robot Framework 7.0.
#### [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-491)
Robot Framework 5.0 introduced native `TRY/EXCEPT` syntax that can be used for handling failures:
```
*** Test Cases ***
Example
TRY
Some Keyword
EXCEPT Expected error message
Error Handler Keyword
END
```
For more details see the separate [TRY/EXCEPT syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax) section.
#### [BuiltIn keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-492)
There are several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords that can be used to execute other keywords so that execution can continue after possible failures:
- Run Keyword And Expect Error executes a keyword and expects it to fail with the specified error message. The aforementioned `TRY/EXCEPT` syntax is nowadays generally recommended instead.
- Run Keyword And Ignore Error executes a keyword and silences possible error. It returns the status along with possible keyword return value or error message. The `TRY/EXCEPT` syntax generally works better in this case as well.
- Run Keyword And Warn On Failure is a wrapper for Run Keyword And Ignore Error that automatically logs a warning if the executed keyword fails.
- Run Keyword And Return Status executes a keyword and returns Boolean `True` or `False` depending on did it pass or fail.
### [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-493)
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.
The tests that are automatically failed get `robot:exit` tag and the generated report will include `NOT robot:exit` [combined tag pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics) to easily see those tests that were not skipped. Note that the test in which the exit happened does not get the `robot:exit` tag.
Note
Prior to Robot Framework 3.1, the special tag was named `robot-exit`.
#### [Pressing `Ctrl-C`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-494)
The execution is stopped when `Ctrl-C` is pressed in the console where the tests are running. The execution is stopped immediately, but reports and logs are still generated.
If `Ctrl-C` is pressed again, the execution ends immediately and reports and logs are not created.
#### [Using signals](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-495)
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.
#### [Using keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-496)
The execution can be stopped also by the executed keywords. There is a separate Fatal Error [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword for this purpose, and custom keywords can use [fatal exceptions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution) when they fail.
#### [Stopping when first test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-497)
If option \--exitonfailure (-X) is used, the whole execution stops immediately if any test fails.
#### [Stopping using `robot:exit-on-failure` tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-498)
If a failed test has a [special](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) `robot:exit-on-failure` tag, the whole execution stops immediately after that test.
Note
This functionality is new in Robot Framework 7.2.
#### [Stopping on parsing or execution error](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-499)
Robot Framework separates *failures* caused by failing keywords from *errors* caused by, for example, invalid settings or failed test library imports. By default these errors are reported as [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but errors themselves do not fail tests or affect execution otherwise. If \--exitonerror option is used, however, all such errors are considered fatal and execution stopped so that remaining tests are marked failed. With parsing errors encountered before execution even starts, this means that no tests are actually run.
Note
Also logging something with the `ERROR` [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) is considered an error and stops the execution if the \--exitonerror option is used.
#### [Handling teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-500)
By default teardowns of the tests and suites that have been started are executed even if the test execution is stopped using one of the methods above. This allows clean-up activities to be run regardless how execution ends.
It is also possible to skip teardowns when execution is stopped by using \--skipteardownonexit option. This can be useful if, for example, clean-up tasks take a lot of time.
## [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-441)
Robot Framework can be used also for other automation purposes than test automation, and starting from Robot Framework 3.1 it is possible to explicitly [create](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) and execute tasks. For most parts task execution and test execution work the same way, and this section explains the differences.
- [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generic-automation-mode)
- [3\.3.2 Task related command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-command-line-options)
### [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-501)
When Robot Framework is used execute a file and it notices that the file has tasks, not tests, it automatically sets itself into the generic automation mode. This mode does not change the actual execution at all, but when logs and reports are created, they use term *task*, not *test*. They have, for example, headers like `Task Log` and `Task Statistics` instead of `Test Log` and `Test Statistics`.
The generic automation mode can also be enabled by using the \--rpa option. In that case the executed files can have either tests or tasks. Alternatively \--norpa can be used to force the test automation mode even if executed files contain tasks. If neither of these options are used, it is an error to execute multiple files so that some have tests and others have tasks.
The execution mode is stored in the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and read by [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot) if outputs are post-processed. The mode can also [be set when using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-execution-mode) if necessary.
### [3\.3.2 Task related command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-502)
All normal command line options can be used when executing tasks. If there is a need to [select only certain tasks for execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases), \--task can be used instead of \--test. Additionally the aforementioned \--rpa can be used to control the execution mode.
## [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-442)
[XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) 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, and using it separately allows creating custom reports and logs as well as combining and merging results.
- [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-rebot)
- [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#synopsis-1)
- [Specifying options and arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-options-and-arguments)
- [Return codes with Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes-with-rebot)
- [Controlling execution mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-execution-mode)
- [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-reports-logs-and-output-files)
- [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs)
- [3\.4.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs)
- [Merging re-executed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-re-executed-tests)
- [Merging suites executed in pieces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-suites-executed-in-pieces)
- [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-output-files)
### [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-503)
#### [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-504)
```
rebot [options] outputs
python -m robot.rebot [options] outputs
python path/to/robot/rebot.py [options] outputs
```
The most common way to use Rebot is using the rebot command. Alternatively it is possible to execute the installed robot.rebot module or the robot/rebot.py file using the selected Python interpreter.
#### [Specifying options and arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-505)
The basic syntax for using Rebot is exactly the same as when [starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) and also most of the command line options are identical. The main difference is that arguments to Rebot are [XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) instead of test data files or directories.
#### [Return codes with Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-506)
Return codes from Rebot are exactly same as when [running tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes).
#### [Controlling execution mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-507)
Rebot notices have [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) or [tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) been run, and by default preserves the execution mode. The mode affects logs and reports so that in the former case they will use term *test* like `Test Log` and `Test Statistics`, and in the latter case term *task* like `Task Log` and `Task Statistics`.
Rebot also supports using \--rpa or \--norpa options to set the execution mode explicitly. This is necessary if multiple output files are processed and they have conflicting modes.
### [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-508)
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:
```
rebot output.xml
rebot path/to/output_file.xml
rebot --include smoke --name Smoke_Tests c:\results\output.xml
```
Another common usage is creating only the output file when running tests (log and report generation can be disabled with ) 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.
Rebot does not create XML output files by default, but it is possible to create them by using the \--output (-o) option. Log and report are created by default, but they can be disabled by using value `NONE` (case-insensitive) if they are not needed:
```
rebot --include smoke --output smoke.xml --log none --report none original.xml
```
### [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-509)
An important feature in 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-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.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-510)
If same tests are re-executed or a single test suite executed in pieces, combining results like discussed above creates an unnecessary top-level test suite. In these cases it is typically better to merge results instead. Merging is done by using \--merge (-R) option which changes the way how Rebot combines two or more output files. This option itself takes no arguments and all other command line options can be used with it normally:
```
rebot --merge original.xml merged.xml
rebot --merge --name Example first.xml second.xml third.xml
```
When suites are merged, documentation, suite setup and suite teardown are got from the last merged suite. Suite metadata from all merged suites is preserved so that values in latter suites have precedence.
How merging tests works is explained in the following sections discussing the two main merge use cases.
Note
Getting suite documentation and metadata from merged suites is new in Robot Framework 6.0.
#### [Merging re-executed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-511)
There is often a need to re-execute a subset of tests, for example, after fixing a bug in the system under test or in the tests themselves. This can be accomplished by [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) by names (\--test and \--suite options), tags (\--include and \--exclude), or by previous status (\--rerunfailed or \--rerunfailedsuites).
Combining re-execution results with the original results using the default [combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs) approach does not work too well. The main problem is that you get separate test suites and possibly already fixed failures are also shown. In this situation it is better to use \--merge (-R) option to tell Rebot to merge the results instead. In practice this means that tests from the latter test runs replace tests in the original. An exception to this rule is that [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped) tests in latter runs are ignored and original tests preserved.
This usage is best illustrated by a practical example using \--rerunfailed and \--merge together:
```
robot --output original.xml tests # first execute all tests
robot --rerunfailed original.xml --output rerun.xml tests # then re-execute failing
rebot --merge original.xml rerun.xml # finally merge results
```
The message of the merged tests contains a note that results have been replaced. The message also shows the old status and message of the test.
Merged results must always have same top-level test suite. Tests and suites in merged outputs that are not found from the original output are added into the resulting output. How this works in practice is discussed in the next section.
Note
Ignoring skipped tests in latter runs is new in Robot Framework 4.1.
#### [Merging suites executed in pieces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-512)
Another important use case for the \--merge option is merging results got when running a test suite in pieces using, for example, \--include and \--exclude options:
```
robot --include smoke --output smoke.xml tests # first run some tests
robot --exclude smoke --output others.xml tests # then run others
rebot --merge smoke.xml others.xml # finally merge results
```
When merging outputs like this, the resulting output contains all tests and suites found from all given output files. If some test is found from multiple outputs, latest results replace the earlier ones like explained in the previous section. Also this merging strategy requires the top-level test suites to be same in all outputs.
### [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-513)
Rebot can create and process output files also in the [JSON](https://json.org/) format. Creating JSON output files is done using the normal \--output option so that the specified file has a .json extension:
```
rebot --output output.json output.xml
```
When reading output files, JSON files are automatically recognized by the extension:
```
rebot output.json
rebot output1.json output2.json
```
When combining or merging results, it is possible to mix JSON and XML output files:
```
rebot output1.xml output2.json
rebot --merge original.xml rerun.json
```
The JSON output file structure is documented in the result.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
Note
Support for JSON output files is new in Robot Framework 7.0. Prior to Robot Framework 7.2 JSON output files contained only information about the executed suite, but nowadays they contain the same result data as [XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file).
## [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-443)
This section explains different command line options that can be used for configuring the [test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) or [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). Options related to generated [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) are discussed in the next section.
- [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse)
- [Executing individual files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-individual-files)
- [Included and excluded files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files)
- [Selecting files by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-name-or-path)
- [Selecting files by extension](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-extension)
- [Using custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers)
- [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases)
- [By test names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names)
- [By suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names)
- [By tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names)
- [Re-executing failed test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-cases)
- [Re-executing failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-suites)
- [When no tests match selection](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection)
- [3\.5.3 Setting metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-metadata)
- [Setting suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name)
- [Setting suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation)
- [Setting free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata)
- [Setting test tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags)
- [3\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions)
- [Locations automatically in module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#locations-automatically-in-module-search-path)
- [PYTHONPATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pythonpath)
- [Using `--pythonpath` option](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-pythonpath-option)
- [Configuring `sys.path` programmatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-sys-path-programmatically)
- [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-variables)
- [3\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run)
- [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order)
- [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data)
- [Example: Select every Xth test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-select-every-xth-test)
- [Example: Exclude tests by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-exclude-tests-by-name)
- [Example: Disable setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-disable-setups-and-teardowns)
- [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-console-output)
- [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type)
- [Console width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-width)
- [Console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors)
- [Console links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links)
- [Console markers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-markers)
- [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners)
### [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-514)
#### [Executing individual files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-515)
When executing individual files, Robot Framework tries to parse and run them regardless the name or the file extension. What parser to use depends on the extension:
- .robot files and files that are not recognized are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
- .rst and .rest files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .rbt and .json files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Files supported by [custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers) are parsed by a matching parser.
Examples:
```
robot example.robot # Standard Robot Framework parser.
robot example.tsv # Must be compatible with the standard parser.
robot example.rst # reStructuredText parser.
robot x.robot y.rst # Parse both files using an appropriate parser.
```
#### [Included and excluded files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-516)
When executing a [directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories), files and directories are parsed using the following rules:
- All files and directories starting with a dot (.) or an underscore (\_) are ignored.
- .robot files are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
- .robot.rst files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .rbt files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Files supported by [custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers) are parsed by a matching parser.
- Other files are ignored unless parsing them has been enabled by using the \--parseinclude or \--extension options discussed in the subsequent sections.
#### [Selecting files by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-517)
When executing a directory, it is possible to parse only certain files based on their name or path by using the \--parseinclude (-I) option. This option has slightly different semantics depending on the value it is used with:
- If the value is just a file name like `example.robot`, files matching the name in all directories will be parsed.
- To match only a certain file in a certain directory, files can be given as relative or absolute paths like `path/to/tests.robot`.
- If the value is a path to a directory, all files inside that directory are parsed, recursively.
Examples:
```
robot --parseinclude example.robot tests # Parse `example.robot` files anywhere under `tests`.
robot -I example_*.robot -I ???.robot tests # Parse files matching `example_*.robot` or `???.robot` under `tests`.
robot -I tests/example.robot tests # Parse only `tests/example.robot`.
robot --parseinclude tests/example tests # Parse files under `tests/example` directory, recursively.
```
Values used with \--parseinclude are case-insensitive and support [glob patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) like `example_*.robot`. There are, however, two small differences compared to how patterns typically work with Robot Framework:
- `*` matches only a single path segment. For example, `path/*/tests.robot` matches path/to/tests.robot but not path/to/nested/tests.robot.
- `**` can be used to enable recursive matching. For example, `path/**/tests.robot` matches both path/to/tests.robot and path/to/nested/tests.robot.
If the pattern contains an extension, files with that extension are parsed even if they by [default would not be](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files). What parser to use depends on the used extension:
- .rst and .rest files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .json files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Other files are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
Notice that when you use a pattern like `*.robot` and there exists a file that matches the pattern in the execution directory, the shell may resolve the pattern before Robot Framework is called and the value passed to it is the file name, not the original pattern. In such cases you need to quote or escape the pattern like `'*.robot'` or `\*.robot`.
Note
\--parseinclude is new in Robot Framework 6.1.
#### [Selecting files by extension](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-518)
In addition to using the \--parseinclude option discussed in the previous section, it is also possible to enable parsing files that are [not parsed by default](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files) by using the \--extension (-F) option. Matching extensions is case insensitive and the leading dot can be omitted. If there is a need to parse more than one kind of files, it is possible to use a colon `:` to separate extensions:
```
robot --extension rst path/to/tests # Parse only *.rst files.
robot -F robot:rst path/to/tests # Parse *.robot and *.rst files.
```
The above is equivalent to the following \--parseinclude usage:
```
robot --parseinclude *.rst path/to/tests
robot -I *.robot -I *.rst path/to/tests
```
Because the \--parseinclude option is more powerful and covers all same use cases as the \--extension option, the latter is likely to be deprecated in the future. Users are recommended to use \--parseinclude already now.
#### [Using custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-519)
External parsers can parse files that Robot Framework does not recognize otherwise. For more information about creating and using such parsers see the [Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface) section.
### [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-520)
Robot Framework offers several command line options for selecting which test cases to execute. The same options work also when [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks) and when post-processing outputs with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot).
#### [By test names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-521)
The easiest way to select only some tests to be run is using the \--test (-t) option. As the name implies, it can be used for selecting tests by their names. Given names are case, space and underscore insensitive and they also support [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns). The option can be used multiple times to match multiple tests:
```
--test Example # Match only tests with name 'Example'.
--test example* # Match tests starting with 'example'.
--test first --test second # Match tests with name 'first' or 'second'.
```
To pinpoint a test more precisely, it is possible to prefix the test name with a suite name:
```
--test mysuite.mytest # Match test 'mytest' in suite 'mysuite'.
--test root.sub.test # Match test 'test' in suite 'sub' in suite 'root'.
--test *.sub.test # Match test 'test' in suite 'sub' anywhere.
```
Notice that when the given name includes a suite name, it must match the whole suite name starting from the root suite. Using a wildcard as in the last example above allows matching tests with a parent suite anywhere.
Using the \--test option is convenient when only a few tests needs to be selected. A common use case is running just the test that is currently being worked on. If a bigger number of tests needs to be selected, it is typically easier to select them [by suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) or [by tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names).
When [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks), it is possible to use the \--task option as an alias for \--test.
#### [By suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-522)
Tests can be selected also by suite names with the \--suite (-s) option that selects all tests in matching suites. Similarly as with \--test, given names are case, space and underscore insensitive and support [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns). To pinpoint a suite more precisely, it is possible to prefix the name with the parent suite name:
```
--suite Example # Match only suites with name 'Example'.
--suite example* # Match suites starting with 'example'.
--suite first --suite second # Match suites with name 'first' or 'second'.
--suite root.child # Match suite 'child' in root suite 'root'.
--suite *.parent.child # Match suite 'child' with parent 'parent' anywhere.
```
If the name contains a parent suite name, it must match the whole suite name the same way as with \--test. Using a wildcard as in the last example above allows matching suites with a parent suite anywhere.
Note
Prior to Robot Framework 7.0, \--suite with a parent suite did not need to match the whole suite name. For example, `parent.child` would match suite `child` with parent `parent` anywhere. The name must be prefixed with a wildcard if this behavior is desired nowadays.
If both \--suite and \--test options are used, only the specified tests in specified suites are selected:
```
--suite mysuite --test mytest # Match test 'mytest' if its inside suite 'mysuite'.
```
Using the \--suite option is more or less the same as executing the appropriate suite file or directory directly. The main difference is that if a file or directory is run directly, possible higher level [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) are ignored:
```
# Root suite is 'Tests' and its possible initialization file is used.
robot --suite example path/to/tests
# Root suite is 'Example' and higher level initialization files are ignored.
robot path/to/tests/example.robot
```
Prior to Robot Framework 6.1, files not matching the \--suite option were not parsed at all for performance reasons. This optimization was not possible anymore after suites got a new Name setting that can override the default suite name that is got from the file or directory name. New \--parseinclude option has been added to [explicitly select which files are parsed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-name-or-path) if this kind of parsing optimization is needed.
#### [By tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-523)
It is possible to include and exclude test cases by [tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) names with the \--include (-i) and \--exclude (-e) options, respectively. If the \--include option is used, only test cases having a matching tag are selected, and with the \--exclude option 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. In that case a test is selected if it has a tag that matches any included tags, and also has no tag that matches any excluded tags.
In addition to specifying a tag to match fully, it is possible to use [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*` and `?` are wildcards and `AND`, `OR`, and `NOT` operators can be used for combining individual tags or patterns together:
```
--include feature-4?
--exclude bug*
--include fooANDbar
--exclude xxORyyORzz
--include fooNOTbar
```
Another way to exclude tests by tags is using the `robot:exclude` [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags). This tag can also be set using a variable, which allows excluding test dynamically during execution.
```
*** Variables ***
${EXCLUDE} robot:exclude
*** Test Cases ***
Literal
[Documentation] Unconditionally excluded.
[Tags] robot:exclude
Log This is not executed
As variable
[Documentation] Excluded unless ${EXCLUDE} is set to a different value.
[Tags] ${EXCLUDE}
Log This is not executed by default
```
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, often called smoke tests, can be tagged with `smoke` and executed with `--include smoke`.
- Unfinished test can be committed to version control with a tag such as `not_ready` and excluded from the test execution with `--exclude not_ready`.
- Tests can be tagged with `sprint-<num>`, where `<num>` specifies the number of the current sprint, and after executing all test cases, a separate report containing only the tests for a certain sprint can be generated (for example,
```
rebot
--include sprint-42 output.xml
```
).
Options \--include and \--exclude can be used in combination with \--suite and \--test discussed in the previous section. In that case tests that are selected must match all selection criteria:
```
--suite example --include tag # Match test if it is in suite 'example' and has tag 'tag'.
--suite example --exclude tag # Match test if it is in suite 'example' and does not have tag 'tag'.
--test ex* --include tag # Match test if its name starts with 'ex' and it has tag 'tag'.
--test ex* --exclude tag # Match test if its name starts with 'ex' and it does not have tag 'tag'.
```
Note
`robot:exclude` is new in Robot Framework 5.0.
Note
Using variables with `robot:exclude` is new in Robot Framework 7.2. Using variables with tags matched against \--include and \--exclude is not supported.
Note
In Robot Framework 7.0 \--include and \--test were cumulative and selected tests needed to match only either of these options. That behavior caused [backwards incompatibility problems](https://github.com/robotframework/robotframework/issues/5023) and it was reverted already in Robot Framework 7.0.1.
#### [Re-executing failed test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-524)
Command line option \--rerunfailed (-R) can be used to select all failed tests from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for re-execution. This option is useful, for example, if running all tests takes a lot of time and one wants to iteratively fix failing test cases.
```
robot tests # first execute all tests
robot --rerunfailed output.xml tests # then re-execute failing
```
Behind the scenes this option selects the failed tests as they would have been selected individually using the \--test option. It is possible to further fine-tune the list of selected tests by using \--test, \--suite, \--include and \--exclude options.
It is an error if the output contains no failed tests, but this behavior can be changed by using the \--runemptysuite option [discussed below](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). Using an output not originating from executing the same tests that are run now causes undefined results. Using a special value `NONE` as the output is same as not specifying this option at all.
Tip
Re-execution results and original results can be [merged together](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs) using the \--merge command line option.
#### [Re-executing failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-525)
Command line option \--rerunfailedsuites (-S) can be used to select all failed suites from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for re-execution. Like \--rerunfailed (-R), this option is useful when full test execution takes a lot of time. Note that all tests from a failed test suite will be re-executed, even passing ones. This option is useful when the tests in a test suite depends on each other.
Behind the scenes this option selects the failed suites as they would have been selected individually with the \--suite option. It is possible to further fine-tune the list of selected tests by using \--test, \--suite, \--include and \--exclude options.
#### [When no tests match selection](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-526)
By default when no tests match the selection criteria test execution fails with an error like:
```
[ ERROR ] Suite 'Example' contains no tests matching tag 'xxx'.
```
Because no outputs are generated, this behavior can be problematic if tests are executed and results processed automatically. Luckily a command line option \--RunEmptySuite (case-insensitive) 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.
Similar situation can occur also when processing output files with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). It is possible that no test match the used filtering criteria or that the output file contained no tests to begin with. By default executing Rebot fails in these cases, but it has a separate \--ProcessEmptySuite option that can be used to alter the behavior. In practice this option works the same way as \--RunEmptySuite when running tests.
Note
Using \--RunEmptySuite with \--ReRunFailed or \--ReRunFailedSuites requires Robot Framework 5.0.1 or newer.
### [3\.5.3 Setting metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-527)
#### [Setting suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-528)
When Robot Framework parses test data, [suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name) 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):
```
robot --name "Custom name" tests.robot
```
#### [Setting suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-529)
In addition to [defining documentation in the test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation), documentation of the top-level suite can be given from the command line with the option \--doc (-D). The value can contain simple [HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) and must be quoted if it contains spaces.
If the given documentation is a relative or absolute path pointing to an existing file, the actual documentation will be read from that file. This is especially convenient if the externally specified documentation is long or contains multiple lines.
Examples:
```
robot --doc "Example documentation" tests.robot
robot --doc doc.txt tests.robot # Documentation read from doc.txt if it exits.
```
Note
Reading documentation from an external file is new in Robot Framework 4.1.
Prior to Robot Framework 3.1, underscores in documentation were converted to spaces same way as with the \--name option.
#### [Setting free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-530)
[Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-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. The value can contain simple [HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) and the whole argument must be quoted if it contains spaces. This option may be used several times to set multiple metadata values.
If the given value is a relative or absolute path pointing to an existing file, the actual value will be read from that file. This is especially convenient if the value is long or contains multiple lines. If the value should be a path to an existing file, not read from that file, the value must be separated with a space from the `name:` part.
Examples:
```
robot --metadata Name:Value tests.robot
robot --metadata "Another Name:Another value, now with spaces" tests.robot
robot --metadata "Read From File:meta.txt" tests.robot # Value read from meta.txt if it exists.
robot --metadata "Path As Value: meta.txt" tests.robot # Value always used as-is.
```
Note
Reading metadata value from an external file is new in Robot Framework 4.1.
Prior to Robot Framework 3.1, underscores in the value were converted to spaces same way as with the \--name option.
#### [Setting test tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-531)
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\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-532)
When Robot Framework imports a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import), [listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners), or some other Python based extension, it uses the Python interpreter to import the module containing the extension from the system. The list of locations where modules are looked for is called *the module search path*, and its contents can be configured using different approaches explained in this section.
Robot Framework uses Python's module search path also when importing [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files) if the specified path does not match any file directly.
The module search path being set correctly so that libraries and other extensions are found is a requirement for successful test execution. If you need to customize it using approaches explained below, it is often a good idea to create a custom [start-up script](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-script).
#### [Locations automatically in module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-533)
Python interpreters have their own standard library as well as a directory where third party modules are installed automatically in the module search path. This means that test libraries [packaged using Python's own packaging system](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#packaging-libraries) are automatically installed so that they can be imported without any additional configuration.
#### [PYTHONPATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-534)
Python reads additional locations to be added to the module search path from PYTHONPATH environment variables. If you want to specify more than one location in any of them, you need to separate the locations with a colon on UNIX-like machines (e.g. `/opt/libs:$HOME/testlibs`) and with a semicolon on Windows (e.g. `D:\libs;%HOMEPATH%\testlibs`).
Environment variables can be configured permanently system wide or so that they affect only a certain user. Alternatively they can be set temporarily before running a command, something that works extremely well in custom [start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-scripts).
#### [Using `--pythonpath` option](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-535)
Robot Framework has a separate command line option \--pythonpath (-P) for adding locations to the module search path.
Multiple locations can be given by separating them with a colon (`:`) or a semicolon (`;`) or by using this option multiple times. If the value contains both colons and semicolons, it is split from semicolons. Paths can also be [glob patterns](https://en.wikipedia.org/wiki/Glob_\(programming\)) matching multiple paths, but they typically need to be escaped when used on the console.
Examples:
```
--pythonpath libs
--pythonpath /opt/testlibs:mylibs.zip:yourlibs
--pythonpath /opt/testlibs --pythonpath mylibs.zip --pythonpath yourlibs
--pythonpath c:\temp;d:\resources
--pythonpath lib/\*.zip # '*' is escaped
```
Note
Both colon and semicolon work regardless the operating system. Using semicolon is new in Robot Framework 5.0.
#### [Configuring `sys.path` programmatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-536)
Python interpreters store the module search path they use as a list of strings in [sys.path](http://docs.python.org/library/sys.html#sys.path) attribute. This list can be updated dynamically during execution, and changes are taken into account next time when something is imported.
### [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-537)
[Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can be set from the command line either [individually](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) using the \--variable (-v) option or through [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-538)
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 \--dryrun.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) are shown, for example, when test library or resource file imports cannot be resolved.
It is possible to disable dry run validation of specific [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) by adding a special `robot:no-dry-run` [keyword tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) to them. This is useful if a keyword fails in the dry run mode for some reason, but work fine when executed normally.
Note
The dry run mode does not validate variables.
### [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-539)
The test execution order can be randomized using option \--randomize \<what\>\[:\<seed\>\], where `<what>` is one of the following:
`tests`
Test cases inside each test suite are executed in random order.
`suites`
All test suites are executed in a random order, but test cases inside suites are run in the order they are defined.
`all`
Both test cases and test suites are executed in a random order.
`none`
Neither execution order of test nor suites is randomized. This value can be used to override the earlier value set with \--randomize.
It is possible to give a custom seed to initialize the random generator. This is useful if you want to re-run tests using the same order as earlier. The seed is given as part of the value for \--randomize in format `<what>:<seed>` and it must be an integer. If no seed is given, it is generated randomly. The executed top level test suite automatically gets [metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) named Randomized that tells both what was randomized and what seed was used.
Examples:
```
robot --randomize tests my_test.robot
robot --randomize all:12345 path/to/tests
```
### [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-540)
If the provided built-in features to modify test data before execution are not enough, Robot Framework makes it possible to do custom modifications programmatically. This is accomplished by creating a so called *pre-run modifier* and activating it using the \--prerunmodifier option.
Pre-run modifiers should be implemented as visitors that can traverse through the executable test suite structure and modify it as needed. The visitor interface is explained as part of the [Robot Framework API documentation](http://robot-framework.readthedocs.org/en/master/autodoc/robot.model.html#module-robot.model.visitor), and it possible to modify executed [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite), [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [keywords](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.Keyword) using it. The examples below ought to give an idea of how pre-run modifiers can be used and how powerful this functionality is.
When a pre-run modifier is taken into use on the command line using the \--prerunmodifier option, it can be specified either as a name of the modifier class or a path to the modifier file. If the modifier is given as a class name, the module containing the class must be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), and if the module name is different than the class name, the given name must include both like `module.ModifierClass`. If the modifier is given as a path, the class name must be same as the file name. For most parts this works exactly like when [importing a test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import).
If a modifier requires arguments, like the examples below do, they can be specified after the modifier name or path using either a colon (`:`) or a semicolon (`;`) as a separator. If both are used in the value, the one used first is considered to be the actual separator. Starting from Robot Framework 4.0, arguments also support the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) as well as [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) based on [type hints](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) and [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) the same way as keywords do.
If more than one pre-run modifier is needed, they can be specified by using the \--prerunmodifier option multiple times. If similar modifying is needed before creating logs and reports, [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results) can be enabled using the \--prerebotmodifier option.
Pre-run modifiers are executed before other configuration affecting the executed test suite and test cases. Most importantly, options related to [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) are processed after modifiers, making it possible to use options like \--include also with possible dynamically added tests.
Another way to modify tests is using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) interface. Modifying the `data` argument passed to the `start_suite` listener method when it is called for the first time has in practice the same effect as using a pre-run modifier. The main difference is that `--include/--exclude` and other such options do not have an effect to the added tests. The main benefit of using listeners is that they allow making modifications dynamically based on what happens during the execution.
Tip
Modifiers are taken into use from the command line exactly the same way as [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface). See the [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line) section for more information and examples.
#### [Example: Select every Xth test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-541)
The first example shows how a pre-run modifier can remove tests from the executed test suite structure. In this example only every Xth tests is preserved, and the X is given from the command line along with an optional start index.
```
"""Pre-run modifier that selects only every Xth test for execution.
Starts from the first test by default. Tests are selected per suite.
"""
from robot.api import SuiteVisitor
class SelectEveryXthTest(SuiteVisitor):
def __init__(self, x: int, start: int = 0):
self.x = x
self.start = start
def start_suite(self, suite):
"""Modify suite's tests to contain only every Xth."""
suite.tests = suite.tests[self.start::self.x]
def end_suite(self, suite):
"""Remove suites that are empty after removing tests."""
suite.suites = [s for s in suite.suites if s.test_count > 0]
def visit_test(self, test):
"""Avoid visiting tests and their keywords to save a little time."""
pass
```
If the above pre-run modifier is in a file SelectEveryXthTest.py and the file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), it could be used like this:
```
# Specify the modifier as a path. Run every second test.
robot --prerunmodifier path/to/SelectEveryXthTest.py:2 tests.robot
# Specify the modifier as a name. Run every third test, starting from the second.
robot --prerunmodifier SelectEveryXthTest:3:1 tests.robot
```
#### [Example: Exclude tests by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-542)
Also the second example removes tests, this time based on a given name pattern. In practice it works like a negative version of the built-in \--test option.
```
"""Pre-run modifier that excludes tests by their name.
Tests to exclude are specified by using a pattern that is both case and space
insensitive and supports '*' (match anything) and '?' (match single character)
as wildcards.
"""
from robot.api import SuiteVisitor
from robot.utils import Matcher
class ExcludeTests(SuiteVisitor):
def __init__(self, pattern):
self.matcher = Matcher(pattern)
def start_suite(self, suite):
"""Remove tests that match the given pattern."""
suite.tests = [t for t in suite.tests if not self._is_excluded(t)]
def _is_excluded(self, test):
return self.matcher.match(test.name) or self.matcher.match(test.longname)
def end_suite(self, suite):
"""Remove suites that are empty after removing tests."""
suite.suites = [s for s in suite.suites if s.test_count > 0]
def visit_test(self, test):
"""Avoid visiting tests and their keywords to save a little time."""
pass
```
Assuming the above modifier is in a file named ExcludeTests.py, it could be used like this:
```
# Exclude test named 'Example'.
robot --prerunmodifier path/to/ExcludeTests.py:Example tests.robot
# Exclude all tests ending with 'something'.
robot --prerunmodifier path/to/ExcludeTests.py:*something tests.robot
```
#### [Example: Disable setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-543)
Sometimes when debugging tests it can be useful to disable setups or teardowns. This can be accomplished by editing the test data, but pre-run modifiers make it easy to do that temporarily for a single run:
```
"""Pre-run modifiers for disabling suite and test setups and teardowns."""
from robot.api import SuiteVisitor
class SuiteSetup(SuiteVisitor):
def start_suite(self, suite):
suite.setup = None
class SuiteTeardown(SuiteVisitor):
def start_suite(self, suite):
suite.teardown = None
class TestSetup(SuiteVisitor):
def start_test(self, test):
test.setup = None
class TestTeardown(SuiteVisitor):
def start_test(self, test):
test.teardown = None
```
Assuming that the above modifiers are all in a file named disable.py and this file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), setups and teardowns could be disabled, for example, as follows:
```
# Disable suite teardowns.
robot --prerunmodifier disable.SuiteTeardown tests.robot
# Disable both test setups and teardowns by using '--prerunmodifier' twice.
robot --prerunmodifier disable.TestSetup --prerunmodifier disable.TestTeardown tests.robot
```
Note
Prior to Robot Framework 4.0 `setup` and `teardown` were accessed via the intermediate `keywords` attribute and, for example, suite setup was disabled like `suite.keywords.setup = None`.
### [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-544)
There are various command line options to control how test execution is reported on the console.
#### [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-545)
The overall console output type is set with the \--console option. It supports the following case-insensitive values:
`verbose`
Every test suite and test case is reported individually. This is the default.
`dotted`
Only show `.` for passed test, `F` for failed tests, `s` for skipped tests and `x` for tests which are skipped because [test execution exit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). Failed tests are listed separately after execution. This output type makes it easy to see are there any failures during execution even if there would be a lot of tests.
`quiet`
No output except for [errors and warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings).
`none`
No output whatsoever. Useful when creating a custom output using, for example, [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface).
Separate convenience options \--dotted (-.) and \--quiet are shortcuts for `--console dotted` and `--console quiet`, respectively.
Examples:
```
robot --console quiet tests.robot
robot --dotted tests.robot
```
#### [Console width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-546)
The width of the test execution output in the console can be set using the option \--consolewidth (-W). The default width is 78 characters.
Tip
On many UNIX-like machines you can use handy `$COLUMNS` environment variable like `--consolewidth $COLUMNS`.
#### [Console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-547)
The \--consolecolors (-C) option is used to control whether colors should be used in the console output. Colors are implemented using [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code) with a backup mechanism for older Windows versions that do not support ANSI codes.
This option supports the following case-insensitive values:
`auto`
Colors are enabled when outputs are written into the console, but not when they are redirected into a file or elsewhere. This is the default.
`on`
Colors are used also when outputs are redirected. Does not work on Windows.
`ansi`
Same as `on` but forces ANSI codes to be used unconditionally on Windows.
`off`
Colors are disabled.
Note
Using ANSI codes on Windows by default is new in Robot Framework 7.1.
#### [Console links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-548)
Result file paths written to the console at the end of the execution are, by default, hyperlinks. This behavior can be controlled with the \--consolelinks option that accepts the following case-insensitive values:
`auto`
Paths are converted to links when [console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) are enabled. This is the default.
`off`
Links are unconditionally disabled.
The hyperlink support depends also on the console that is used, but nowadays the [support is pretty good](https://github.com/Alhadis/OSC8-Adoption). The commonly used [Windows Console](https://en.wikipedia.org/wiki/Windows_Console) does not support links, though, but the newer [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal) does.
Note
Hyperlink support is new in Robot Framework 7.1.
#### [Console markers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-549)
Special markers `.` (success) and `F` (failure) are shown on the console when using the [verbose output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type) and top level keywords in test cases end. The markers allow following the test execution in high level, and they are erased when test cases end.
It is possible to configure when markers are used with \--consolemarkers (-K) option. It supports the following case-insensitive values:
`auto`
Markers are enabled when the standard output is written into the console, but not when it is redirected into a file or elsewhere. This is the default.
`on`
Markers are always used.
`off`
Markers are disabled.
### [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-550)
[Listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) can be used to monitor the test execution. When they are taken into use from the command line, they are specified using the \--listener command line option. The value can either be a path to a listener or a listener name. See the [Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) section for more details about importing listeners and using them in general.
## [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-444)
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\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files)
- [Output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory)
- [Output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file)
- [Log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file)
- [Report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file)
- [XUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file)
- [Debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file)
- [Timestamping output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files)
- [Setting titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles)
- [Setting background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors)
- [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels)
- [Available log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-log-levels)
- [Setting log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level)
- [Visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level)
- [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs)
- [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics)
- [Configuring displayed suite statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics)
- [Including and excluding tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics)
- [Generating combined tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics)
- [Creating links from tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names)
- [Adding documentation to tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags)
- [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords)
- [Removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords)
- [Flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keywords)
- [Flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keyword-during-execution-time)
- [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords)
- [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution)
- [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports)
- [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results)
- [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)
### [3\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-551)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-552)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-553)
Output files contain all execution results in machine readable XML or JSON format. [Log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file), [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [xUnit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit) files are typically generated based on them, and they can also be combined and otherwise post-processed with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). Various external tools also process output files to be able to show detailed execution information.
Tip
Generating [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [xUnit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit) files as part of test execution does not require processing output files after execution. Disabling [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) generation when running tests can thus save memory.
The command line option \--output (-o) determines the path where the output file is created. The path is relative to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) and the default value is output.xml when executing tests. When [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs) with Rebot, new output files are not created unless the \--output option is explicitly used.
It is possible to disable the output file by using a special value `NONE` with the \--output option. If no outputs are needed, they should all be explicitly disabled using `--output NONE --report NONE --log NONE`.
##### XML output format
Output files are created using XML by default. The XML output format is documented in the result.xsd [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
##### JSON output format
Robot Framework supports also JSON outputs and this format is used automatically if the output file extension is .json. The JSON output format is documented in the result.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
Note
JSON output files are supported during execution starting from Robot Framework 7.2. [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot) can create them based on XML output files already with Robot Framework 7.0.
##### Legacy XML format
There were some [backwards incompatible changes](https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.0.rst#changes-to-output-xml) to the XML output file format in Robot Framework 7.0. To make it possible to use new Robot Framework versions with external tools that are not yet updated to support the new format, there is a \--legacyoutput option that produces output files that are compatible with Robot Framework 6.x and earlier. Robot Framework itself can process output files both in the old and in the new formats.
We hope that external tools are updated soon, but we plan to support this option at least until Robot Framework 8.0. If you encounter tools that are not compatible, please inform the tool developers about changes.
#### [Log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-554)
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.
[](https://robotframework.org/robotframework/latest/images/log_passed.html)
An example of beginning of a log file
[](https://robotframework.org/robotframework/latest/images/log_failed.html)
An example of a log file with keyword details visible
[](https://robotframework.org/robotframework/latest/images/log_skipped.html)
An example of a log file with skipped and passed tests
#### [Report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-555)
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 tests pass and bright red if any test fails. Background can also be yellow, which means that all tests were [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped).
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.
[](https://robotframework.org/robotframework/latest/images/report_passed.html)
An example report file of successful test execution
[](https://robotframework.org/robotframework/latest/images/report_failed.html)
An example report file of failed test execution
#### [XUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-556)
XUnit result files contain the test execution summary in [xUnit](http://en.wikipedia.org/wiki/XUnit) compatible XML format. These files can thus be used as an input for external tools that understand xUnit reports. For example, [Jenkins](http://jenkins-ci.org/) continuous integration server supports generating statistics based on xUnit compatible results.
Tip
Jenkins also has a separate [Robot Framework plugin](https://wiki.jenkins-ci.org/display/JENKINS/Robot+Framework+Plugin).
XUnit output files are not created unless the command line option \--xunit (-x) is used explicitly. This option requires a path to the generated xUnit file, relatively to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory), as a value.
XUnit output files were changed pretty heavily in Robot Framework 5.0. They nowadays contain separate `<testsuite>` elements for each suite, `<testsuite>` elements have `timestamp` attribute, and [suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation) and [metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) is stored as `<property>` elements.
#### [Debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-557)
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 [fileviewer.py](https://bitbucket.org/robotframework/robottools/src/master/fileviewer/) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-558)
All output files generated by Robot Framework itself 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 output files like output-20080604-163225.xml and mylog-20080604-163225.html:
```
robot --timestampoutputs --log mylog.html --report NONE tests.robot
```
#### [Setting titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-559)
The default titles for [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) and [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) 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.
Example:
```
robot --logtitle "Smoke Test Log" --reporttitle "Smoke Test Report" --include smoke my_tests/
```
Note
Prior to Robot Framework 3.1, underscores in the given titles were converted to spaces. Nowadays spaces need to be escaped or quoted like in the example above.
#### [Setting background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-560)
By default the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) has red background if there are failures, green background if there are passed tests and possibly some skipped ones, and a yellow background if all tests are skipped or no tests have been run. 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 blue:red:orange
--reportbackground #00E:#E00
```
If you specify two colors, the first one will be used instead of the default green (pass) color and the second instead of the default red (fail). 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 two have same semantics as earlier and the last one replaces the default yellow (skip) color.
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, red and yellow colors are specified using hexadecimal values `#9e9`, `#f66` and `#fed84f`, respectively.
### [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-561)
#### [Available log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-562)
Messages in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) can have different log levels. Some of the messages are written by Robot Framework itself, but also executed keywords can [log information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) using different levels. The available log levels are:
`FAIL`
Used when a keyword fails. Can be used only by Robot Framework itself.
`ERROR`
Used for displaying errors. Errors are shown in [the console and in the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but they do not affect test case statuses. If the [\--exitonerror option is enabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error), errors stop the whole execution, though,
`WARN`
Used for displaying warnings. Warnings are shown in [the console and in the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but they do not affect test case statuses.
`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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-563)
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.
It is possible to use the \--loglevel option also when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown).
#### [Visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-564)
If the log file contains messages at `DEBUG` or `TRACE` levels, a visible log level drop down is shown in the upper right corner. This allows users to remove messages below chosen level from the view. This can be useful especially when running test at `TRACE` level.
[](https://robotframework.org/robotframework/latest/images/visible_log_level.html)
An example log showing the visible log level drop down
By default the drop down will be set at the lowest level in the log file, so that all messages are shown. The default visible log level can be changed using \--loglevel option by giving the default after the normal log level separated by a colon:
```
--loglevel DEBUG:INFO
```
In the above example, tests are run using level `DEBUG`, but the default visible level in the log file is `INFO`.
### [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-565)
Normally the log file is just a single HTML file. When the amount of the test cases increases, the size of the file can grow so large that opening it into a browser is inconvenient or even impossible. Hence, 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.
The JavaScript files are saved to the same directory where the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) itself is saved. It is the common [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) by default, but it can be changed with the \--log command line option.
Note
When copying the log files, you need to copy also all the log-\*.js files or some information will be missing.
### [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-566)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-567)
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. By 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-568)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names):
```
--tagstatinclude some-tag --tagstatinclude another-tag
--tagstatexclude owner-*
--tagstatinclude prefix-* --tagstatexclude prefix-13
```
#### [Generating combined tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-569)
The command line option \--tagstatcombine can be used to generate aggregate tags that combine statistics from multiple tags. The combined tags are specified using [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*` and `?` are supported as wildcards and `AND`, `OR` and `NOT` operators can be used for combining individual tags or patterns together.
The following examples illustrate creating combined tag statistics using different patterns, and the figure below shows a snippet of the resulting Statistics by Tag table:
```
--tagstatcombine owner-*
--tagstatcombine smokeANDmytag
--tagstatcombine smokeNOTowner-janne*
```

Examples of combined tag statistics
As the above example illustrates, the name of the added combined statistic is, by default, just the given pattern. If this is not good enough, it is possible to give a custom name after the pattern by separating them with a colon (`:`):
```
--tagstatcombine "prio1ORprio2:High priority tests"
```
Note
Prior to Robot Framework 3.1, underscores in the custom name were converted to spaces. Nowadays spaces need to be escaped or quoted like in the example above.
#### [Creating links from tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-570)
You can add external links to the Statistics by Tag table by using the command line option \--tagstatlink. Arguments to this option are given in the format `tag:link:name`, where `tag` specifies the tags to assign the link to, `link` is the link to be created, and `name` is the name to give to the link.
`tag` may be a single tag, but more commonly a [simple pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) where `*` matches anything and `?` matches any single character. When `tag` is a pattern, the matches to wildcards may be used in `link` and `title` with the syntax `%N`, where "N" is the index of the match starting from 1.
The following examples illustrate the usage of this option, and the figure below shows a snippet of the resulting Statistics by Tag table when example test data is executed with these options:
```
--tagstatlink mytag:http://www.google.com:Google
--tagstatlink example-bug-*:http://example.com
--tagstatlink owner-*:mailto:%1@domain.com?subject=Acceptance_Tests:Send_Mail
```

Examples of links from tag names
#### [Adding documentation to tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-571)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) matching multiple tags. `doc` is the assigned documentation.
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:Example
--tagdoc "regression:See http://example.com/info.html"
--tagdoc "owner-*:Original author"
```
Note
Prior to Robot Framework 3.1, underscores in the documentation were converted to spaces. Nowadays spaces need to be escaped or quoted like in the examples above.
### [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-572)
Most of the content of [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) comes from keywords and their log messages. When creating higher level reports, log files are not necessarily needed at all, and in that case keywords and their messages just take space unnecessarily. Log files themselves can also grow overly large, especially if they contain [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) or other constructs that repeat certain keywords multiple times.
In these situations, command line options \--removekeywords and \--flattenkeywords can be used to dispose or flatten unnecessary keywords. They can be used both when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). When used during execution, they only affect the log file, not the XML output file. With `rebot` they affect both logs and possibly generated new output XML files.
#### [Removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-573)
The \--removekeywords option removes keywords and their messages altogether. It has the following modes of operation, and it can be used multiple times to enable multiple modes. Keywords that contain [errors or warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings) are not removed except when using the `ALL` mode.
`ALL`
Remove data from all keywords unconditionally.
`PASSED`
Remove keyword data from passed test cases. In most cases, log files created using this option contain enough information to investigate possible failures.
`FOR`
Remove all passed iterations from [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) except the last one.
`WHILE`
Remove all passed iterations from [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) except the last one.
`WUKS`
Remove all failing keywords inside [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Wait Until Keyword Succeeds except the last one.
`NAME:<pattern>`
Remove data from all keywords matching the given pattern regardless the keyword status. The pattern is matched against the full name of the keyword, prefixed with the possible library or resource file name like `MyLibrary.Keyword Name`. The pattern is case, space, and underscore insensitive, and it supports [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) with `*`, `?` and `[]` as wildcards.
`TAG:<pattern>`
Remove data from keywords with tags that match the given pattern. Tags are case and space insensitive and they can be specified using [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*`, `?` and `[]` are supported as wildcards and `AND`, `OR` and `NOT` operators can be used for combining individual tags or patterns together. Can be used both with [library keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) and [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags).
Examples:
```
rebot --removekeywords all --output removed.xml output.xml
robot --removekeywords passed --removekeywords for tests.robot
robot --removekeywords name:HugeKeyword --removekeywords name:resource.* tests.robot
robot --removekeywords tag:huge tests.robot
```
Removing keywords is done after parsing the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and generating an internal model based on it. Thus it does not reduce memory usage as much as [flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keywords).
#### [Flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-574)
The \--flattenkeywords option flattens matching keywords. In practice this means that matching keywords get all log messages from their child keywords, recursively, and child keywords are discarded otherwise. Flattening supports the following modes:
`FOR`
Flatten [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) fully.
`WHILE`
Flatten [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) fully.
`ITERATION`
Flatten individual `FOR` and `WHILE` loop iterations.
`FORITEM`
Deprecated alias for `ITERATION`.
`NAME:<pattern>`
Flatten keywords matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `NAME:<pattern>` mode.
`TAG:<pattern>`
Flatten keywords with tags matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `TAG:<pattern>` mode.
Examples:
```
robot --flattenkeywords name:HugeKeyword --flattenkeywords name:resource.* tests.robot
rebot --flattenkeywords foritem --output flattened.xml original.xml
```
Flattening keywords is done already when the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is parsed initially. This can save a significant amount of memory especially with deeply nested keyword structures.
#### [Flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-575)
Starting from Robot Framework 6.1, it is possible to enable the keyword flattening during the execution time. This can be done only on an user keyword level by defining the [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) `robot:flatten` as a [keyword tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags). Using this tag will work similarly as the command line option described in the previous chapter, e.g. all content except for log messages is removed from under the keyword having the tag. One important difference is that in this case, the removed content is not written to the output file at all, and thus cannot be accessed at later time.
```
*** Keywords ***
Example
[Tags] robot:flatten
Log Keywords and the loop are removed, but logged messages are preserved.
FOR ${i} IN RANGE 1 101
Log Iteration ${i}/100.
END
```
### [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-576)
Keywords that have passed are closed in the log file by default. Thus information they contain is not visible unless you expand them. If certain keywords have important information that should be visible when the log file is opened, you can use the \--expandkeywords option to set keywords automatically expanded in log file similar to failed keywords. Expanding supports the following modes:
`NAME:<pattern>`
Expand keywords matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `NAME:<pattern>` mode.
`TAG:<pattern>`
Expand keywords with tags matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `TAG:<pattern>` mode.
If you need to expand keywords matching different names or patterns, you can use the \--expandkeywords multiple times.
Examples:
```
robot --expandkeywords name:SeleniumLibrary.CapturePageScreenshot tests.robot
rebot --expandkeywords tag:example --expandkeywords tag:another output.xml
```
Note
The \--expandkeywords option is new in Robot Framework 3.2.
### [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-577)
When [combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs) using Rebot, 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.
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 , where all separators are optional and the parts from milliseconds to hours can be omitted. For example, 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
```
### [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-578)
If a test case fails and has a long error message, the message shown in [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is automatically cut from the middle to keep reports easier to read. By default messages longer than 40 lines are cut, but that can be configured by using the \--maxerrorlines command line option. The minimum value for this option is 10, and it is also possible to use a special value `NONE` to show the full message.
Full error messages are always visible in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as messages of the failed keywords.
Note
The \--maxerrorlines option is new in Robot Framework 3.1.
### [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-579)
If the provided built-in features to modify results are not enough, Robot Framework makes it possible to do custom modifications programmatically. This is accomplished by creating a model modifier and activating it using the \--prerebotmodifier option.
This functionality works nearly exactly like [programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data) that can be enabled with the \--prerunmodifier option. The obvious difference is that this time modifiers operate with the [result model](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#module-robot.result.model), not the [running model](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#module-robot.running.model). For example, the following modifier marks all passed tests that have taken more time than allowed as failed:
```
from robot.api import SuiteVisitor
class ExecutionTimeChecker(SuiteVisitor):
def __init__(self, max_seconds: float):
self.max_milliseconds = max_seconds * 1000
def visit_test(self, test):
if test.status == 'PASS' and test.elapsedtime > self.max_milliseconds:
test.status = 'FAIL'
test.message = 'Test execution took too long.'
```
If the above modifier would be in file ExecutionTimeChecker.py, it could be used, for example, like this:
```
# Specify modifier as a path when running tests. Maximum time is 42 seconds.
robot --prerebotmodifier path/to/ExecutionTimeChecker.py:42 tests.robot
# Specify modifier as a name when using Rebot. Maximum time is 3.14 seconds.
# ExecutionTimeChecker.py must be in the module search path.
rebot --prerebotmodifier ExecutionTimeChecker:3.14 output.xml
```
If more than one model modifier is needed, they can be specified by using the \--prerebotmodifier option multiple times. When executing tests, it is possible to use \--prerunmodifier and \--prerebotmodifier options together.
### [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-580)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) 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
robot --name Syslog_example path/to/tests
```
# [4 Extending Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-126)
- [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries)
- [4\.2 Remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface)
- [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface)
- [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface)
## [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-581)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-128)
#### Supported programming languages
Robot Framework itself is written with [Python](http://python.org/) and naturally test libraries extending it can be implemented using the same language. It is also possible to implement libraries with C using [Python C API](http://docs.python.org/c-api/index.html), although it is often easier to interact with C code from Python libraries using [ctypes](http://docs.python.org/library/ctypes.html) module.
Libraries implemented using Python can also act as wrappers to functionality implemented using other programming languages. A good example of this approach is the [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library), and another widely used approaches is running external scripts or tools as separate processes.
#### Different test library APIs
Robot Framework has three different test library APIs.
Static API
> The simplest approach is having a module or a class with functions/methods which map directly to [keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-names). Keywords also take the same [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) as the methods implementing them. Keywords [report failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) with exceptions, [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) by writing to standard output and can [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#returning-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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) and the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api) differ from it is then discussed in sections of their own.
### [4\.1.2 Creating test library class or module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-129)
Test libraries can be implemented as Python modules or classes.
#### Library name
As discussed under the [Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) section, libraries can be [imported by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import):
```
*** Settings ***
Library MyLibrary
Library module.LibraryClass
Library path/AnotherLibrary.py
```
When a library is imported by a name, the library module must be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) and the name can either refer to a library module or to a library class. When a name refers directly to a library class, the name must be in format like `modulename.ClassName`. Paths to libraries always refer to modules.
Even when a library import refers to a module, either by a name or by a path, a class in the module, not the module itself, is used as a library in these cases:
1. If the module contains a class that has the same name as the module. The class can be either implemented in the module or imported into it.
This makes it possible to import libraries using simple names like `MyLibrary` instead of specifying both the module and the class like `module.MyLibrary` or `MyLibrary.MyLibrary`. When importing a library by a path, it is not even possible to directly refer to a library class and automatically using a class from the imported module is the only option.
2. If the module contains exactly one class decorated with the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator). In this case the class needs to be implemented in the module, not imported to it.
This approach has all the same benefits as the earlier one, but it also allows the class name to differ from the module name.
Using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) for this purpose is new in Robot Framework 7.2.
Tip
If the library name is really long, it is often a good idea to give it a [simpler alias](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) at the import time.
#### Providing arguments to libraries
All test libraries implemented as classes can take arguments. These arguments are specified after the library name when the library is imported, 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.
The number of arguments needed by the library is the same as the number of arguments accepted by the library's `__init__` method. The default values, argument conversion, and other such features work the same way as with [keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments). 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.
```
*** Settings ***
Library MyLibrary 10.0.0.1 8080
Library AnotherLib ${ENVIRONMENT}
```
Example implementations for the libraries used in the above example:
```
from example import Connection
class MyLibrary:
def __init__(self, host, port=80):
self.connection = Connection(host, port)
def send_message(self, message):
self.connection.send(message)
```
```
class AnotherLib:
def __init__(self, environment):
self.environment = environment
def do_something(self):
if self.environment == 'test':
do_something_in_test_environment()
else:
do_something_in_other_environments()
```
If a library is imported multiple times with different arguments within a single suite, it needs to be given a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) or otherwise latter imports are ignored:
```
*** Settings ***
Library MyLibrary 10.0.0.1 8080 AS RemoteLibrary
Library MyLibrary 127.0.0.1 AS LocalLibrary
*** Test Cases ***
Example
RemoteLibrary.Send Message Hello!
LocalLibrary.Send Message Hi!
```
#### 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`
A new instance is created for every test case. A possible suite setup and suite teardown share yet another instance.
Prior to Robot Framework 3.2 this value was `TEST CASE`, but nowadays `TEST` is recommended. Because all unrecognized values are considered same as `TEST`, both values work with all versions. For the same reason it is possible to also use value `TASK` if the library is targeted for [RPA](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rpa) usage more than testing. `TEST` is also the default value if the `ROBOT_LIBRARY_SCOPE` attribute is not set.
`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.
Prior to Robot Framework 3.2 this value was `TEST SUITE`. That value still works, but `SUITE` is recommended with libraries targeting Robot Framework 3.2 and newer.
`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.
Note
If a library is imported multiple times with different [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#providing-arguments-to-libraries), a new instance is created every time regardless the scope.
When the `SUITE` or `GLOBAL` scopes are used with 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 opened browsers.
Example library using the `SUITE` scope:
```
class ExampleLibrary:
ROBOT_LIBRARY_SCOPE = 'SUITE'
def __init__(self):
self._counter = 0
def count(self):
self._counter += 1
print(self._counter)
def clear_count(self):
self._counter = 0
```
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) to provide debugging information. Library documentation tool [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) also writes this information into the keyword documentations it generates.
Version information is read from attribute `ROBOT_LIBRARY_VERSION`, similarly as [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
An example module using `__version__`:
```
__version__ = '0.1'
def keyword():
pass
```
#### Documentation format
Library documentation tool [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) supports documentation in multiple formats. If you want to use something else than Robot Framework's own [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting), you can specify the format in the source code using `ROBOT_LIBRARY_DOC_FORMAT` attribute similarly as [scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope) and [version](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version) are set with their own `ROBOT_LIBRARY_*` attributes.
The possible case-insensitive values for documentation format are `ROBOT` (default), `HTML`, `TEXT` (plain text), and `reST` ([reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText)). Using the `reST` format requires the [docutils](https://pypi.python.org/pypi/docutils) module to be installed when documentation is generated.
Setting the documentation format is illustrated by the following example that uses reStructuredText format. See [Documenting libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-libraries) section and [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) chapter for more information about documenting test libraries in general.
```
"""A library for *documentation format* demonstration purposes.
This documentation is created using reStructuredText__. Here is a link
to the only \`Keyword\`.
__ http://docutils.sourceforge.net
"""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def keyword():
"""**Nothing** to see here. Not even in the table below.
======= ===== =====
Table here has
nothing to see.
======= ===== =====
"""
pass
```
#### Library acting as listener
[Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) allows external listeners to get notifications about test execution. They are called, for example, when suites, tests, and keywords start and end. Sometimes getting such notifications is also useful for test libraries, and they can register a custom listener by using `ROBOT_LIBRARY_LISTENER` attribute. The value of this attribute should be an instance of the listener to use, possibly the library itself.
For more information and examples see [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners) section.
#### `@library` decorator
An easy way to configure libraries implemented as classes is using the `robot.api.deco.library` class decorator. It allows configuring library's [scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope), [version](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version), [custom argument converters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters), [documentation format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) and [listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-acting-as-listener) with optional arguments `scope`, `version`, `converter`, `doc_format` and `listener`, respectively. When these arguments are used, they set the matching `ROBOT_LIBRARY_SCOPE`, `ROBOT_LIBRARY_VERSION`, `ROBOT_LIBRARY_CONVERTERS`, `ROBOT_LIBRARY_DOC_FORMAT` and `ROBOT_LIBRARY_LISTENER` attributes automatically:
```
from robot.api.deco import library
from example import Listener
@library(scope='GLOBAL', version='3.2b1', doc_format='reST', listener=Listener())
class Example:
...
```
The `@library` decorator also disables the [automatic keyword discovery](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#what-methods-are-considered-keywords) by setting the `ROBOT_AUTO_KEYWORDS` argument to `False` by default. This means that it is mandatory to decorate methods with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) to expose them as keywords. If only that behavior is desired and no further configuration is needed, the decorator can also be used without parenthesis like:
```
from robot.api.deco import library
@library
class Example:
...
```
If needed, the automatic keyword discovery can be enabled by using the `auto_keywords` argument:
```
from robot.api.deco import library
@library(scope='GLOBAL', auto_keywords=True)
class Example:
...
```
The `@library` decorator only sets class attributes `ROBOT_LIBRARY_SCOPE`, `ROBOT_LIBRARY_VERSION`, `ROBOT_LIBRARY_CONVERTERS`, `ROBOT_LIBRARY_DOC_FORMAT` and `ROBOT_LIBRARY_LISTENER` if the respective arguments `scope`, `version`, `converters`, `doc_format` and `listener` are used. The `ROBOT_AUTO_KEYWORDS` attribute is set always and its presence can be used as an indication that the `@library` decorator has been used. When attributes are set, they override possible existing class attributes.
When a class is decorated with the `@library` decorator, it is used as a library even when a [library import refers only to a module containing it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-name). This is done regardless does the class name match the module name or not.
Note
The `@library` decorator is new in Robot Framework 3.2, the `converters` argument is new in Robot Framework 5.0, and specifying that a class in an imported module should be used as a library is new in Robot Framework 7.2.
### [4\.1.3 Creating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-130)
#### What methods are considered keywords
When the static library API is used, Robot Framework uses introspection to find out what keywords the library class or module implements. By default it excludes methods and functions starting with an underscore. All the methods and functions that are not ignored are considered keywords. For example, the library below implements a single keyword My Keyword.
```
class MyLibrary:
def my_keyword(self, arg):
return self._helper_method(arg)
def _helper_method(self, arg):
return arg.upper()
```
#### Limiting public methods becoming keywords
Automatically considering all public methods and functions keywords typically works well, but there are cases where it is not desired. There are also situations where keywords are created when not expected. For example, when implementing a library as class, it can be a surprise that also methods in possible base classes are considered keywords. When implementing a library as a module, functions imported into the module namespace becoming keywords is probably even a bigger surprise.
This section explains how to prevent methods and functions becoming keywords.
##### Class based libraries
When a library is implemented as a class, it is possible to tell Robot Framework not to automatically expose methods as keywords by setting the `ROBOT_AUTO_KEYWORDS` attribute to the class with a false value:
```
class Example:
ROBOT_AUTO_KEYWORDS = False
```
When the `ROBOT_AUTO_KEYWORDS` attribute is set like this, only methods that have explicitly been decorated with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) or otherwise have the `robot_name` attribute become keywords. The `@keyword` decorator can also be used for setting a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name), [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) and [argument types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) to the keyword.
Although the `ROBOT_AUTO_KEYWORDS` attribute can be set to the class explicitly, it is more convenient to use the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) that sets it to `False` by default:
```
from robot.api.deco import keyword, library
@library
class Example:
@keyword
def this_is_keyword(self):
pass
@keyword('This is keyword with custom name')
def xxx(self):
pass
def this_is_not_keyword(self):
pass
```
Note
Both limiting what methods become keywords using the `ROBOT_AUTO_KEYWORDS` attribute and the `@library` decorator are new in Robot Framework 3.2.
Another way to explicitly specify what keywords a library implements is using the [dynamic](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or the [hybrid](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api) library API.
##### Module based libraries
When implementing a library as a module, all functions in the module namespace become keywords. This is true also with imported functions, and that can cause nasty surprises. For example, if the module below would be used as a library, it would contain a keyword Example Keyword, as expected, but also a keyword Current Thread.
```
from threading import current_thread
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
```
A simple way to avoid imported functions becoming keywords is to only import modules (e.g. `import threading`) and to use functions via the module (e.g `threading.current_thread()`). Alternatively functions could be given an alias starting with an underscore at the import time (e.g. `from threading import current_thread as _current_thread`).
A more explicit way to limit what functions become keywords is using the module level `__all__` attribute that [Python itself uses for similar purposes](https://docs.python.org/tutorial/modules.html#importing-from-a-package). If it is used, only the listed functions can be keywords. For example, the library below implements only one keyword Example Keyword:
```
from threading import current_thread
__all__ = ['example_keyword']
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
def this_is_not_keyword():
pass
```
If the library is big, maintaining the `__all__` attribute when keywords are added, removed or renamed can be a somewhat big task. Another way to explicitly mark what functions are keywords is using the `ROBOT_AUTO_KEYWORDS` attribute similarly as it can be used with [class based libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#class-based-libraries). When this attribute is set to a false value, only functions explicitly decorated with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) become keywords. For example, also this library implements only one keyword Example Keyword:
```
from threading import current_thread
from robot.api.deco import keyword
ROBOT_AUTO_KEYWORDS = False
@keyword
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
def this_is_not_keyword():
pass
```
Note
Limiting what functions become keywords using `ROBOT_AUTO_KEYWORDS` is a new feature in Robot Framework 3.2.
##### Using `@not_keyword` decorator
Functions in modules and methods in classes can be explicitly marked as "not keywords" by using the `@not_keyword` decorator. When a library is implemented as a module, this decorator can also be used to avoid imported functions becoming keywords.
```
from threading import current_thread
from robot.api.deco import not_keyword
not_keyword(current_thread) # Don't expose `current_thread` as a keyword.
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
@not_keyword
def this_is_not_keyword():
pass
```
Using the `@not_keyword` decorator is pretty much the opposite way to avoid functions or methods becoming keywords compared to disabling the automatic keyword discovery with the `@library` decorator or by setting the `ROBOT_AUTO_KEYWORDS` to a false value. Which one to use depends on the context.
Note
The `@not_keyword` decorator is new in Robot Framework 3.2.
#### 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 library implemented as a module in the MyLibrary.py file:
```
def hello(name):
print(f"Hello, {name}!")
def do_nothing():
pass
```
The example below illustrates how the example library above can be used. If you want to try this yourself, make sure that the library is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
```
*** Settings ***
Library MyLibrary
*** Test Cases ***
My Test
Do Nothing
Hello world
```
##### Setting custom name
It is possible to expose a different name for a keyword instead of the default keyword name which maps to the method name. This can be accomplished by setting the `robot_name` attribute on the method to the desired custom name:
```
def login(username, password):
...
login.robot_name = 'Login via user panel'
```
```
*** Test Cases ***
My Test
Login Via User Panel ${username} ${password}
```
Instead of explicitly setting the `robot_name` attribute like in the above example, it is typically easiest to use the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator):
```
from robot.api.deco import keyword
@keyword('Login via user panel')
def login(username, password):
...
```
Using this decorator without an argument will have no effect on the exposed keyword name, but will still set the `robot_name` attribute. This allows [marking methods to expose as keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#marking-methods-to-expose-as-keywords) without actually changing keyword names. Methods that have the `robot_name` attribute also create keywords even if the method name itself would start with an underscore.
Setting a custom keyword name can also enable library keywords to accept arguments using the [embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names) syntax.
#### Keyword tags
Library keywords and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) can have tags. Library keywords can define them by setting the `robot_tags` attribute on the method to a list of desired tags. Similarly as when [setting custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name), it is easiest to set this attribute by using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator):
```
from robot.api.deco import keyword
@keyword(tags=['tag1', 'tag2'])
def login(username, password):
...
@keyword('Custom name', ['tags', 'here'])
def another_example():
...
```
Another option for setting tags is giving them on the last line of [keyword documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-libraries) with `Tags:` prefix and separated by a comma. For example:
```
def login(username, password):
"""Log user in to SUT.
Tags: tag1, tag2
"""
...
```
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) have other means for sharing this information, so this section is not relevant to them.
The most common and also the simplest situation is when a keyword needs an exact number of arguments. In this case, the method 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 keywords taking different numbers of arguments:
```
def no_arguments():
print("Keyword got no arguments.")
def one_argument(arg):
print(f"Keyword got one argument '{arg}'.")
def three_arguments(a1, a2, a3):
print(f"Keyword got three arguments '{a1}', '{a2}' and '{a3}'.")
```
#### Default values to keywords
It is often useful that some of the arguments that a keyword uses have default values.
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(f"Got argument '{arg}'.")
def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
print(f"Got arguments '{arg1}', '{arg2}' and '{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.
```
*** Test Cases ***
Defaults
One Default
One Default argument
Multiple Defaults required arg
Multiple Defaults required arg optional
Multiple Defaults required arg optional 1 optional 2
```
#### Variable number of arguments (`*varargs`)
Robot Framework supports also keywords that take any number of arguments.
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(f"Required: {required}\nOthers:")
for arg in others:
print(arg)
def also_defaults(req, def1="default 1", def2="default 2", *rest):
print(req, def1, def2, rest)
```
```
*** Test Cases ***
Varargs
Any Arguments
Any Arguments argument
Any Arguments arg 1 arg 2 arg 3 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
```
#### Free keyword arguments (`**kwargs`)
Robot Framework supports [Python's \*\*kwargs syntax](https://docs.python.org/tutorial/controlflow.html#keyword-arguments). How to use use keywords that accept *free keyword arguments*, also known as *free named arguments*, is [discussed under the Creating test cases section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments). In this section we take a look at how to create such keywords.
If you are already familiar how kwargs work with Python, understanding how they work with Robot Framework test libraries is rather simple. The example below shows the basic functionality:
```
def example_keyword(**stuff):
for name, value in stuff.items():
print(name, value)
```
```
*** Test Cases ***
Keyword Arguments
Example Keyword hello=world # Logs 'hello world'.
Example Keyword foo=1 bar=42 # Logs 'foo 1' and 'bar 42'.
```
Basically, all arguments at the end of the keyword call that use the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) `name=value`, and that do not match any other arguments, are passed to the keyword as kwargs. To avoid using a literal value like `foo=quux` as a free keyword argument, it must be [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) like `foo\=quux`.
The following example illustrates how normal arguments, varargs, and kwargs work together:
```
def various_args(arg=None, *varargs, **kwargs):
if arg is not None:
print('arg:', arg)
for value in varargs:
print('vararg:', value)
for name, value in sorted(kwargs.items()):
print('kwarg:', name, value)
```
```
*** Test Cases ***
Positional
Various Args hello world # Logs 'arg: hello' and 'vararg: world'.
Named
Various Args arg=value # Logs 'arg: value'.
Kwargs
Various Args a=1 b=2 c=3 # Logs 'kwarg: a 1', 'kwarg: b 2' and 'kwarg: c 3'.
Various Args c=3 a=1 b=2 # Same as above. Order does not matter.
Positional and kwargs
Various Args 1 2 kw=3 # Logs 'arg: 1', 'vararg: 2' and 'kwarg: kw 3'.
Named and kwargs
Various Args arg=value hello=world # Logs 'arg: value' and 'kwarg: hello world'.
Various Args hello=world arg=value # Same as above. Order does not matter.
```
For a real world example of using a signature exactly like in the above example, see Run Process and Start Keyword keywords in the [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library.
#### Keyword-only arguments
Starting from Robot Framework 3.1, it is possible to use [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) with different keywords. This support is provided by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102). Keyword-only arguments are specified after possible `*varargs` or after a dedicated `*` marker when `*varargs` are not needed. Possible `**kwargs` are specified after keyword-only arguments.
Example:
```
def sort_words(*words, case_sensitive=False):
key = str.lower if case_sensitive else None
return sorted(words, key=key)
def strip_spaces(word, *, left=True, right=True):
if left:
word = word.lstrip()
if right:
word = word.rstrip()
return word
```
```
*** Test Cases ***
Example
Sort Words Foo bar baZ
Sort Words Foo bar baZ case_sensitive=True
Strip Spaces ${word} left=False
```
#### Positional-only arguments
Python supports so called [positional-only arguments](https://www.python.org/dev/peps/pep-0570/) that make it possible to specify that an argument can only be given as a [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-argument), not as a [named argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument) like `name=value`. Positional-only arguments are specified before normal arguments and a special `/` marker must be used after them:
```
def keyword(posonly, /, normal):
print(f"Got positional-only argument {posonly} and normal argument {normal}.")
```
The above keyword could be used like this:
```
*** Test Cases ***
Example
# Positional-only and normal argument used as positional arguments.
Keyword foo bar
# Normal argument can also be named.
Keyword foo normal=bar
```
If a positional-only argument is used with a value that contains an equal sign like `example=usage`, it is not considered to mean [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) even if the part before the `=` would match the argument name. This rule only applies if the positional-only argument is used in its correct position without other arguments using the name argument syntax before it, though.
```
*** Test Cases ***
Example
# Positional-only argument gets literal value `posonly=foo` in this case.
Keyword posonly=foo normal=bar
# This fails.
Keyword normal=bar posonly=foo
```
Positional-only arguments are fully supported starting from Robot Framework 4.0. Using them as positional arguments works also with earlier versions, but using them as named arguments causes an error on Python side.
#### Argument conversion
Arguments defined in Robot Framework test data are, by default, passed to keywords as Unicode strings. There are, however, several ways to use non-string values as well:
- [Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can contain any kind of objects as values, and variables used as arguments are passed to keywords as-is.
- Keywords can themselves [convert arguments they accept](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#manual-argument-conversion) to other types.
- It is possible to specify argument types explicitly using [function annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) or the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator). In these cases Robot Framework converts arguments automatically.
- Automatic conversion is also done based on [keyword default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values).
- Libraries can register [custom argument converters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters).
Automatic argument conversion based on function annotations, types specified using the `@keyword` decorator, and argument default values are all new features in Robot Framework 3.1. The [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section specifies which argument conversion are supported in these cases.
Prior to Robot Framework 4.0, automatic conversion was done only if the given argument was a string. Nowadays it is done regardless the argument type.
##### Manual argument conversion
If no type information is specified to Robot Framework, all arguments not passed as [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) are given to keywords as Unicode strings. This includes cases like this:
```
*** Test Cases ***
Example
Example Keyword 42 False
```
It is always possible to convert arguments passed as strings insider keywords. In simple cases this means using `int()` or `float()` to convert arguments to numbers, but other kind of conversion is possible as well. When working with Boolean values, care must be taken because all non-empty strings, including string `False`, are considered true by Python. Robot Framework's own `robot.utils.is_truthy()` utility handles this nicely as it considers strings like `FALSE`, `NO` and `NONE` (case-insensitively) to be false:
```
from robot.utils import is_truthy
def example_keyword(count, case_insensitive):
count = int(count)
if is_truthy(case_insensitive):
...
```
Keywords can also use Robot Framework's argument conversion functionality via the [robot.api.TypeInfo](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.arguments.html#robot.running.arguments.typeinfo.TypeInfo) class and its `convert` method. This can be useful if the needed conversion logic is more complicated or the are needs for better error reporting than what simply using, for example, `int()` provides.
```
from robot.api import TypeInfo
def example_keyword(count, case_insensitive):
count = TypeInfo.from_type(int).convert(count)
if TypeInfo.from_type(bool).convert(case_insensitive):
...
```
Tip
It is generally recommended to specify types using type hints or otherwise and let Robot Framework handle argument conversion automatically. Manual argument conversion should only be needed in special cases.
Note
`robot.api.TypeInfo` is new in Robot Framework 7.0.
##### Specifying argument types using function annotations
Starting from Robot Framework 3.1, arguments passed to keywords are automatically converted if argument type information is available and the type is recognized. The most natural way to specify types is using Python [function annotations](https://www.python.org/dev/peps/pep-3107/). For example, the keyword in the previous example could be implemented as follows and arguments would be converted automatically:
```
def example_keyword(count: int, case_insensitive: bool = True):
if case_insensitive:
...
```
See the [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section below for a list of types that are automatically converted and what values these types accept. It is an error if an argument having one of the supported types is given a value that cannot be converted. Annotating only some of the arguments is fine.
Annotating arguments with other than the supported types is not an error, and it is also possible to use annotations for other than typing purposes. In those cases no conversion is done, but annotations are nevertheless shown in the documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc).
Keywords can also have a return type annotation specified using the `->` notation at the end of the signature like `def example() -> int:`. This information is not used for anything during execution, but starting from Robot Framework 7.0 it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
##### Specifying argument types using `@keyword` decorator
An alternative way to specify explicit argument types is using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator). Starting from Robot Framework 3.1, it accepts an optional `types` argument that can be used to specify argument types either as a dictionary mapping argument names to types or as a list mapping arguments to types based on position. These approaches are shown below implementing the same keyword as in earlier examples:
```
from robot.api.deco import keyword
@keyword(types={'count': int, 'case_insensitive': bool})
def example_keyword(count, case_insensitive=True):
if case_insensitive:
...
@keyword(types=[int, bool])
def example_keyword(count, case_insensitive=True):
if case_insensitive:
...
```
Regardless of the approach that is used, it is not necessarily to specify types for all arguments. When specifying types as a list, it is possible to use `None` to mark that a certain argument does not have type information and arguments at the end can be omitted altogether. For example, both of these keywords specify the type only for the second argument:
```
@keyword(types={'second': float})
def example1(first, second, third):
...
@keyword(types=[None, float])
def example2(first, second, third):
...
```
Starting from Robot Framework 7.0, it is possible to specify the keyword return type by using key `'return'` with an appropriate type in the type dictionary. This information is not used for anything during execution, but it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
If any types are specified using the `@keyword` decorator, type information got from [annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) is ignored with that keyword. Setting `types` to `None` like `@keyword(types=None)` disables type conversion altogether so that also type information got from [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) is ignored.
##### Implicit argument types based on default values
If type information is not got explicitly using annotations or the `@keyword` decorator, Robot Framework 3.1 and newer tries to get it based on possible argument default value. In this example `count` and `case_insensitive` get types `int` and `bool`, respectively:
```
def example_keyword(count=-1, case_insensitive=True):
if case_insensitive:
...
```
When type information is got implicitly based on the default values, argument conversion itself is not as strict as when the information is got explicitly:
- Conversion may be attempted also to other "similar" types. For example, if converting to an integer fails, float conversion is attempted.
- Conversion failures are not errors, keywords get the original value in these cases instead.
If an argument has an explicit type and a default value, conversion is first attempted based on the explicit type. If that fails, then conversion is attempted based on the default value. In this special case conversion based on the default value is strict and a conversion failure causes an error.
If argument conversion based on default values is not desired, the whole argument conversion can be disabled with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) like `@keyword(types=None)`.
Note
Prior to Robot Framework 4.0 conversion was done based on the default value only if the argument did not have an explict type.
##### Supported conversions
The table below lists the types that Robot Framework 3.1 and newer convert arguments to. These characteristics apply to all conversions:
- Type can be explicitly specified using [function annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) or the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator).
- If not explicitly specified, type can be got implicitly from [argument default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values).
- Conversion is done regardless of the type of the given argument. If the argument type is incompatible with the expected type, conversion fails.
- Conversion failures cause an error if the type has been specified explicitly. If the type is got based on a default value, the given argument is used as-is.
Note
If an argument has both a type hint and a default value, conversion is first attempted based on the type hint and then, if that fails, based on the default value type. This behavior is likely to change in the future so that conversion based on the default value is done *only* if the argument does not have a type hint. That will change conversion behavior in cases like `arg: list = None` where `None` conversion will not be attempted anymore. Library creators are strongly recommended to specify the default value type explicitly like `arg: list | None = None` already now.
The type to use can be specified either using concrete types (e.g. [list](https://docs.python.org/library/stdtypes.html#list)), by using abstract base classes (ABC) (e.g. [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence)), or by using sub classes of these types (e.g. [MutableSequence](https://docs.python.org/library/collections.abc.html#collections.abc.MutableSequence)). Also types in in the [typing](https://docs.python.org/library/typing.html) module that map to the supported concrete types or ABCs (e.g. `List`) are supported. In all these cases the argument is converted to the concrete type.
In addition to using the actual types (e.g. `int`), it is possible to specify the type using type names as a string (e.g. `'int'`) and some types also have aliases (e.g. `'integer'`). Matching types to names and aliases is case-insensitive.
The Accepts column specifies which given argument types are converted. If the given argument already has the expected type, no conversion is done. Other types cause conversion failures.
| Type | ABC | Aliases | Accepts | Explanation | Examples |
|---|---|---|---|---|---|
| [bool](https://docs.python.org/library/functions.html#bool) | | boolean | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float), [None](https://docs.python.org/library/constants.html#None) | Strings `TRUE`, `YES`, `ON` and `1` are converted to `True`, the empty string as well as `FALSE`, `NO`, `OFF` and `0` are converted to `False`, and the string `NONE` is converted to `None`. Other strings and other accepted values are passed as-is, allowing keywords to handle them specially if needed. All string comparisons are case-insensitive. True and false strings can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations. | `TRUE` (converted to `True`) `off` (converted to `False`) `example` (used as-is) |
| [int](https://docs.python.org/library/functions.html#int) | [Integral](https://docs.python.org/library/numbers.html#numbers.Integral) | integer, long | [str](https://docs.python.org/library/functions.html#func-str), [float](https://docs.python.org/library/functions.html#float) | Conversion is done using the [int](https://docs.python.org/library/functions.html#int) built-in function. Floats are accepted only if they can be represented as integers exactly. For example, `1.0` is accepted and `1.1` is not. If converting a string to an integer fails and the type is got implicitly based on a default value, conversion to float is attempted as well. Starting from Robot Framework 4.1, it is possible to use hexadecimal, octal and binary numbers by prefixing values with `0x`, `0o` and `0b`, respectively. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. Starting from Robot Framework 7.0, strings representing floats are accepted as long as their decimal part is zero. This includes using the scientific notation like `1e100`. | `42` `-1` `10 000 000` `1e100` `0xFF` `0o777` `0b1010` `0xBAD_C0FFEE` `${1}` `${1.0}` |
| [float](https://docs.python.org/library/functions.html#float) | [Real](https://docs.python.org/library/numbers.html#numbers.Real) | double | [str](https://docs.python.org/library/functions.html#func-str), [Real](https://docs.python.org/library/numbers.html#numbers.Real) | Conversion is done using the [float](https://docs.python.org/library/functions.html#float) built-in. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. | `3.14` `2.9979e8` `10 000.000 01` `10_000.000_01` |
| [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | Conversion is done using the [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) class. [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) is recommended over [float](https://docs.python.org/library/functions.html#float) when decimal numbers need to be represented exactly. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. | `3.14` `10 000.000 01` `10_000.000_01` |
| [str](https://docs.python.org/library/functions.html#func-str) | | string, unicode | Anything | All arguments are converted to Unicode strings. Most values are converted simply by using `str(value)`. An exception is that bytes are mapped directly to Unicode code points with same ordinals. This means that, for example, `b"hyv\xe4"` becomes `"hyvä"`. Another exception is that [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) objects are explicitly rejected. New in Robot Framework 4.0. Converting bytes specially and rejecting `Secret` objects are new in Robot Framework 7.4. | |
| [bytes](https://docs.python.org/library/functions.html#func-bytes) | | | [str](https://docs.python.org/library/functions.html#func-str), [bytearray](https://docs.python.org/library/functions.html#func-bytearray) | Strings are converted to bytes so that each Unicode code point below 256 is directly mapped to a matching byte. Higher code points are not allowed. Integers and sequences of integers are converted to matching bytes directly. They must be in range 0-255. Support for integers and sequences of integers is new in Robot Framework 7.4. | Strings: `good` `hyvä` (converted to `hyv\xe4`) `\x00` (converted to the null byte) Integers and sequences of integers: `0` (converted to the null byte) `[82, 70, 33]` (converted to `RF!`) |
| [bytearray](https://docs.python.org/library/functions.html#func-bytearray) | | | [str](https://docs.python.org/library/functions.html#func-str), [bytes](https://docs.python.org/library/functions.html#func-bytes) | Same conversion as with [bytes](https://docs.python.org/library/functions.html#func-bytes), but the result is a [bytearray](https://docs.python.org/library/functions.html#func-bytearray). | |
| [datetime](https://docs.python.org/library/datetime.html#datetime.datetime) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | String timestamps are expected to be in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) like format `YYYY-MM-DD hh:mm:ss.mmmmmm`, where any non-digit character can be used as a separator or separators can be omitted altogether. Additionally, only the date part is mandatory, all possibly missing time components are considered to be zeros. Special values `NOW` and `TODAY` (case-insensitive) can be used to get the current local `datetime`. This is new in Robot Framework 7.3. Integers and floats are considered to represent seconds since the [Unix epoch](http://en.wikipedia.org/wiki/Unix_time). | `2022-02-09T16:39:43.632269` `20220209 16:39` `2022-02-09` `now` (current local date and time) `TODAY` (same as above) `${1644417583.632269}` (Epoch time) |
| [date](https://docs.python.org/library/datetime.html#datetime.date) | | | [str](https://docs.python.org/library/functions.html#func-str) | Same timestamp conversion as with [datetime](https://docs.python.org/library/datetime.html#datetime.datetime), but all time components are expected to be omitted or to be zeros. Special values `NOW` and `TODAY` (case-insensitive) can be used to get the current local `date`. This is new in Robot Framework 7.3. | `2018-09-12` `20180912` `today` (current local date) `NOW` (same as above) |
| [timedelta](https://docs.python.org/library/datetime.html#datetime.timedelta) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | Strings are expected to represent a time interval in one of the time formats Robot Framework supports: [time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number), [time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string) or [time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string). Integers and floats are considered to be seconds. | `42` (42 seconds) `1 minute 2 seconds` `01:02` (same as above) |
| [Path](https://docs.python.org/library/pathlib.html) | [PathLike](https://docs.python.org/library/os.html#os.PathLike) | | [str](https://docs.python.org/library/functions.html#func-str) | Strings are converted to [pathlib.Path](https://docs.python.org/library/pathlib.html) objects. On Windows `/` is converted to \\ automatically. New in Robot Framework 6.0. | `/tmp/absolute/path` `relative/path/to/file.ext` `name.txt` |
| [Enum](https://docs.python.org/library/enum.html#enum.Enum) | | | [str](https://docs.python.org/library/functions.html#func-str) | The specified type must be an enumeration (a subclass of [Enum](https://docs.python.org/library/enum.html#enum.Enum) or [Flag](https://docs.python.org/library/enum.html#enum.Flag)) and given arguments must match its member names. Matching member names is case, space, underscore and hyphen insensitive, but exact matches have precedence over normalized matches. Ignoring hyphens is new in Robot Framework 7.0. Enumeration documentation and members are shown in documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. | `NORTH` (Direction.NORTH) `north west` (Direction.NORTH\_WEST) |
| [IntEnum](https://docs.python.org/library/enum.html#enum.IntEnum) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int) | The specified type must be an integer based enumeration (a subclass of [IntEnum](https://docs.python.org/library/enum.html#enum.IntEnum) or [IntFlag](https://docs.python.org/library/enum.html#enum.IntFlag)) and given arguments must match its member names or values. Matching member names works the same way as with `Enum`. Values can be given as integers and as strings that can be converted to integers. Enumeration documentation and members are shown in documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. New in Robot Framework 4.1. | `OFF` (PowerState.OFF) `1` (PowerState.ON) |
| [Literal](https://docs.python.org/library/typing.html#typing.Literal) | | | Depends on usage | Only specified values are accepted. Values can be strings, integers, bytes, Booleans, enums and `None`, and used arguments are converted using the value type specific conversion logic. Strings are case, space, underscore and hyphen insensitive, but exact matches have precedence over normalized matches. `Literal` provides similar functionality as `Enum`, but does not support custom documentation. New in Robot Framework 7.0. | `OFF` `on` |
| [None](https://docs.python.org/library/constants.html#None) | | | [str](https://docs.python.org/library/functions.html#func-str) | String `NONE` (case-insensitive) and the empty string are converted to the Python `None` object. Other values cause an error. Converting the empty string is new in Robot Framework 7.4. | `None` |
| [Any](https://docs.python.org/library/typing.html#typing.Any) | | | Anything | Any value is accepted. No conversion is done. New in Robot Framework 6.1. | |
| [object](https://docs.python.org/3/library/functions.html#object) | | | Anything | Any value is accepted. No conversion is done. New in Robot Framework 7.4. | |
| [list](https://docs.python.org/library/stdtypes.html#list) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Converts strings and sequences to `list`. Strings must be Python list or tuple literals. They are converted using the [ast.literal\_eval](https://docs.python.org/library/ast.html#ast.literal_eval) function and possible tuples converted further to lists. They can contain any values `ast.literal_eval` supports, including lists and other collections. If the argument is a list, it is used without conversion. Tuples and other sequences are converted to lists. Support for tuple literals is new in Robot Framework 7.4. | `['one', 'two']` `[('one', 1), ('two', 2)]` |
| [tuple](https://docs.python.org/library/stdtypes.html#tuple) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Same as `list`, but the result is [tuple](https://docs.python.org/library/stdtypes.html#tuple). Prior to Robot Framework 7.4, only tuple literals were supported. | `('one', 'two')` |
| [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Same as `list`, but any sequence is accepted without conversion. If the used type is [MutableSequence](https://docs.python.org/library/collections.abc.html#collections.abc.MutableSequence), immutable values are converted to lists. | `[1, 2, 3]` (result is `list`) `(1, 2, 3)` (result is `tuple`) |
| [set](https://docs.python.org/library/stdtypes.html#set) | [Set](https://docs.python.org/library/collections.abc.html#collections.abc.Set) | | [str](https://docs.python.org/library/functions.html#func-str), [Collection](https://docs.python.org/library/collections.abc.html#collections.abc.Collection) | Same as `list`, but also collection objects and set literals are supported and the result is [set](https://docs.python.org/library/stdtypes.html#set). Prior to Robot Framework 7.4, only set literals were supported. | `{1, 2, 3, 42}` `set()` (an empty set) |
| [frozenset](https://docs.python.org/library/stdtypes.html#frozenset) | | | [str](https://docs.python.org/library/functions.html#func-str), [Collection](https://docs.python.org/library/collections.abc.html#collections.abc.Collection) | Same as `set`, but the result is a [frozenset](https://docs.python.org/library/stdtypes.html#frozenset). | `{1, 2, 3, 42}` `frozenset()` (an empty set) |
| [dict](https://docs.python.org/library/stdtypes.html#dict) | | dictionary | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Converts strings and mappings to `dict`. Strings must be Python dictionary literals. They are converted to `dict` using the [ast.literal\_eval](https://docs.python.org/library/ast.html#ast.literal_eval) function. They can contain any values `ast.literal_eval` supports, including dictionaries and other collections. | `{'a': 1, 'b': 2}` `{'key': 1, 'nested': {'key': 2}}` |
| [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | | map | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Same as `dict`, but the original mapping type is preserved. If type is [MutableMapping](https://docs.python.org/library/collections.abc.html#collections.abc.MutableMapping), immutable values are converted to `dict`. | |
| [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict) | | | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Same as `dict`, but dictionary items are also converted to the specified types and items not included in the type spec are not allowed. New in Robot Framework 6.0. Normal `dict` conversion was used earlier. | `{'width': 1600, 'enabled': True}` |
| [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) | | | [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) | Using the [Secret type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-type) as a type hint ensures that only [secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables) are accepted as arguments. New in Robot Framework 7.4. | |
Note
Starting from Robot Framework 5.0, types that have a converted are automatically shown in [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) outputs.
Note
Prior to Robot Framework 4.0, most types supported converting string `NONE` (case-insensitively) to Python `None`. That support has been removed and `None` conversion is only done if an argument has `None` as an explicit type or as a default value.
##### Specifying multiple possible types
It is possible to specify that an argument has multiple possible types. In this situation argument conversion is attempted based on each type, from left to right, and the value of the first succeeding conversion is used. If none of these conversions succeeds, the whole conversion fails.
###### Union syntax
When using function annotations, the natural syntax to specify that an argument has multiple possible types is using a [Union](https://docs.python.org/3/library/typing.html#typing.Union):
```
from typing import Union
def example(length: Union[int, float], padding: Union[int, str, None] = None):
...
```
When using Python 3.10 or newer, it is possible to use the [native union syntax](https://peps.python.org/pep-0604/) like `int | float` instead:
```
def example(length: int | float, padding: int | str | None = None):
...
```
Robot Framework 7.0 enhanced the support for the union syntax so that also "stringly typed" unions like `"int | float"` work. This syntax works also with older Python versions:
```
def example(length: "int | float", padding: "int | str | None" = None):
...
```
###### Using tuples
An alternative is specifying types as a tuple. It is not recommended with annotations, because that syntax is not supported by other tools, but it works well with the `@keyword` decorator:
```
from robot.api.deco import keyword
@keyword(types={'length': (int, float), 'padding': (int, str, None)})
def example(length, padding=None):
...
```
With the above examples the `length` argument would first be converted to an integer and if that fails then to a float. The `padding` would be first converted to an integer, then to a string, and finally to `None`.
###### When argument matches one of the types
If the given argument has one of the accepted types, then no conversion is done and the argument is used as-is. For example, if the `length` argument typed like `length: int | float` is used with a floating point number `1.5`, it is not converted to an integer. Notice that using non-string values like floats as an argument requires using variables as these examples giving different values to the `length` argument demonstrate:
```
*** Test Cases ***
Conversion
Example 10 # Argument is a string. Converted to an integer.
Example 1.5 # Argument is a string. Converted to a float.
Example ${10} # Argument is an integer. Accepted as-is.
Example ${1.5} # Argument is a float. Accepted as-is.
```
If one of the accepted types is string like in `padding: int | str | None`, then no conversion is done if the given argument is a string. As the following examples giving different values to the `padding` argument demonstrate, also in these cases passing other types is possible using variables:
```
*** Test Cases ***
Conversion
Example 1 big # Argument is a string. Accepted as-is.
Example 1 10 # Argument is a string. Accepted as-is.
Example 1 ${10} # Argument is an integer. Accepted as-is.
Example 1 ${None} # Argument is `None`. Accepted as-is.
Example 1 ${1.5} # Argument is a float. Converted to an integer.
```
If the given argument does not have any of the accepted types, conversion is attempted in the order types are specified.
Note
The order of types changes the conversion result in cases where the used value does not match any of the types, but conversion to multiple types would succeed.
For example, if typing is `float | int` and the used value is string `42`, the result will be float `42.0` instead of integer `42`. The reason is that a string does not match either of the types and `float` conversion is attempted first. If the order is changed to `int | float`, the result will be an integer.
String `3.14` would be converted to a float regardless the order, because `int` conversion does not succeed. The order does not affect usages where the value is already an integer or a float either, because there is no need for conversion in such cases.
###### Handling `Any` and `object`
If `Any` or `object` is used as a type hint on its own like `arg: Any` or `arg: object`, any value is accepted without conversion. How they work when used in an union differs, though.
If `Any` is used in a union like `arg: int | Any`, any value is accepted without conversion. This allows using `Any` as an escape hatch that disables argument conversion altogether.
On the other hand, if `object` is used in an union like `arg: int | object`, conversion is attempted to types before `object`. This allows attempting conversion to certain type or types, but getting the original value if conversions fail.
Note
Although this subtle difference in behavior may be useful, it is also somewhat confusing and the plan is to change it in Robot Framework 8.0 so that `Any` behaves like `object`. See the issue [\#5571](https://github.com/robotframework/robotframework/issues/5571) for more information and comment the issue if you do not think the planned change is a good idea.
###### Handling unrecognized types
If types that are not recognized by Robot Framework are used in an union, they are handled like this:
- If a used value matches any of the types, including unrecognized types, the value is used as-is without conversion.
- Otherwise conversion is attempted to recognized types from left to right.
- If any conversion succeeds, the converted value is returned.
- If no conversion succeeds, the original value is returned.
For example, with the following keyword string `"7"` would be converted to an integer, but string `"something"` would be used as-is:
```
def example(argument: int | Unrecognized):
...
```
Starting from Robot Framework 6.1, the above logic works also if an unrecognized type is listed before a recognized type like `Unrecognized | int`. Also in this case `int` conversion is attempted, and the argument id passed as-is if it fails. With earlier Robot Framework versions, `int` conversion would not be attempted at all.
##### Parameterized types
With generics also the parameterized syntax like `list[int]` or `dict[str, int]` works. When this syntax is used, the given value is first converted to the base type and then individual items are converted to the nested types. Conversion with different generic types works according to these rules:
- With lists there can be only one type like `list[float]`. All list items are converted to that type.
- With tuples there can be any number of types like `tuple[int, int]` and `tuple[str, int, bool]`. Tuples used as arguments are expected to have exactly that amount of items and they are converted to matching types.
- To create a homogeneous tuple, it is possible to use exactly one type and ellipsis like `tuple[int, ...]`. In this case tuple can have any number of items, including zero, and they are all converted to the specified type.
- With dictionaries there must be exactly two types like `dict[str, int]`. Dictionary keys are converted using the first type and values using the second.
- With sets there can be exactly one type like `set[float]`. Conversion logic is the same as with lists.
Using the native `list[int]` syntax requires [Python 3.9](https://peps.python.org/pep-0585/) or newer. If there is a need to support also earlier Python versions, it is possible to either use matching types from the [typing](https://docs.python.org/library/typing.html) module like `List[int]` or use the "stringly typed" syntax like `'list[int]'`.
Note
Support for converting nested types with generics is new in Robot Framework 6.0. Same syntax works also with earlier versions, but arguments are only converted to the base type and nested type information is ignored.
Note
Support for "stringly typed" parameterized generics is new in Robot Framework 7.0.
##### Secret type
Robot Framework has a custom [robot.api.types.Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) type that encapsulates values so that they are not shown in log files. If the `Secret` type is used as an argument type, only `Secret` objects are accepted and trying to use, for example, literal strings fails. The encapsulated value is available in the `value` attribute so keywords can access it easily:
```
from example import SUT
from robot.api.types import Secret
def login_to_sut(user: str, token: Secret):
SUT.login(user, token.value)
```
The [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables) section explains how to create `Secret` objects in the data, on the command line, and elsewhere. In the data that involves using [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) and, for example, [environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables):
```
*** Variables ***
${USER} robot
${TOKEN: Secret} %{ROBOT_TOKEN}
*** Test Cases ***
Example
Login to SUT ${USER} ${TOKEN}
```
Keywords can also accept `Secret` objects in addition to strings by using the union syntax like `str | Secret`:
```
from example import SUT
from robot.api import logger
from robot.api.types import Secret
def input_password(password: str | Secret):
logger.debug(f"Typing password: {password}")
if isinstance(password, Secret):
password = password.value
SUT.input_password(password)
```
In this kind of cases it is important to not log or otherwise disclose actual secret values. The string representation of `Secret` objects is always `<secret>` and thus logging `f"Typing password: {password}"` in the above example is safe, but logging it at the end of the example would not be. The `repr()` of `Secret` objects is `Secret(value=<secret>)` so the real value is not shown in that string representation either.
Using the `Secret` type in complex type hints works similarly as with other types. The following example is similar to the example above, but uses a [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict) with a `Secret` item:
```
from typing import TypedDict
from robot.api.types import Secret
class Credential(TypedDict):
user: str
token: Secret
def login_to_sut(credentials: Credential):
SUT.login(credentials["user"], credentials["token"].value)
```
```
*** Variables ***
${TOKEN: Secret} %{ROBOT_TOKEN}
&{CREDENTIALS} user=robot token=${TOKEN}
*** Test Cases ***
Example
Login to SUT ${CREDENTIALS}
```
Warning
Secret objects do not hide or encrypt their values. The real values are thus available for all code that can access these objects directly or indirectly via Robot Framework APIs.
Warning
Actual secret values that keywords pass forward may be logged or otherwise disclosed by external modules or tools using them.
Note
The [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) type is new in Robot Framework 7.4.
##### Custom argument converters
In addition to doing argument conversion automatically as explained in the previous sections, Robot Framework supports custom argument conversion. This functionality has two main use cases:
- Overriding the standard argument converters provided by the framework.
- Adding argument conversion for custom types and for other types not supported out-of-the-box.
Argument converters are functions or other callables that get arguments used in data and convert them to desired format before arguments are passed to keywords. Converters are registered for libraries by setting `ROBOT_LIBRARY_CONVERTERS` attribute (case-sensitive) to a dictionary mapping desired types to converts. When implementing a library as a module, this attribute must be set on the module level, and with class based libraries it must be a class attribute. With libraries implemented as classes, it is also possible to use the `converters` argument with the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator). Both of these approaches are illustrated by examples in the following sections.
Note
Custom argument converters are new in Robot Framework 5.0.
###### Overriding default converters
Let's assume we wanted to create a keyword that accepts [date](https://docs.python.org/library/datetime.html#datetime.date) objects for users in Finland where the commonly used date format is `dd.mm.yyyy`. The usage could look something like this:
```
*** Test Cases ***
Example
Keyword 25.1.2022
```
[Automatic argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) supports dates, but it expects them to be in `yyyy-mm-dd` format so it will not work. A solution is creating a custom converter and registering it to handle [date](https://docs.python.org/library/datetime.html#datetime.date) conversion:
```
from datetime import date
# Converter function.
def parse_fi_date(value):
day, month, year = value.split('.')
return date(int(year), int(month), int(day))
# Register converter function for the specified type.
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
# Keyword using custom converter. Converter is resolved based on argument type.
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Conversion errors
If we try using the above keyword with invalid argument like `invalid`, it fails with this error:
```
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: not enough values to unpack (expected 3, got 1)
```
This error is not too informative and does not tell anything about the expected format. Robot Framework cannot provide more information automatically, but the converter itself can be enhanced to validate the input. If the input is invalid, the converter should raise a `ValueError` with an appropriate message. In this particular case there would be several ways to validate the input, but using [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) makes it possible to validate both that the input has dots (`.`) in correct places and that date parts contain correct amount of digits:
```
from datetime import date
import re
def parse_fi_date(value):
# Validate input using regular expression and raise ValueError if not valid.
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return date(int(year), int(month), int(day))
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
With the above converter code, using the keyword with argument `invalid` fails with a lot more helpful error message:
```
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: Expected date in format 'dd.mm.yyyy', got 'invalid'.
```
###### Restricting value types
By default Robot Framework tries to use converters with all given arguments regardless their type. This means that if the earlier example keyword would be used with a variable containing something else than a string, conversion code would fail in the `re.match` call. For example, trying to use it with argument `${42}` would fail like this:
```
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date: TypeError: expected string or bytes-like object
```
This error situation could naturally handled in the converter code by checking the value type, but if the converter only accepts certain types, it is typically easier to just restrict the value to that type. Doing it requires only adding appropriate type hint to the converter:
```
def parse_fi_date(value: str):
...
```
Notice that this type hint *is not* used for converting the value before calling the converter, it is used for strictly restricting which types can be used. With the above addition calling the keyword with `${42}` would fail like this:
```
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date.
```
If the converter can accept multiple types, it is possible to specify types as a [Union](https://docs.python.org/3/library/typing.html#typing.Union). For example, if we wanted to enhance our keyword to accept also integers so that they would be considered seconds since the [Unix epoch](http://en.wikipedia.org/wiki/Unix_time), we could change the converter like this:
```
from datetime import date
import re
from typing import Union
# Accept both strings and integers.
def parse_fi_date(value: Union[str, int]):
# Integers are converted separately.
if isinstance(value, int):
return date.fromtimestamp(value)
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return date(int(year), int(month), int(day))
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Converting custom types
A problem with the earlier example is that [date](https://docs.python.org/library/datetime.html#datetime.date) objects could only be given in `dd.mm.yyyy` format. It would not work if there was a need to support dates in different formats like in this example:
```
*** Test Cases ***
Example
Finnish 25.1.2022
US 1/25/2022
ISO 8601 2022-01-22
```
A solution to this problem is creating custom types instead of overriding the default [date](https://docs.python.org/library/datetime.html#datetime.date) conversion:
```
from datetime import date
import re
from typing import Union
from robot.api.deco import keyword, library
# Custom type. Extends an existing type but that is not required.
class FiDate(date):
# Converter function implemented as a classmethod. It could be a normal
# function as well, but this way all code is in the same class.
@classmethod
def from_string(cls, value: str):
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return cls(int(year), int(month), int(day))
# Another custom type.
class UsDate(date):
@classmethod
def from_string(cls, value: str):
match = re.match(r'(\d{1,2})/(\d{1,2})/(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'mm/dd/yyyy', got '{value}'.")
month, day, year = match.groups()
return cls(int(year), int(month), int(day))
# Register converters using '@library' decorator.
@library(converters={FiDate: FiDate.from_string, UsDate: UsDate.from_string})
class Library:
# Uses custom converter supporting 'dd.mm.yyyy' format.
@keyword
def finnish(self, arg: FiDate):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Uses custom converter supporting 'mm/dd/yyyy' format.
@keyword
def us(self, arg: UsDate):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Uses IS0-8601 compatible default conversion.
@keyword
def iso_8601(self, arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Accepts date in different formats.
@keyword
def any(self, arg: Union[FiDate, UsDate, date]):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Strict type validation
Converters are not used at all if the argument is of the specified type to begin with. It is thus easy to enable strict type validation with a custom converter that does not accept any value. For example, the Example keyword accepts only `StrictType` instances:
```
class StrictType:
pass
def strict_converter(arg):
raise TypeError(f'Only StrictType instances accepted, got {type(arg).__name__}.')
ROBOT_LIBRARY_CONVERTERS = {StrictType: strict_converter}
def example(argument: StrictType):
assert isinstance(argument, StrictType)
```
As a convenience, Robot Framework allows setting converter to `None` to get the same effect. For example, this code behaves exactly the same way as the code above:
```
class StrictType:
pass
ROBOT_LIBRARY_CONVERTERS = {StrictType: None}
def example(argument: StrictType):
assert isinstance(argument, StrictType)
```
Note
Using `None` as a strict converter is new in Robot Framework 6.0. An explicit converter function needs to be used with earlier versions.
###### Accessing the test library from converter
Starting from Robot Framework 6.1, it is possible to access the library instance from a converter function. This allows defining dynamic type conversions that depend on the library state. For example, if the library can be configured to test particular locale, you might use the library state to determine how a date should be parsed like this:
```
from datetime import date
import re
def parse_date(value, library):
# Validate input using regular expression and raise ValueError if not valid.
# Use locale based from library state to determine parsing format.
if library.locale == 'en_US':
match = re.match(r'(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<year>\d{4})$', value)
format = 'mm/dd/yyyy'
else:
match = re.match(r'(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{4})$', value)
format = 'dd.mm.yyyy'
if not match:
raise ValueError(f"Expected date in format '{format}', got '{value}'.")
return date(int(match.group('year')), int(match.group('month')), int(match.group('day')))
ROBOT_LIBRARY_CONVERTERS = {date: parse_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
The `library` argument to converter function is optional, i.e. if the converter function only accepts one argument, the `library` argument is omitted. Similar result can be achieved by making the converter function accept only variadic arguments, e.g. `def parse_date(*varargs)`.
###### Converter documentation
Information about converters is added to outputs produced by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. This information includes the name of the type, accepted values (if specified using type hints) and documentation. Type information is automatically linked to all keywords using these types.
Used documentation is got from the converter function by default. If it does not have any documentation, documentation is got from the type. Both of these approaches to add documentation to converters in the previous example thus produce the same result:
```
class FiDate(date):
@classmethod
def from_string(cls, value: str):
"""Date in ``dd.mm.yyyy`` format."""
...
class UsDate(date):
"""Date in ``mm/dd/yyyy`` format."""
@classmethod
def from_string(cls, value: str):
...
```
Adding documentation is in general recommended to provide users more information about conversion. It is especially important to document converter functions registered for existing types, because their own documentation is likely not very useful in this context.
#### `@keyword` decorator
Although Robot Framework gets lot of information about keywords automatically, such as their names and arguments, there are sometimes needs to configure this information further. This is typically easiest done by using the `robot.api.deco.keyword` decorator. It has several useful usages that are explained thoroughly elsewhere and only listened here as a reference:
- Exposing methods and functions as keywords when the [automatic keyword discovery](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-public-methods-becoming-keywords) has been disabled by using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) or otherwise.
- Setting a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) to a keyword. This is especially useful when using the [embedded argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names).
- Setting [keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags).
- Setting [type information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) to enable automatic argument type conversion. Supports also disabling the argument conversion altogether.
- [Marking methods to expose as keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#marking-methods-to-expose-as-keywords) when using the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
#### `@not_keyword` decorator
The `robot.api.deco.not_keyword` decorator can be used for [disabling functions or methods becoming keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-not-keyword-decorator).
#### Using custom decorators
When implementing keywords, it is sometimes useful to modify them with [Python decorators](https://realpython.com/primer-on-python-decorators/). However, decorators often modify function signatures and can thus confuse Robot Framework's introspection when determining which arguments keywords accept. This is especially problematic when creating library documentation with [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) and when using external tools like [RIDE](https://github.com/robotframework/RIDE). The easiest way to avoid this problem is decorating the decorator itself using [functools.wraps](https://docs.python.org/library/functools.html#functools.wraps). Other solutions include using external modules like [decorator](https://pypi.org/project/decorator/) and [wrapt](https://wrapt.readthedocs.io/) that allow creating fully signature-preserving decorators.
Note
Support for "unwrapping" decorators decorated with `functools.wraps` is a new feature in Robot Framework 3.2.
#### Embedding arguments into keyword names
Library keywords can also accept *embedded arguments* the same way as [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). This section mainly covers the Python syntax to use to create such keywords, the embedded arguments syntax itself is covered in detail as part of [user keyword documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
Library keywords with embedded arguments need to have a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) that is typically set using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator). Values matching embedded arguments are passed to the function or method implementing the keyword as positional arguments. If the function or method accepts more arguments, they can be passed to the keyword as normal positional or named arguments. Argument names do not need to match the embedded argument names, but that is generally a good convention.
Keywords accepting embedded arguments:
```
from robot.api.deco import keyword
@keyword('Select ${animal} from list')
def select_animal_from_list(animal):
...
@keyword('Number of ${animals} should be')
def number_of_animals_should_be(animals, count):
...
```
Tests using the above keywords:
```
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
Embedded and normal arguments
Number of cats should be 2
Number of dogs should be count=3
```
If type information is specified, automatic [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion) works also with embedded arguments:
```
@keyword('Add ${quantity} copies of ${item} to cart')
def add_copies_to_cart(quantity: int, item: str):
...
```
Note
Embedding type information to keyword names like `Add ${quantity: int} copies of ${item: str} to cart` similarly as with [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-embedded-arguments) *is not supported* with library keywords.
Note
Support for mixing embedded arguments and normal arguments is new in Robot Framework 7.0.
#### Asynchronous keywords
Starting from Robot Framework 6.1, it is possible to run native asynchronous functions (created by `async def`) just like normal functions:
```
import asyncio
from robot.api.deco import keyword
@keyword
async def this_keyword_waits():
await asyncio.sleep(5)
```
You can get the reference of the loop using `asyncio.get_running_loop()` or `asyncio.get_event_loop()`. Be careful when modifying how the loop runs, it is a global resource. For example, never call `loop.close()` because it will make it impossible to run any further coroutines. If you have any function or resource that requires the event loop, even though `await` is not used explicitly, you have to define your function as async to have the event loop available.
More examples of functionality:
```
import asyncio
from robot.api.deco import keyword
async def task_async():
await asyncio.sleep(5)
@keyword
async def examples():
tasks = [task_async() for _ in range(10)]
results = await asyncio.gather(*tasks)
background_task = asyncio.create_task(task_async())
await background_task
# If running with Python 3.10 or higher
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(task_async())
task2 = tg.create_task(task_async())
```
Note
Robot Framework waits for the function to complete. If you want to have a task that runs for a long time, use, for example, `asyncio.create_task()`. It is your responsibility to manage the task and save a reference to avoid it being garbage collected. If the event loop closes and a task is still pending, a message will be printed to the console.
Note
If execution of keyword cannot continue for some reason, for example a signal stop, Robot Framework will cancel the async task and any of its children. Other async tasks will continue running normally.
### [4\.1.4 Communicating with Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-131)
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`.
Normal execution failures and errors can be reported using the standard exceptions such as `AssertionError`, `ValueError` and `RuntimeError`. There are, however, some special cases explained in the subsequent sections where special exceptions are needed.
##### Error messages
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 .
It is possible to avoid adding the exception type as a prefix to failure message also with non generic exceptions. This is done by adding a special `ROBOT_SUPPRESS_NAME` attribute with value `True` to your exception.
Python:
```
class MyError(RuntimeError):
ROBOT_SUPPRESS_NAME = True
```
In all cases, it is important for the users that the exception message is as informative as possible.
##### HTML in error messages
It is also possible to have HTML formatted error messages by starting the message with text `*HTML*`:
```
raise AssertionError("*HTML* <a href='robotframework.org'>Robot Framework</a> rulez!!")
```
This method can be used both when raising an exception in a library, like in the example above, and [when users provide an error message in the test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures).
##### Cutting long messages automatically
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.
##### Tracebacks
The traceback of the exception is also logged using `DEBUG` [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). 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`.
#### Exceptions provided by Robot Framework
Robot Framework provides some exceptions that libraries can use for reporting failures and other events. These exceptions are exposed via the [robot.api](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html) package and contain the following:
`Failure`
Report failed validation. There is no practical difference in using this exception compared to using the standard `AssertionError`. The main benefit of using this exception is that its name is consistent with other provided exceptions.
`Error`
Report error in execution. Failures related to the system not behaving as expected should typically be reported using the `Failure` exception or the standard `AssertionError`. This exception can be used, for example, if the keyword is used incorrectly. There is no practical difference, other than consistent naming with other provided exceptions, compared to using this exception and the standard `RuntimeError`.
`ContinuableFailure`
Report failed validation but allow continuing execution. See the [Continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuable-failures) section below for more information.
`SkipExecution`
Mark the executed test or task [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped). See the [Skipping tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipping-tests) section below for more information.
`FatalError`
Report error that stops the whole execution. See the [Stopping test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution) section below for more information.
Note
All these exceptions are new in Robot Framework 4.0. Other features than skipping tests, which is also new in Robot Framework 4.0, are available by other means in earlier versions.
#### Continuable failures
It is possible to [continue test execution even when there are failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). The easiest way to do that is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.ContinuableFailure` exception:
```
from robot.api import ContinuableFailure
def example_keyword():
if something_is_wrong():
raise ContinuableFailure('Something is wrong but execution can continue.')
...
```
An alternative is creating a custom exception that has a special `ROBOT_CONTINUE_ON_FAILURE` attribute set to a `True` value. This is demonstrated by the example below.
```
class MyContinuableError(RuntimeError):
ROBOT_CONTINUE_ON_FAILURE = True
```
#### Skipping tests
It is possible to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) tests with a library keyword. The easiest way to do that is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.SkipExecution` exception:
```
from robot.api import SkipExecution
def example_keyword():
if test_should_be_skipped():
raise SkipExecution('Cannot proceed, skipping test.')
...
```
An alternative is creating a custom exception that has a special `ROBOT_SKIP_EXECUTION` attribute set to a `True` value. This is demonstrated by the example below.
```
class MySkippingError(RuntimeError):
ROBOT_SKIP_EXECUTION = True
```
#### Stopping test execution
It is possible to fail a test case so that [the whole test execution is stopped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). The easiest way to accomplish this is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.FatalError` exception:
```
from robot.api import FatalError
def example_keyword():
if system_is_not_running():
raise FatalError('System is not running!')
...
```
In addition to using the `robot.api.FatalError` exception, it is possible create a custom exception that has a special `ROBOT_EXIT_ON_FAILURE` attribute set to a `True` value. This is illustrated by the example below.
```
class MyFatalError(RuntimeError):
ROBOT_EXIT_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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) simply by writing to the standard output stream (stdout) or to the standard error stream (stderr), and they can even use different [log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). Another, and often better, logging possibility is using the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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`. In this formant `*LEVEL*` must be in the beginning of a line and `LEVEL` must be one of the available concrete log levels `TRACE`, `DEBUG`, `INFO`, `WARN` or `ERROR`, or a pseudo log level `HTML` or `CONSOLE`. The pseudo levels can be used for [logging HTML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-html) and [logging to console](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-to-console), respectively.
##### Errors and warnings
Messages with `ERROR` or `WARN` level are automatically written to the console and a separate [Test Execution Errors section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) in the log files. This makes these messages more visible than others 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, for example, one badly placed `</table>` tag can ruin the log file quite badly.
When using the [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api), various logging methods have optional `html` attribute that can be set to `True` to enable logging in HTML format.
##### 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.
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](http://en.wikipedia.org/wiki/Unix_time) and it must be placed after the [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-log-levels) 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. It is, however, even easier to get accurate timestamps using the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis). A big benefit of adding timestamps explicitly is that this approach works also with the [remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface).
```
import time
def example_keyword():
timestamp = int(time.time() * 1000)
print(f'*INFO:{timestamp}* Message with timestamp')
```
##### Logging to console
Libraries have several options for writing messages to the console. As already discussed, warnings and 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.
Starting from Robot Framework 6.1, libraries can use a pseudo log level `CONSOLE` for logging messages *both* to the log file and to the console:
```
def my_keyword(arg):
print('*CONSOLE* Message both to log and to console.')
```
These messages will be logged to the log file using the `INFO` level similarly as with the `HTML` pseudo log level. When using this approach, messages are logged to the console only after the keyword execution ends.
Another option is writing messages to `sys.__stdout__` or `sys.__stderr__`. When using this approach, messages are written to the console immediately and are not written to the log file at all:
```
import sys
def my_keyword(arg):
print('Message only to console.', file=sys.__stdout__)
```
The final option is using the [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api). Also in with this approach messages are written to the console immediately:
```
from robot.api import logger
def log_to_console(arg):
logger.console('Message only to console.')
def log_to_console_and_log_file(arg):
logger.info('Message both to log and to console.', also_console=True)
```
##### 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` or `ERROR` level can be used to make messages more visible and `HTML` is useful if any kind of formatting is needed. Level `CONSOLE` can be used when the message needs to shown both in console and in the log file.
The following examples clarify how logging with different levels works.
```
print('Hello from a library.')
print('*WARN* Warning from a library.')
print('*ERROR* Something unexpected happen that may indicate a problem in the test.')
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('*CONSOLE* This logs into console and log file.')
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 | ERROR | Something unexpected happen that may indicate a problem in the test. |
| 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 logs into console and log file. |
| 16:18:42.123 | INFO | This is **bold**. |
| 16:18:42.123 | INFO | [Robot Framework](http://robotframework.org/) |
#### Programmatic logging APIs
Programmatic APIs provide somewhat cleaner way to log information than using the standard output and error streams.
##### Public logging API
Robot Framework has a 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamps).
The public logging API [is thoroughly documented](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#module-robot.api.logger) as part of the API documentation at <https://robot-framework.readthedocs.org>. Below is a simple usage example:
```
from robot.api import logger
def my_keyword(arg):
logger.debug(f"Got argument '{arg}'.")
do_something()
logger.info('<i>This</i> is a boring example', html=True)
logger.console('Hello, console!')
```
An obvious limitation is that test libraries using this logging API have a dependency to Robot Framework. If Robot Framework is not running, the messages are redirected automatically to Python's standard [logging](http://docs.python.org/library/logging.html) module.
##### Using Python's standard `logging` module
In addition to the new [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api), Robot Framework offers a built-in support to Python's standard [logging](http://docs.python.org/library/logging.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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(f"Got argument '{arg}'.")
do_something()
logging.info('This is a boring example')
```
The `logging` module has slightly different log levels than Robot Framework. Its levels `DEBUG`, `INFO`, `WARNING` and `ERROR` are mapped directly to the matching Robot Framework log levels, and `CRITICAL` is mapped to `ERROR`. Custom log levels are mapped to the closest standard level smaller than the custom level. For example, a level between `INFO` and `WARNING` is mapped to Robot Framework's `INFO` level.
#### Logging during library initialization
Libraries can also log during the test library import and initialization. These messages do not appear in the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) like the normal log messages, but are instead written to the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log). This allows logging any kind of useful debug information about the library initialization. Messages logged using the `WARN` or `ERROR` levels are also visible in the [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) section in the log file.
Logging during the import and initialization is possible both using the [standard output and error streams](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) and the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis). Both of these are demonstrated below.
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__`, the messages may be logged multiple times depending on the [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope).
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) in the test data and then used as inputs for other keywords, even from different test libraries.
Values are returned using the `return` statement in methods. Normally, one value is assigned into one [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), as illustrated in the example below. This example also illustrates that it is possible to return any objects and to use [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) to access object attributes.
```
from mymodule import MyObject
def return_string():
return "Hello, world!"
def return_object(name):
return MyObject(name)
```
```
*** Test Cases ***
Returning one value
${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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables) at once, into [a list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables), or into scalar variables and a list variable. All these usages require that returned values are lists or list-like objects.
```
def return_two_values():
return 'first value', 'second value'
def return_multiple_values():
return ['a', 'list', 'of', 'strings']
```
```
*** Test Cases ***
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 ${s1} ${s2} a list
Should Be Equal @{li}[0] @{li}[1] of strings
```
#### Detecting is Robot Framework running
Starting from Robot Framework 6.1, it is easy to detect is Robot Framework running at all and is the dry-run mode active by using the `robot_running` and `dry_run_active` properties of the BuiltIn library. A relatively common use case is that library initializers may want to avoid doing some work if the library is not used during execution but is initialized, for example, by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc):
```
from robot.libraries.BuiltIn import BuiltIn
class MyLibrary:
def __init__(self):
builtin = BuiltIn()
if builtin.robot_running and not builtin.dry_run_active:
# Do some initialization that only makes sense during real execution.
```
For more information about using the BuiltIn library as a programmatic API, including another example using `robot_running`, see the [Using BuiltIn library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-builtin-library) section.
#### 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 the worst 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.
Messages logged by non-main threads using the normal logging methods from [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis) are silently ignored.
There is also a `BackgroundLogger` in separate [robotbackgroundlogger](https://github.com/robotframework/robotbackgroundlogger) project, with a similar API as the standard `robot.api.logger`. Normal logging methods will ignore messages from other than main thread, but the `BackgroundLogger` will save the background messages so that they can be later logged to Robot's log.
### [4\.1.5 Distributing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-132)
#### 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](http://www.python.org/dev/peps/pep-0257) as in the example 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
```
Python has 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). This tool can create a library documentation from libraries using the static library API, such as the ones above, but it also handles libraries using the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) and [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
The first logical line of a keyword documentation, until the first empty line, is used for a special purpose and should contain a short overall description of the keyword. It is used as a *short documentation* by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) (for example, as a tool tip) and also shown in the [test logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).
By default documentation is considered to follow Robot Framework's [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) rules. This simple format allows often used styles like `*bold*` and `_italic_`, tables, lists, links, etc. It is possible to use also HTML, plain text and [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) formats. See the [Documentation format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) section for information how to set the format in the library source code and [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) chapter for more information about the formats in general.
Note
Prior to Robot Framework 3.1, the short documentation contained only the first physical line of the keyword documentation.
#### 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.
Python has 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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 [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-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. For information about packaging and distributing Python code see <https://packaging.python.org/>. When such a package is installed using [pip](https://pip.pypa.io/) or other tools, it is automatically in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
#### 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 can be deprecated by starting their documentation with text `*DEPRECATED`, case-sensitive, and having a closing `*` also on the first line of the documentation. For example, `*DEPRECATED*`, `*DEPRECATED.*`, and `*DEPRECATED in version 1.5.*` are all valid markers.
When a deprecated keyword is executed, a deprecation warning is logged and the warning is shown also in [the console and the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution). The deprecation warning starts with text and has rest of the [short documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-libraries) after the deprecation marker, if any, afterwards. For example, if the 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 results.
"""
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation).
### [4\.1.6 Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-133)
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. In other words, users do not need to know what APIs their libraries use.
Only differences between static and dynamic libraries are how Robot Framework discovers what keywords a library implements, what arguments and documentation these keywords have, and how the keywords are actually executed. With the static API, all this is done using reflection, 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 must have all keywords in one class or module, whereas with the dynamic API, you can, for example, implement each keyword as a separate class. This use case is not so important with Python, though, because its dynamic capabilities and multi-inheritance already give plenty of flexibility, and there is also possibility to use the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
Another major use case for the dynamic API is implementing a library so that it works as proxy for an actual library possibly running on some other process or even on another machine. This kind of a proxy library can be very thin, and because keyword names and all other information is got dynamically, there is no need to update the proxy when new keywords are added to 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. Python users may also find the [PythonLibCore](https://github.com/robotframework/PythonLibCore) project useful.
#### Getting keyword names
Dynamic libraries tell what keywords they implement with the `get_keyword_names` method. This method cannot take any arguments, and it must return a list or array of strings 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 be mapped to 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.
##### Marking methods to expose as keywords
If a dynamic library should contain both methods which are meant to be keywords and methods which are meant to be private helper methods, it may be wise to mark the keyword methods as such so it is easier to implement `get_keyword_names`. The `robot.api.deco.keyword` decorator allows an easy way to do this since it creates a [custom 'robot\_name' attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) on the decorated method. This allows generating the list of keywords just by checking for the `robot_name` attribute on every method in the library during `get_keyword_names`.
```
from robot.api.deco import keyword
class DynamicExample:
def get_keyword_names(self):
# Get all attributes and their values from the library.
attributes = [(name, getattr(self, name)) for name in dir(self)]
# Filter out attributes that do not have 'robot_name' set.
keywords = [(name, value) for name, value in attributes
if hasattr(value, 'robot_name')]
# Return value of 'robot_name', if given, or the original 'name'.
return [value.robot_name or name for name, value in keywords]
def helper_method(self):
...
@keyword
def keyword_method(self):
...
```
#### 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 `run_keyword` method to get it executed. This method takes two or three 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 [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments) given to the keyword in the test data, and the optional third argument is a dictionary containing [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments). If the third argument is missing, [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries) and [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-dynamic-libraries) are not supported, and other named arguments are mapped to positional arguments.
Note
Prior to Robot Framework 3.1, normal named arguments were mapped to positional arguments regardless did `run_keyword` accept two or three arguments. The third argument only got possible free named arguments.
After getting keyword name and arguments, the library 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 or by using the provided logging APIs, 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 but rest of the methods in the dynamic API are optional. 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, named_args):
print(f"Running keyword '{name}' with positional arguments {args} "
f"and named arguments {named_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 accept. For example, both First Keyword and Second Keyword in the example above could be used with any 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 communicate what arguments their keywords expect by using the `get_keyword_arguments` (alias `getKeywordArguments`) method. This method gets the name of a keyword as an argument, and it must return a list of strings containing the arguments accepted by that keyword.
Similarly as other keywords, dynamic keywords can require any number of [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments), have [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values), accept [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments), accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) and have [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments). The syntax how to represent all these different variables is derived from how they are specified in Python and explained in the following table.
| Argument type | How to represent | Examples |
|---|---|---|
| No arguments | Empty list. | `[]` |
| One or more [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-argument) | List of strings containing argument names. | `['argument']` `['arg1', 'arg2', 'arg3']` |
| [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) | Two ways how to represent the argument name and the default value: As a string where the name and the default are separated with `=`. As a tuple with the name and the default as separate items. New in Robot Framework 3.2. | String with `=` separator: `['name=default']` `['a', 'b=1', 'c=2']` Tuple: `[('name', 'default')]` `['a', ('b', 1), ('c', 2)]` |
| [Positional-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments) | Arguments before the `/` marker. New in Robot Framework 6.1. | `['posonly', '/']` `['p', 'q', '/', 'normal']` |
| [Variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) (varargs) | Argument after possible positional arguments has a `*` prefix | `['*varargs']` `['argument', '*rest']` `['a', 'b=42', '*c']` |
| [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) | Arguments after varargs or a lone `*` if there are no varargs. With or without defaults. Requires `run_keyword` to [support named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries). New in Robot Framework 3.1. | `['*varargs', 'named']` `['*', 'named']` `['*', 'x', 'y=default']` `['a', '*b', ('c', 42)]` |
| [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) (kwargs) | Last arguments has `**` prefix. Requires `run_keyword` to [support free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-dynamic-libraries). | `['**named']` `['a', ('b', 42), '**c']` `['*varargs', '**kwargs']` `['*', 'kwo', '**kws']` |
When the `get_keyword_arguments` is used, Robot Framework automatically calculates how many positional arguments the keyword requires and does it support free named arguments or not. If a keyword is used with invalid arguments, an error occurs and `run_keyword` is not even called.
The actual argument names and default values that are returned are also important. They are needed for [named argument support](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax-with-dynamic-libraries) and the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool needs them to be able to create a meaningful library documentation.
As explained in the above table, default values can be specified with argument names either as a string like `'name=default'` or as a tuple like `('name', 'default')`. The main problem with the former syntax is that all default values are considered strings whereas the latter syntax allows using all objects like `('integer', 1)` or `('boolean', True)`. When using other objects than strings, Robot Framework can do [automatic argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) based on them.
For consistency reasons, also arguments that do not accept default values can be specified as one item tuples. For example, `['a', 'b=c', '*d']` and `[('a',), ('b', 'c'), ('*d',)]` are equivalent.
If `get_keyword_arguments` is missing or returns Python `None` for a certain keyword, that keyword gets an argument specification accepting all arguments. This automatic argument spec is either `[*varargs, **kwargs]` or `[*varargs]`, depending does `run_keyword` [support free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries) or not.
Note
Support to specify arguments as tuples like `('name', 'default')` is new in Robot Framework 3.2. Support for positional-only arguments in dynamic library API is new in Robot Framework 6.1.
#### Getting keyword argument types
Robot Framework 3.1 introduced support for automatic argument conversion and the dynamic library API supports that as well. The conversion logic works exactly like with [static libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion), but how the type information is specified is naturally different.
With dynamic libraries types can be returned using the optional `get_keyword_types` method (alias `getKeywordTypes`). It can return types using a list or a dictionary exactly like types can be specified when using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator). Type information can be specified using actual types like `int`, but especially if a dynamic library gets this information from external systems, using strings like `'int'` or `'integer'` may be easier. See the [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section for more information about supported types and how to specify them.
Robot Framework does automatic argument conversion also based on the [argument default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). Earlier this did not work with the dynamic API because it was possible to specify arguments only as strings. As [discussed in the previous section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments), this was changed in Robot Framework 3.2 and nowadays default values returned like `('example', True)` are automatically used for this purpose.
Starting from Robot Framework 7.0, dynamic libraries can also specify the keyword return type by using key `'return'` with an appropriate type in the returned type dictionary. This information is not used for anything during execution, but it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
#### Getting keyword tags
Dynamic libraries can report [keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) by using the `get_keyword_tags` method (alias `getKeywordTags`). It gets a keyword name as an argument, and should return corresponding tags as a list of strings.
Alternatively it is possible to specify tags on the last row of the documentation returned by the `get_keyword_documentation` method discussed below. This requires starting the last row with `Tags:` and listing tags after it like `Tags: first tag, second, third`.
Tip
The `get_keyword_tags` method is guaranteed to be called before the `get_keyword_documentation` method. This makes it easy to embed tags into the documentation only if the `get_keyword_tags` method is not called.
#### Getting keyword documentation
If dynamic libraries want to provide keyword documentation, they can implement the `get_keyword_documentation` method (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. The main use case is getting keywords' documentations into a library documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) in practice.
Dynamic libraries can also specify the general library documentation directly in the code as the docstring of the library class and its `__init__` method. If a non-empty documentation is got both directly from the code and from the `get_keyword_documentation` method, the latter has precedence.
#### Getting keyword source information
The dynamic API masks the real implementation of keywords from Robot Framework and thus makes it impossible to see where keywords are implemented. This means that editors and other tools utilizing Robot Framework APIs cannot implement features such as go-to-definition. This problem can be solved by implementing yet another optional dynamic method named `get_keyword_source` (alias `getKeywordSource`) that returns the source information.
The return value from the `get_keyword_source` method must be a string or `None` if no source information is available. In the simple case it is enough to simply return an absolute path to the file implementing the keyword. If the line number where the keyword implementation starts is known, it can be embedded to the return value like `path:lineno`. Returning only the line number is possible like `:lineno`.
The source information of the library itself is got automatically from the imported library class the same way as with other library APIs. The library source path is used with all keywords that do not have their own source path defined.
Note
Returning source information for keywords is a new feature in Robot Framework 3.2.
#### Named argument syntax with dynamic libraries
Also the dynamic library API supports the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). Using the syntax works based on the argument names and default values [got from the library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) using the `get_keyword_arguments` method.
If the `run_keyword` method accepts three arguments, the second argument gets all positional arguments as a list and the last arguments gets all named arguments as a mapping. If it accepts only two arguments, named arguments are mapped to positional arguments. In the latter case, if a keyword has multiple arguments with default values and only some of the latter ones are given, the framework fills the skipped optional arguments based on the default values returned by the `get_keyword_arguments` method.
Using the named argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has an argument specification `[a, b=d1, c=d2]`. The comment on each row shows how `run_keyword` would be called in these cases if it has two arguments (i.e. signature is `name, args`) and if it has three arguments (i.e. `name, args, kwargs`).
```
*** Test Cases *** # args # args, kwargs
Positional only
Dynamic x # [x] # [x], {}
Dynamic x y # [x, y] # [x, y], {}
Dynamic x y z # [x, y, z] # [x, y, z], {}
Named only
Dynamic a=x # [x] # [], {a: x}
Dynamic c=z a=x b=y # [x, y, z] # [], {a: x, b: y, c: z}
Positional and named
Dynamic x b=y # [x, y] # [x], {b: y}
Dynamic x y c=z # [x, y, z] # [x, y], {c: z}
Dynamic x b=y c=z # [x, y, z] # [x], {y: b, c: z}
Intermediate missing
Dynamic x c=z # [x, d1, z] # [x], {c: z}
```
Note
Prior to Robot Framework 3.1, all normal named arguments were mapped to positional arguments and the optional `kwargs` was only used with free named arguments. With the above examples `run_keyword` was always called like it is nowadays called if it does not support `kwargs`.
#### Free named arguments with dynamic libraries
Dynamic libraries can also support [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) (`**named`). A mandatory precondition for this support is that the `run_keyword` method [takes three arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords): the third one will get the free named arguments along with possible other named arguments. These arguments are passed to the keyword as a mapping.
What arguments a keyword accepts depends on what `get_keyword_arguments` [returns for it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). If the last argument starts with `**`, that keyword is recognized to accept free named arguments.
Using the free named argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has an argument specification `[a=d1, b=d2, **named]`. The comment shows the arguments that the `run_keyword` method is actually called with.
```
*** Test Cases *** # args, kwargs
No arguments
Dynamic # [], {}
Only positional
Dynamic x # [x], {}
Dynamic x y # [x, y], {}
Only free named
Dynamic x=1 # [], {x: 1}
Dynamic x=1 y=2 z=3 # [], {x: 1, y: 2, z: 3}
Positional and free named
Dynamic x y=2 # [x], {y: 2}
Dynamic x y=2 z=3 # [x], {y: 2, z: 3}
Positional as named and free named
Dynamic a=1 x=1 # [], {a: 1, x: 1}
Dynamic b=2 x=1 a=1 # [], {a: 1, b: 2, x: 1}
```
Note
Prior to Robot Framework 3.1, normal named arguments were mapped to positional arguments but nowadays they are part of the `kwargs` along with the free named arguments.
#### Named-only arguments with dynamic libraries
Starting from Robot Framework 3.1, dynamic libraries can have [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments). This requires that the `run_keyword` method [takes three arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords): the third getting the named-only arguments along with the other named arguments.
In the [argument specification](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) returned by the `get_keyword_arguments` method named-only arguments are specified after possible variable number of arguments (`*varargs`) or a lone asterisk (`*`) if the keyword does not accept varargs. Named-only arguments can have default values, and the order of arguments with and without default values does not matter.
Using the named-only argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has been specified to have argument specification `[positional=default, *varargs, named, named2=default, **free]`. The comment shows the arguments that the `run_keyword` method is actually called with.
```
*** Test Cases *** # args, kwargs
Only named-only
Dynamic named=value # [], {named: value}
Dynamic named=value named2=2 # [], {named: value, named2: 2}
Named-only with positional and varargs
Dynamic argument named=xxx # [argument], {named: xxx}
Dynamic a1 a2 named=3 # [a1, a2], {named: 3}
Named-only with positional as named
Dynamic named=foo positional=bar # [], {positional: bar, named: foo}
Named-only with free named
Dynamic named=value foo=bar # [], {named: value, foo=bar}
Dynamic named2=2 third=3 named=1 # [], {named: 1, named2: 2, third: 3}
```
#### 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.
| Name | Arguments | Purpose |
|---|---|---|
| `get_keyword_names` | | [Return names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-dynamic-keyword-names) of the implemented keywords. |
| `run_keyword` | `name, arguments, kwargs` | [Execute the specified keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords) with given arguments. `kwargs` is optional. |
| `get_keyword_arguments` | `name` | Return keywords' [argument specification](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). Optional method. |
| `get_keyword_types` | `name` | Return keywords' [argument type information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-argument-types). Optional method. New in RF 3.1. |
| `get_keyword_tags` | `name` | Return keywords' [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-tags). Optional method. |
| `get_keyword_documentation` | `name` | Return keywords' and library's [documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-documentation). Optional method. |
| `get_keyword_source` | `name` | Return keywords' [source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-source-information). Optional method. New in RF 3.2. |
A good example of using the dynamic API is Robot Framework's own [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library).
Note
Starting from Robot Framework 7.0, dynamic libraries can have asynchronous implementations of their special methods.
### [4\.1.7 Hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-134)
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](http://docs.python.org/reference/datamodel.html#attribute-access) first.
```
from somewhere import external_keyword
class HybridExample:
def get_keyword_names(self):
return ['my_keyword', 'external_keyword']
def my_keyword(self, arg):
print(f"My Keyword called with '{args}'.")
def __getattr__(self, name):
if name == 'external_keyword':
return external_keyword
raise AttributeError(f"Non-existing attribute '{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`.
#### 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, 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. 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](https://robotframework.org/robotframework/latest/libraries/Telnet.html) library.
### [4\.1.8 Handling Robot Framework's timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-135)
Robot Framework has its own [timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) that can be used for stopping keyword execution if a test or a keyword takes too much time. There are two things to take into account related to them.
#### Doing cleanup if timeout occurs
Timeouts are technically implemented using `robot.errors.TimeoutExceeded` exception that can occur any time during a keyword execution. If a keyword wants to make sure possible cleanup activities are always done, it needs to handle these exceptions. Probably the simplest way to handle exceptions is using Python's `try/finally` structure:
```
def example():
try:
do_something()
finally:
do_cleanup()
```
A benefit of the above is that cleanup is done regardless of the exception. If there is a need to handle timeouts specially, it is possible to catch `TimeoutExceeded` explicitly. In that case it is important to re-raise the original exception afterwards:
```
from robot.errors import TimeoutExceeded
def example():
try:
do_something()
except TimeoutExceeded:
do_cleanup()
raise
```
Note
The `TimeoutExceeded` exception was named `TimeoutError` prior to Robot Framework 7.3. It was renamed to avoid a conflict with Python's standard exception with the same name. The old name still exists as a backwards compatible alias in the `robot.errors` module and can be used if older Robot Framework versions need to be supported.
#### Allowing timeouts to stop execution
Robot Framework's timeouts can stop normal Python code, but if the code calls functionality implemented using C or some other language, timeouts may not work. Well behaving keywords should thus avoid long blocking calls that cannot be interrupted.
As an example, [subprocess.run](https://docs.python.org/3/library/subprocess.html#subprocess.run) cannot be interrupted on Windows, so the following simple keyword cannot be stopped by timeouts there:
```
import subprocess
def run_command(command, *args):
result = subprocess.run([command, *args], encoding='UTF-8')
print(f'stdout: {result.stdout}\nstderr: {result.stderr}')
```
This problem can be avoided by using the lower level [subprocess.Popen](https://docs.python.org/3/library/subprocess.html#subprocess.Popen) and handling waiting in a loop with short timeouts. This adds quite a lot of complexity, though, so it may not be worth the effort in all cases.
```
import subprocess
def run_command(command, *args):
process = subprocess.Popen([command, *args], encoding='UTF-8',
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
try:
stdout, stderr = process.communicate(timeout=0.1)
except subprocess.TimeoutExpired:
continue
else:
break
print(f'stdout: {stdout}\nstderr: {stderr}')
```
### [4\.1.9 Using Robot Framework's internal modules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-136)
Test libraries 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.
#### Available APIs
[API documentation](http://robot-framework.readthedocs.org/) is hosted separately at the excellent [Read the Docs](http://readthedocs.org/) service. If you are unsure how to use certain API or is using them forward compatible, please send a question to [mailing list](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists).
#### Using BuiltIn library
The safest API to use are methods implementing keywords in the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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):
builtin = BuiltIn()
output = do_something_that_creates_a_lot_of_output(argument)
if builtin.robot_running:
output_dir = builtin.replace_variables('${OUTPUT_DIR}')
else:
output_dir = '.'
with open(os.path.join(output_dir, 'output.txt'), 'w') as file:
file.write(output)
print('*HTML* Output written to <a href="output.txt">output.txt</a>')
```
As the above examples illustrates, BuiltIn also has a convenient `robot_running` property for [detecting is Robot Framework running](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#detecting-is-robot-framework-running).
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.
### [4\.1.10 Extending existing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-137)
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](https://github.com/robotframework/SeleniumLibrary).
```
from robot.api.deco import keyword
from SeleniumLibrary import SeleniumLibrary
class ExtendedSeleniumLibrary(SeleniumLibrary):
@keyword
def title_should_start_with(self, expected):
title = self.get_title()
if not title.startswith(expected):
raise AssertionError(f"Title '{title}' did not start with '{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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules).
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
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Get Library Instance 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules). The following example illustrates how to implement the same Title Should Start With keyword as in the earlier example about [using inheritance](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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(f"Title '{title}' did not start with '{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.
```
*** Settings ***
Library SeleniumLibrary
Library SeLibExtensions
*** Test Cases ***
Example
Open Browser http://example # SeleniumLibrary
Title Should Start With Example # SeLibExtensions
```
#### Libraries using dynamic or hybrid API
Test libraries that use the [dynamic](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-582)
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. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries).
- [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-3)
- [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#putting-remote-library-to-use)
- [Importing Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-remote-library)
- [Starting and stopping remote servers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-and-stopping-remote-servers)
- [4\.2.3 Supported argument and return value types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types)
- [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol)
- [Required methods](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#required-methods)
- [Using `get_keyword_names` and keyword specific getters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-get-keyword-names-and-keyword-specific-getters)
- [Using `get_library_information`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-get-library-information)
- [Executing remote keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-remote-keywords)
- [Different argument syntaxes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-argument-syntaxes)
### [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-585)
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](http://www.xmlrpc.com/) protocol. There exists ready-made [generic remote servers](https://github.com/robotframework/RemoteInterface#available-remote-servers) for various languages like Python, Java, Ruby, .NET, and so on.
The remote library interface is provided by the Remote library that is one of the [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol) on top of an XML-RPC channel. The high level architecture of all this is illustrated in the picture below:

Robot Framework architecture with Remote library
Note
The remote client uses Python's standard [XML-RPC module](https://docs.python.org/library/xmlrpc.client.html). It does not support custom XML-RPC extensions implemented by some XML-RPC servers.
### [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-586)
#### [Importing Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-587)
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 suite, or just want to give it a more descriptive name, you can give it an [alias when importing it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library).
```
*** Settings ***
Library Remote http://127.0.0.1:8270 AS Example1
Library Remote http://example.com:8080/ AS Example2
Library Remote http://10.0.0.2/example 1 minute AS Example3
```
The URL used by the first example above is also the default address that the Remote library uses if no address is given.
The last example above shows how to give a custom timeout to the Remote library as an optional second argument. The timeout is used when initially connecting to the server and if a connection accidentally closes. Timeout can be given in Robot Framework [time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format) like `60s` or `2 minutes 10 seconds`. The default timeout is typically several minutes, but it depends on the operating system and its configuration. Notice that setting a timeout that is shorter than keyword execution time will interrupt the keyword.
Note
Port `8270` is the default port that remote servers are expected to use and it has been [registered by IANA](http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=8270) for this purpose. This port number was selected because 82 and 70 are the ASCII codes of letters `R` and `F`, respectively.
Note
When connecting to the local machine, it is recommended to use IP address `127.0.0.1` instead of machine name `localhost`. This avoids address resolution that can be extremely slow [at least on Windows](http://stackoverflow.com/questions/14504450/pythons-xmlrpc-extremely-slow-one-second-per-call).
Note
If the URI contains no path after the server address, the [XML-RPC module](https://docs.python.org/library/xmlrpc.client.html) used by the Remote library will use `/RPC2` path by default. In practice using `http://127.0.0.1:8270` is thus identical to using `http://127.0.0.1:8270/RPC2`. Depending on the remote server this may or may not be a problem. No extra path is appended if the address has a path even if the path is just `/`. For example, neither `http://127.0.0.1:8270/` nor `http://127.0.0.1:8270/my/path` will be modified.
#### [Starting and stopping remote servers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-588)
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 [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) or [SSH](https://github.com/robotframework/SSHLibrary) libraries, can start the server up, but then you may need to use [Import Library keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-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. Typically servers support the following methods:
- Regardless of the library used, remote servers should provide Stop Remote Server keyword that can be easily used by executed tests.
- Remote servers should have `stop_remote_server` method in their XML-RPC interface.
- Hitting `Ctrl-C` on the console where the server is running should stop the server.
- The server process can be terminated using tools provided by the operating system (e.g.
kill
).
Note
Servers 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-589)
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.
Both the Remote library and the Python remote server handle Python values according to the following rules. Other remote servers should behave similarly.
- Strings, numbers and Boolean values are passed without modifications.
- Python `None` is converted to an empty string.
- All lists, tuples, and other iterable objects (except strings and dictionaries) are passed as lists so that their contents are converted recursively.
- Dictionaries and other mappings are passed as dicts so that their keys are converted to strings and values converted to supported types recursively.
- Returned dictionaries are converted to so called *dot-accessible dicts* that allow accessing keys as attributes using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${result.key}`. This works also with nested dictionaries like `${root.child.leaf}`.
- Strings containing bytes in the ASCII range that cannot be represented in XML (e.g. the null byte) are sent as [Binary objects](http://docs.python.org/library/xmlrpc.client.html#binary-objects) that internally use XML-RPC base64 data type. Received Binary objects are automatically converted to byte strings.
- Other types are converted to strings.
### [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-590)
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 remote protocol is implemented on top of [XML-RPC](http://www.xmlrpc.com/), 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 an extension.
The [Python remote server](https://github.com/robotframework/PythonRemoteServer) can be used as a reference implementation.
#### [Required methods](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-591)
There are two possibilities how remote servers can provide information about the keywords they contain. They are briefly explained below and documented more thoroughly in the subsequent sections.
1. Remote servers can implement the same methods as the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) has. This means `get_keyword_names` method and optional `get_keyword_arguments`, `get_keyword_types`, `get_keyword_tags` and `get_keyword_documentation` methods. Notice that using "camel-case names" like `getKeywordNames` is not possible similarly as in the normal dynamic API.
2. Starting from Robot Framework 4.0, remote servers can have a single `get_library_information` method that returns all library and keyword information as a single dictionary. If a remote server has this method, the other getter methods like `get_keyword_names` are not used at all. This approach has the benefit that there is only one XML-RPC call to get information while the approach explained above requires several calls per keyword. With bigger libraries the difference can be significant.
Regardless how remote servers provide information about their keywords, they must have `run_keyword` method that is used when keywords are executed. How the actual keywords are implemented is not relevant for the Remote library. Remote servers can either act as wrappers for the real test libraries, like the available [generic remote servers](https://github.com/robotframework/RemoteInterface#available-remote-servers) do, or they can implement keywords themselves.
Remote servers should additionally have `stop_remote_server` method in their public interface to ease stopping them. They should also automatically expose this method as Stop Remote Server keyword to allow using it in the test data regardless of the test library. Allowing users to stop the server is not always desirable, and servers may support disabling this functionality somehow. The method, and also the exposed keyword, should return `True` or `False` depending on whether stopping is allowed or not. That makes it possible for external tools to know if stopping the server succeeded.
#### [Using `get_keyword_names` and keyword specific getters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-592)
This section explains how the Remote library gets keyword names and other information when the server implements `get_keyword_names`. The next sections covers using the newer `get_library_info` method.
The `get_keyword_names` method must return names of the keyword the server contains as a list of strings. Remote servers can, and should, also implement `get_keyword_arguments`, `get_keyword_types`, `get_keyword_tags` and `get_keyword_documentation` methods to provide more information about the keywords. All these methods take the name of the keyword as an argument and what they must return is explained in the table below.
| Method | Return value |
|---|---|
| `get_keyword_arguments` | Arguments as a list of strings in the [same format as with dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). |
| `get_keyword_types` | Type information as a list or dictionary of strings. See below for details. |
| `get_keyword_documentation` | Documentation as a string. |
| `get_keyword_tags` | Tags as a list of strings. |
Type information used for [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion) can be returned either as a list mapping type names to arguments based on position or as a dictionary mapping argument names to type names directly. In practice this works the same way as when [specifying types using the @keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) with normal libraries. The difference is that because the XML-RPC protocol does not support arbitrary values, type information needs to be specified using type names or aliases like `'int'` or `'integer'`, not using actual types like `int`. Additionally `None` or `null` values may not be allowed by the XML-RPC server, but an empty string can be used to indicate that certain argument does not have type information instead.
Argument conversion is supported also based on default values using the [same logic as with normal libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). For this to work, arguments with default values must be returned as tuples, not as strings, the [same way as with dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). For example, argument conversion works if argument information is returned like `[('count', 1), ('caseless', True)]` but not if it is `['count=1', 'caseless=True']`.
Remote servers can also provide [general library documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-general-library-documentation) to be used when generating documentation with the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool. This information is got by calling `get_keyword_documentation` with special values `__intro__` and `__init__`.
Note
`get_keyword_types` is new in Robot Framework 3.1 and support for argument conversion based on defaults is new in Robot Framework 4.0.
#### [Using `get_library_information`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-593)
The `get_library_information` method allows returning information about the whole library in one XML-RPC call. The information must be returned as a dictionary where keys are keyword names and values are nested dictionaries containing keyword information. The dictionary can also contain separate entries for generic library information.
The keyword information dictionary can contain keyword arguments, documentation, tags and types, and the respective keys are `args`, `doc`, `tags` and `types`. Information must be provided using same semantics as when `get_keyword_arguments`, `get_keyword_documentation`, `get_keyword_tags` and `get_keyword_types` discussed in the previous section. If some information is not available, it can be omitted from the info dictionary altogether.
`get_library_information` supports also returning general library documentation to be used with [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). It is done by including special `__intro__` and `__init__` entries into the returned library information dictionary.
For example, a Python library like
```
"""Library documentation."""
from robot.api.deco import keyword
@keyword(tags=['x', 'y'])
def example(a: int, b=True):
"""Keyword documentation."""
pass
def another():
pass
```
could be mapped into this kind of library information dictionary:
```
{
'__intro__': {'doc': 'Library documentation'}
'example': {'args': ['a', 'b=True'],
'types': ['int'],
'doc': 'Keyword documentation.',
'tags': ['x', 'y']}
'another: {'args': []}
}
```
Note
`get_library_information` is new in Robot Framework 4.0.
#### [Executing remote keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-594)
When the Remote library wants the server to execute some keyword, it calls the remote server's `run_keyword` method and passes it the keyword name, a list of arguments, and possibly a dictionary of [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-argument-syntaxes). Base types can be used as arguments directly, but more complex types are [converted to supported types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-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. Notice that only the `status` entry is mandatory, others can be omitted if they are not applicable.
| 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) in format . It is also possible to embed [timestamps](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamps) to the log messages like `*INFO:1308435758660* Message with timestamp`. |
| return | Possible return value. Must be one of the [supported types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types). |
| error | Possible error message. Used only when the execution fails. |
| traceback | Possible stack trace to [write into the log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) using DEBUG level when the execution fails. |
| continuable | When set to `True`, or any value considered `True` in Python, the occurred failure is considered [continuable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). |
| fatal | Like `continuable`, but denotes that the occurred failure is [fatal](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). |
#### [Different argument syntaxes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-595)
The Remote library is a [dynamic library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library), and in general it handles different argument syntaxes [according to the same rules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) as any other dynamic library. This includes mandatory arguments, default values, varargs, as well as [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax-with-dynamic-libraries).
Also free named arguments (`**kwargs`) works mostly the [same way as with other dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries). First of all, the `get_keyword_arguments` must return an argument specification that contains `**kwargs` exactly like with any other dynamic library. The main difference is that remote servers' `run_keyword` method must have an **optional** third argument that gets the kwargs specified by the user. The third argument must be optional because, for backwards-compatibility reasons, the Remote library passes kwargs to the `run_keyword` method only when they have been used in the test data.
In practice `run_keyword` should look something like the following Python and Java examples, depending on how the language handles optional arguments.
```
def run_keyword(name, args, kwargs=None):
# ...
```
```
public Map run_keyword(String name, List args) {
// ...
}
public Map run_keyword(String name, List args, Map kwargs) {
// ...
}
```
## [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-583)
Robot Framework's listener interface provides a powerful mechanism for getting notifications and for inspecting and modifying data and results during execution. Listeners are called, for example, when suites, tests and keywords start and end, when output files are ready, and finally when the whole execution ends. Example usages include communicating with external test management systems, sending a message when a test fails, and modifying tests during execution.
Listeners are implemented as classes or modules with certain special methods. They can be [taken into use from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line) and be [registered by libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners). The former listeners are active during the whole execution while the latter are active only when executing suites where libraries registering them are imported.
There are two supported listener interface versions, [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2) and [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3). They have mostly the same methods, but these methods are called with different arguments. The newer listener version 3 is more powerful and generally recommended.
- [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-structure)
- [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions)
- [Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2)
- [Listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3)
- [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-listeners-into-use)
- [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line)
- [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners)
- [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-calling-order)
- [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-examples)
- [Getting information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-information)
- [Modifying data and results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#modifying-data-and-results)
- [More examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#more-examples)
### [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-596)
Listeners are implement as modules or classes [similarly as libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-library-class-or-module). They can implement certain named hook methods depending on what events they are interested in. For example, if a listener wants to get a notification when a test starts, it can implement the `start_test` method. As discussed in the subsequent sections, different listener versions have slightly different set of available methods and they also are called with different arguments.
```
# Listener implemented as a module using the listener API version 3.
def start_suite(data, result):
print(f"Suite '{data.name}' starting.")
def end_test(data, result):
print(f"Test '{result.name}' ended with status {result.status}.")
```
Listeners do not need to implement any explicit interface, it is enough to simply implement needed methods and they will be recognized automatically. There are, however, base classes [robot.api.interfaces.ListenerV2](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV2) and [robot.api.interfaces.ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) that can be used to get method name completion in editors, type hints, and so on.
```
# Same as the above example, but uses an optional base class and type hints.
from robot import result, running
from robot.api.interfaces import ListenerV3
class Example(ListenerV3):
def start_suite(self, data: running.TestSuite, result: result.TestSuite):
print(f"Suite '{data.name}' starting.")
def end_test(self, data: running.TestCase, result: result.TestCase):
print(f"Test '{result.name}' ended with status {result.status}.")
```
Note
Optional listener base classes are new in Robot Framework 6.1.
In addition to using "snake case" like `start_test` with listener method names, it is possible to use "camel case" like `startTest`. This support was added when it was possible to run Robot Framework on Jython and implement listeners using Java. It is preserved for backwards compatibility reasons, but not recommended with new listeners.
### [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-597)
There are two supported listener interface versions with version numbers 2 and 3. A listener can specify which version to use by having a `ROBOT_LISTENER_API_VERSION` attribute with value 2 or 3, respectively. Starting from Robot Framework 7.0, the listener version 3 is used by default if the version is not specified.
[Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2) and [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) have mostly the same methods, but arguments passed to these methods are different. Arguments given to listener 2 methods are strings and dictionaries containing information about execution. This information can be inspected and sent further, but it is not possible to modify it directly. Listener 3 methods get the same model objects that Robot Framework itself uses, and these model objects can be both inspected and modified.
Listener version 3 is more powerful than the older listener version 2 and generally recommended.
#### [Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-598)
Listeners using the listener API version 2 get notifications about various events during execution, but they do not have access to actually executed tests and thus cannot directly affect the execution or created results.
Listener methods in the API version 2 are listed in the following table and in the API docs of the optional [ListenerV2](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV2) base class. All methods related to test execution progress have the same signature `method(name, attributes)`, where `attributes` is a dictionary containing details of the event. Listener methods are free to do whatever they want to do with the information they receive, but they cannot directly change it. If that is needed, [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) can be used instead.
| Method | Arguments | Documentation |
|---|---|---|
| start\_suite | name, attributes | Called when a test suite starts. Contents of the attribute dictionary: `id`: Suite id. `s1` for the top level suite, `s1-s1` for its first child suite, `s1-s2` for the second child, and so on. `longname`: Suite name including parent suites. `doc`: Suite documentation. `metadata`: [Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) as a dictionary. `source`: An absolute path of the file/directory the suite was created from. `suites`: Names of the direct child suites this suite has as a list. `tests`: Names of the tests this suite has as a list. Does not include tests of the possible child suites. `totaltests`: The total number of tests in this suite. and all its sub-suites as an integer. `starttime`: Suite execution start time. |
| end\_suite | name, attributes | Called when a test suite ends. Contents of the attribute dictionary: `id`: Same as in `start_suite`. `longname`: Same as in `start_suite`. `doc`: Same as in `start_suite`. `metadata`: Same as in `start_suite`. `source`: Same as in `start_suite`. `starttime`: Same as in `start_suite`. `endtime`: Suite execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Suite status as string `PASS`, `FAIL` or `SKIP`. `statistics`: Suite statistics (number of passed and failed tests in the suite) as a string. `message`: Error message if suite setup or teardown has failed, empty otherwise. |
| start\_test | name, attributes | Called when a test case starts. Contents of the attribute dictionary: `id`: Test id in format like `s1-s2-t2`, where the beginning is the parent suite id and the last part shows test index in that suite. `longname`: Test name including parent suites. `originalname`: Test name with possible variables unresolved. New in RF 3.2. `doc`: Test documentation. `tags`: Test tags as a list of strings. `template`: The name of the template used for the test. An empty string if the test not templated. `source`: An absolute path of the test case source file. New in RF 4.0. `lineno`: Line number where the test starts in the source file. New in RF 3.2. `starttime`: Test execution execution start time. |
| end\_test | name, attributes | Called when a test case ends. Contents of the attribute dictionary: `id`: Same as in `start_test`. `longname`: Same as in `start_test`. `originalname`: Same as in `start_test`. `doc`: Same as in `start_test`. `tags`: Same as in `start_test`. `template`: Same as in `start_test`. `source`: Same as in `start_test`. `lineno`: Same as in `start_test`. `starttime`: Same as in `start_test`. `endtime`: Test execution execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Test status as string `PASS`, `FAIL` or `SKIP`. `message`: Status message. Normally an error message or an empty string. |
| start\_keyword | name, attributes | Called when a keyword or a control structure such as `IF/ELSE` or `TRY/EXCEPT` starts. With keywords `name` is the full keyword name containing possible library or resource name as a prefix like `MyLibrary.Example Keyword`. With control structures `name` contains string representation of parameters. Keywords and control structures share most of attributes, but control structures can have additional attributes depending on their `type`. Shared attributes: `type`: String specifying type of the started item. Possible values are: `KEYWORD`, `SETUP`, `TEARDOWN`, `FOR`, `WHILE`, `ITERATION`, `IF`, `ELSE IF`, `ELSE`, `TRY`, `EXCEPT`, `FINALLY`, `VAR`, `RETURN`, `BREAK`, `CONTINUE` and `ERROR`. All type values were changed in RF 4.0 and in RF 5.0 `FOR ITERATION` was changed to `ITERATION`. `kwname`: Name of the keyword without library or resource prefix. String representation of parameters with control structures. `libname`: Name of the library or resource file the keyword belongs to. An empty string with user keywords in a test case file and with control structures. `doc`: Keyword documentation. `args`: Keyword's arguments as a list of strings. `assign`: A list of variable names that keyword's return value is assigned to. `tags`: [Keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) as a list of strings. `source`: An absolute path of the file where the keyword was used. New in RF 4.0. `lineno`: Line where the keyword was used. Typically an integer, but can be `None` if a keyword has been executed by a listener. New in RF 4.0. `status`: Initial keyword status. `NOT RUN` if keyword is not executed (e.g. due to an earlier failure), `NOT SET` otherwise. New in RF 4.0. `starttime`: Keyword execution start time. Additional attributes for `FOR` types: `variables`: Assigned variables for each loop iteration as a list or strings. `flavor`: Type of loop (e.g. `IN RANGE`). `values`: List of values being looped over as a list or strings. `start`: Start configuration. Only used with `IN ENUMERATE` loops. New in RF 6.1. `mode`: Mode configuration. Only used with `IN ZIP` loops. New in RF 6.1. `fill`: Fill value configuration. Only used with `IN ZIP` loops. New in RF 6.1. Additional attributes for `ITERATION` types with `FOR` loops: `variables`: Variables and string representations of their contents for one `FOR` loop iteration as a dictionary. Additional attributes for `WHILE` types: `condition`: The looping condition. `limit`: The maximum iteration limit. `on_limit`: What to do if the limit is exceeded. Valid values are `pass` and `fail`. New in RF 7.0. `on_limit_message`: The custom error raised when the limit of the WHILE loop is reached. New in RF 6.1. Additional attributes for `IF` and `ELSE IF` types: `condition`: The conditional expression being evaluated. With `ELSE IF` new in RF 6.1. Additional attributes for `EXCEPT` types: `patterns`: The exception patterns being matched as a list or strings. `pattern_type`: The type of pattern match (e.g. `GLOB`). `variable`: The variable containing the captured exception. Additional attributes for `RETURN` types: `values`: Return values from a keyword as a list or strings. Additional attributes for `VAR` types: `name`: Variable name. `value`: Variable value. A string with scalar variables and a list otherwise. `scope`: Variable scope (e.g. `GLOBAL`) as a string. Additional attributes for control structures are in general new in RF 6.0. `VAR` is new in RF 7.0. |
| end\_keyword | name, attributes | Called when a keyword or a control structure ends. `name` is the full keyword name containing possible library or resource name as a prefix. For example, `MyLibrary.Example Keyword`. Control structures have additional attributes, which change based on the `type` attribute. For descriptions of all possible attributes, see the `start_keyword` section. Contents of the attribute dictionary: `type`: Same as with `start_keyword`. `kwname`: Same as with `start_keyword`. `libname`: Same as with `start_keyword`. `doc`: Same as with `start_keyword`. `args`: Same as with `start_keyword`. `assign`: Same as with `start_keyword`. `tags`: Same as with `start_keyword`. `source`: Same as with `start_keyword`. `lineno`: Same as with `start_keyword`. `starttime`: Same as with `start_keyword`. `endtime`: Keyword execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Keyword status as string `PASS`, `FAIL`, `SKIP` or `NOT RUN`. `SKIP` and `NOT RUN` are new in RF 4.0. |
| log\_message | message | Called when an executed keyword writes a log message. `message` is a dictionary with the following contents: `message`: The content of the message. `level`: [Log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) used in logging the message. `timestamp`: Message creation time in format `YYYY-MM-DD hh:mm:ss.mil`. `html`: String `yes` or `no` denoting whether the message should be interpreted as HTML or not. Not called if the message level is below the current [threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). |
| message | message | Called when the framework itself writes a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) message. `message` is a dictionary with the same contents as with `log_message` method. |
| library\_import | name, attributes | Called when a library has been imported. `name` is the name of the imported library. If the library has been given a custom name when imported it using `AS`, `name` is the specified alias. Contents of the attribute dictionary: `args`: Arguments passed to the library as a list. `originalname`: The original library name if the library has been given an alias using `AS`, otherwise same as `name`. `source`: An absolute path to the library source. An empty string if getting the source of the library failed for some reason. `importer`: An absolute path to the file importing the library. `None` when [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) is imported as well as when using the Import Library keyword. |
| resource\_import | name, attributes | Called when a resource file has been imported. `name` is the name of the imported resource file without the file extension. Contents of the attribute dictionary: `source`: An absolute path to the imported resource file. `importer`: An absolute path to the file importing the resource file. `None` when using the Import Resource keyword. |
| variables\_import | name, attributes | Called when a variable file has been imported. `name` is the name of the imported variable file with the file extension. Contents of the attribute dictionary: `args`: Arguments passed to the variable file as a list. `source`: An absolute path to the imported variable file. `importer`: An absolute path to the file importing the resource file. `None` when using the Import Variables keyword. |
| output\_file | path | Called when writing to an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is ready. `path` is an absolute path to the file as a string or a string `None` if creating the output file is disabled. |
| log\_file | path | Called when writing to a [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) is ready. `path` is an absolute path to the file as a string. Not called if creating the log file is disabled. |
| report\_file | path | Called when writing to a [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is ready. `path` is an absolute path to the file as a string. Not called if creating the report file is disabled. |
| xunit\_file | path | Called when writing to an [xunit file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-file) is ready. `path` is an absolute path to the file as a string. Only called if creating the xunit file is enabled. |
| debug\_file | path | Called when writing to a [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) is ready. `path` is an absolute path to the file as a string. Only called if creating the debug file is enabled. |
| close | | Called when the whole test execution ends. With [library listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-listeners) called when the library goes out of scope. |
#### [Listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-599)
Listener version 3 has mostly the same methods as [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2), but arguments of the methods related to test execution are different. These methods get actual running and result model objects that used by Robot Framework itself, and listeners can both query information they need and change the model objects on the fly.
Note
Modifications to the data can also be done using [pre-run modifiers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifiers). The main benefit of using listeners is that changes can be done dynamically based on what happens during the execution. Another difference is that command like options related to [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) affect tests added by pre-run modifiers but not tests added by listeners.
Listener version 3 was enhanced heavily in Robot Framework 7.0 when it got methods related to keywords and control structures. It was enhanced further in Robot Framework 7.1 when it got methods related to library, resource file and variable file imports.
Listener version 3 has separate methods for library keywords, user keywords and all control structures. If there is a need to listen to all keyword related events, it is possible to implement `start_keyword` and `end_keyword`. In addition to that, `start_body_item` and `end_body_item` can be implemented to get notifications related to all keywords and control structures. These higher level listener methods are not called if more specific methods like `start_library_keyword` or `end_if` are implemented.
Listener methods in the API version 3 are listed in the following table and in the API docs of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class.
| Method | Arguments | Documentation |
|---|---|---|
| start\_suite | data, result | Called when a test suite starts. `data` and `result` are model objects representing the [executed test suite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.TestSuite), respectively. |
| end\_suite | data, result | Called when a test suite ends. Same arguments as with `start_suite`. |
| start\_test | data, result | Called when a test case starts. `data` and `result` are model objects representing the [executed test case](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.TestCase), respectively. |
| end\_test | data, result | Called when a test case ends. Same arguments as with `start_test`. |
| start\_keyword | data, result | Called when a keyword starts. `data` and `result` are model objects representing the [executed keyword call](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.Keyword) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.Keyword), respectively. This method is called, by default, with user keywords, library keywords and when a keyword call is invalid. It is not called if a more specific `start_user_keyword`, `start_library_keyword` or `start_invalid_keyword` method is implemented. |
| end\_keyword | data, result | Called when a keyword ends. Same arguments and other semantics as with `start_keyword`. |
| start\_user\_keyword | data, implementation, result | Called when a user keyword starts. `data` and `result` are the same as with `start_keyword` and `implementation` is the actually executed [user keyword](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.resourcemodel.UserKeyword). If this method is implemented, `start_keyword` is not called with user keywords. |
| end\_user\_keyword | data, implementation, result | Called when a user keyword ends. Same arguments and other semantics as with `start_user_keyword`. |
| start\_library\_keyword | data implementation, result | Called when a library keyword starts. `data` and `result` are the same as with `start_keyword` and `implementation` represents the executed [library keyword](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.librarykeyword.LibraryKeyword). If this method is implemented, `start_keyword` is not called with library keywords. |
| end\_library\_keyword | data, implementation, result | Called when a library keyword ends. Same arguments and other semantics as with `start_library_keyword`. |
| start\_invalid\_keyword | data implementation, result | Called when an invalid keyword call starts. `data` and `result` are the same as with `start_keyword` and `implementation` represents the [invalid keyword call](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.invalidkeyword.InvalidKeyword). Keyword may not have been found, there could have been multiple matches, or the keyword call itself could have been invalid. If this method is implemented, `start_keyword` is not called with invalid keyword calls. |
| end\_invalid\_keyword | data, implementation, result | Called when an invalid keyword call ends. Same arguments and other semantics as with `start_invalid_keyword`. |
| start\_for, start\_for\_iteration, start\_while, start\_while\_iteration, start\_if, start\_if\_branch, start\_try, start\_try\_branch, start\_group, start\_var, start\_continue, start\_break, start\_return | data, result | Called when control structures start. See the documentation and type hints of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class for more information. |
| end\_for, end\_for\_iteration, end\_while, end\_while\_iteration, end\_if, end\_if\_branch, end\_try, end\_try\_branch, end\_group, end\_var, end\_continue, end\_break, end\_return | data, result | Called when control structures end. See the documentation and type hints of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class for more information. |
| start\_error | data, result | Called when invalid syntax starts. |
| end\_error | data, result | Called when invalid syntax ends. |
| start\_body\_item | data, result | Called when a keyword or a control structure starts, unless a more specific method such as `start_keyword` or `start_if` is implemented. |
| end\_body\_item | data, result | Called when a keyword or a control structure ends, unless a more specific method such as `end_keyword` or `end_if` is implemented. |
| log\_message | message | Called when an executed keyword writes a log message. `message` is a model object representing the [logged message](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.Message). This method is not called if the message has level below the current [threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). |
| message | message | Called when the framework itself writes a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) message. `message` is same object as with `log_message`. |
| library\_import | library, importer | Called after a library has been imported. [library](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.testlibraries.TestLibrary) represents the imported library. It can be inspected and also modified. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the library was imported. |
| resource\_import | resource, importer | Called after a resource file has been imported. [resource](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.ResourceFile) represents the imported resource file. It can be inspected and also modified. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the resource was imported. |
| variables\_import | attrs, importer | Called after a variable file has been imported. `attrs` contains information about the imported variable file as a dictionary. It can be inspected, but modifications to it have no effect. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the variable file was imported. This method will be changed in the future so that the `attrs` dictionary is replaced with an object representing the imported variable file. |
| output\_file | path | Called when writing to an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object or the `None` object if creating the output file is disabled. |
| log\_file | path | Called when writing to a [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Not called if creating the log file is disabled. |
| report\_file | path | Called when writing to a [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Not called if creating the report file is disabled. |
| xunit\_file | path | Called when writing to an [xunit file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Only called if creating the xunit file is enabled. |
| debug\_file | path | Called when writing to a [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Only called if creating the debug file is enabled. |
| close | | Called when the whole test execution ends. With [library listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-listeners) called when the library goes out of scope. |
Note
Methods related to keywords and control structures are new in Robot Framework 7.0.
Note
Methods related to library, resource file and variable file imports are new in Robot Framework 7.1.
Note
Prior to Robot Framework 7.0, paths passed to result file related listener version 3 methods were strings.
### [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-600)
#### [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-601)
Listeners that need to be active during the whole execution must be taken into use from the command line. That is done using 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, similarly as [library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-name) is got from the class or module implementing the library. The specified listeners must be in the same [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) where test libraries are searched from when they are imported. In addition to registering a listener by using a name, it is possible to give an absolute or a relative path to the listener file [similarly as with test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-physical-path-to-library). It is possible to take multiple listeners into use by using this option several times:
```
robot --listener MyListener tests.robot
robot --listener path/to/MyListener.py tests.robot
robot --listener module.Listener --listener AnotherListener tests.robot
```
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. If a listener is given as an absolute Windows path, the colon after the drive letter is not considered a separator. Additionally, it is possible to use a semicolon (`;`) as an alternative argument separator. This is useful if listener arguments themselves contain colons, but requires surrounding the whole value with quotes on UNIX-like operating systems:
```
robot --listener listener.py:arg1:arg2 tests.robot
robot --listener "listener.py;arg:with:colons" tests.robot
robot --listener c:\path\listener.py;d:\first\arg;e:\second\arg tests.robot
```
In addition to passing arguments one-by-one as positional arguments, it is possible to pass them using the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) similarly as when using keywords:
```
robot --listener listener.py:name=value tests.robot
robot --listener "listener.py;name=value:with:colons;second=argument" tests.robot
```
Listener arguments are automatically converted using [same rules as with keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) based on [type hints](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) and [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). For example, this listener
```
class Listener:
def __init__(self, port: int, log=True):
self.port = post
self.log = log
```
could be used like
```
robot --listener Listener:8270:false
```
and the first argument would be converted to an integer based on the type hint and the second to a Boolean based on the default value.
Note
Both the named argument syntax and argument conversion are new in Robot Framework 4.0.
#### [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-602)
Sometimes it is useful also for [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) to get notifications about test execution. This allows them, for example, to perform certain clean-up activities automatically when a test suite or the whole test execution ends.
##### Registering listener
A test library can register a listener by using the `ROBOT_LIBRARY_LISTENER` attribute. The value of this attribute should be an instance of the listener to use. It may be a totally independent listener or the library itself can act as a listener. To avoid listener methods to be exposed as keywords in the latter case, it is possible to prefix them with an underscore. For example, instead of using `end_suite` it is possible to use `_end_suite`.
Following examples illustrates using an external listener as well as a library acting as a listener itself:
```
from listener import Listener
class LibraryWithExternalListener:
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_LISTENER = Listener()
def example_keyword(self):
...
```
```
class LibraryItselfAsListener:
ROBOT_LIBRARY_SCOPE = 'SUITE'
ROBOT_LISTENER_API_VERSION = 2
def __init__(self):
self.ROBOT_LIBRARY_LISTENER = self
# Use the '_' prefix to avoid listener method becoming a keyword.
def _end_suite(self, name, attrs):
print(f"Suite '{name}' ending with status {attrs['id']}.")
def example_keyword(self):
...
```
As the second example above already demonstrated, library listeners can specify [listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions) using the `ROBOT_LISTENER_API_VERSION` attribute exactly like any other listener.
Starting from Robot Framework 7.0, a listener can register itself to be a listener also by using a string `SELF` (case-insensitive) as a listener. This is especially convenient when using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator):
```
from robot.api.deco import keyword, library
@library(scope='SUITE', listener='SELF')
class LibraryItselfAsListener:
# Listener version is not specified, so uses the listener version 3 by default.
# When using the @library decorator, keywords must use the @keyword decorator,
# so there is no need to use the '_' prefix here.
def end_suite(self, data, result):
print(f"Suite '{data.name}' ending with status {result.status}.")
@keyword
def example_keyword(self):
...
```
It is also possible to specify multiple listeners for a single library by giving `ROBOT_LIBRARY_LISTENER` a value as a list:
```
from listeners import Listener1, Listener2, Listener3
class LibraryWithMultipleListeners:
ROBOT_LIBRARY_LISTENER = [Listener1(), Listener2(), Listener3()]
def example_keyword(self):
...
```
##### Called listener methods
Library listeners get notifications about all events in suites where libraries using them are imported. In practice this means that suite, test, keyword, control structure and log message related methods are called. In addition to them, the `close` method is called when the library goes out of the scope.
If library creates a new listener instance every time when the library itself is instantiated, the actual listener instance to use will change according to the [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope).
### [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-603)
By default, listeners are called in the order they are taken into use so that listeners registered from the command line are called before library listeners. It is, however, possible to control the calling order by setting the special `ROBOT_LISTENER_PRIORITY` attribute to an integer or a floating point value. The bigger the number, the higher precedence the listener has and the earlier it is called. The number can be positive or negative and it is zero by default.
The custom order does not affect the `close` method of library listeners, though. That method is always called when the library goes out of its scope.
Note
Controlling listener calling order is new in Robot Framework 7.1.
### [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-604)
This section contains examples using the listener interface. First examples illustrate getting notifications during execution and latter examples modify executed tests and created results.
#### [Getting information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-605)
The first example is implemented as a Python module. It uses the [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2), but could equally well be implemented by using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
```
"""Listener that stops execution if a test fails."""
ROBOT_LISTENER_API_VERSION = 2
def end_test(name, attrs):
if attrs['status'] == 'FAIL':
print(f"Test '{name}'" failed: {attrs['message']}")
input("Press enter to continue.")
```
If the above example would be saved to, for example, PauseExecution.py file, it could be used from the command line like this:
```
robot --listener path/to/PauseExecution.py tests.robot
```
The next example, which still uses the listener version 2, 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 it also has a default value. Note that in real usage, the [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) functionality available through the command line option \--debugfile is probably more useful than this example.
```
import os.path
import tempfile
class Example:
ROBOT_LISTENER_API_VERSION = 2
def __init__(self, file_name='listen.txt'):
path = os.path.join(tempfile.gettempdir(), file_name)
self.file = open(path, 'w')
def start_suite(self, name, attrs):
self.file.write("%s '%s'\n" % (name, attrs['doc']))
def start_test(self, name, attrs):
tags = ' '.join(attrs['tags'])
self.file.write("- %s '%s' [ %s ] :: " % (name, attrs['doc'], tags))
def end_test(self, name, attrs):
if attrs['status'] == 'PASS':
self.file.write('PASS\n')
else:
self.file.write('FAIL: %s\n' % attrs['message'])
def end_suite(self, name, attrs):
self.file.write('%s\n%s\n' % (attrs['status'], attrs['message']))
def close(self):
self.file.close()
```
#### [Modifying data and results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-606)
The following examples illustrate how to modify the executed tests and suites as well as the execution results. All these examples require using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
##### Modifying executed suites and tests
Changing what is executed is as easy as modifying the model objects representing executed data passed to listener methods. This is illustrated by the example below that adds a new test to each executed suite and a new keyword call to each test.
```
def start_suite(data, result):
data.tests.create(name='New test')
def start_test(data, result):
data.body.create_keyword(name='Log', args=['Keyword added by listener!'])
```
This API is very similar to the [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) API that can be used to modify suites and tests before the whole test execution starts. The main benefit of using the listener API is that modifications can be done dynamically based on execution results or otherwise. This allows, for example, interesting possibilities for model based testing.
Although the listener interface is not built on top of Robot Framework's internal [visitor interface](http://robot-framework.readthedocs.org/en/master/autodoc/robot.model.html#module-robot.model.visitor) similarly as the pre-run modifier API, listeners can still use the visitors interface themselves. For example, the `SelectEveryXthTest` visitor used in [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) examples could be used like this:
```
from SelectEveryXthTest import SelectEveryXthTest
def start_suite(suite, result):
selector = SelectEveryXthTest(x=2)
suite.visit(selector)
```
##### Accessing library or resource file
It is possible to get more information about the actually executed keyword and the library or resource file it belongs to:
```
from robot.running import Keyword as KeywordData, LibraryKeyword
from robot.result import Keyword as KeywordResult
def start_library_keyword(data: KeywordData,
implementation: LibraryKeyword,
result: KeywordResult):
library = implementation.owner
print(f"Keyword '{implementation.name}' is implemented in library "
f"'{library.name}' at '{implementation.source}' on line "
f"{implementation.lineno}. The library has {library.scope.name} "
f"scope and the current instance is {library.instance}.")
```
As the above example illustrates, it is possible to get an access to the actual library instance. This means that listeners can inspect the library state and also modify it. With user keywords it is even possible to modify the keyword itself or, via the `owner` resource file, any other keyword in the resource file.
##### Modifying results
Test execution results can be altered by modifying the result objects passed to listener methods. This is demonstrated by the following listener that is implemented as a class and also uses type hints:
```
from robot import result, running
class ResultModifier:
def __init__(self, max_seconds: float = 10.0):
self.max_seconds = max_seconds
def start_suite(self, data: running.TestSuite, result: result.TestSuite):
result.doc = 'Documentation set by listener.'
# Information about tests only available via data at this point.
smoke_tests = [test for test in data.tests if 'smoke' in test.tags]
result.metadata['Smoke tests'] = len(smoke_tests)
def end_test(self, data: running.TestCase, result: result.TestCase):
elapsed_seconds = result.elapsed_time.total_seconds()
if result.status == 'PASS' and elapsed_seconds > self.max_seconds:
result.status = 'FAIL'
result.message = 'Test execution took too long.'
def log_message(self, msg: result.Message):
if msg.level == 'WARN' and not msg.html:
msg.message = f'<b style="font-size: 1.5em">{msg.message}</b>'
msg.html = True
if self._message_is_not_relevant(msg.message):
msg.message = None
def _message_is_not_relevant(self, message: str) -> bool:
...
```
A limitation is that modifying the name of the current test suite or test case is not possible because it has already been written to the [output.xml](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-xml) file when listeners are called. Due to the same reason modifying already finished tests in the `end_suite` method has no effect either.
When modifying logged messages, it is possible to remove a message altogether by setting `message` to `None` as the above example demonstrates. This can be used for removing sensitive or non-relevant messages so that there is nothing visible in the log file.
This API is very similar to the [pre-Rebot modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-rebot-modifier) API that can be used to modify results before report and log are generated. The main difference is that listeners modify also the created output.xml file.
Note
Removing messages altogether by setting them to `None` is new in Robot Framework 7.2.
##### Changing keyword and control structure status
Listeners can also affect the execution flow by changing statuses of the executed keywords and control structures. For example, if a listener changes the status of a passed keyword to FAIL, the keyword is considered failed exactly as if it had failed normally. Similarly, it is possible to change the status of a passed or failed keyword to SKIP to get the keyword and the whole test skipped. It is also possible to silence failures by changing the status to PASS, but this should be done only in special cases and with great care to avoid hiding real failures.
The following example demonstrates changing the status by failing keywords that take too long time to execute. The previous example had similar logic with tests, but this listener also stops the execution immediately if there is a keyword that is too slow. As the example shows, listeners can also change the error message, not only the status.
```
from robot import result, running
class KeywordPerformanceMonitor:
def __init__(self, max_seconds: float = 0.1):
self.max_seconds = max_seconds
def end_keyword(self, data: running.Keyword, result: result.Keyword):
elapsed_seconds = result.elapsed_time.total_seconds()
if result.status == 'PASS' and elapsed_seconds > self.max_seconds:
result.status = 'FAIL'
result.message = 'Keyword execution took too long.'
```
Note
Changes to status only affect the execution flow starting from Robot Framework 7.1.
#### [More examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-607)
Keyword and control structure related listener version 3 methods are so versatile that covering them fully here in the User Guide is not possible. For more examples, you can see the [acceptance tests](https://github.com/robotframework/robotframework/tree/master/atest/testdata/output/listener_interface/body_items_v3) using theses methods in various ways.
## [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-584)
Robot Framework supports external parsers that can handle custom data formats or even override Robot Framework's own parser.
Note
Custom parsers are new in Robot Framework 6.1.
- [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-parsers-into-use)
- [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-api)
- [`EXTENSION` or `extension` attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extension-or-extension-attribute)
- [`parse` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parse-method)
- [`parse_init` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parse-init-method)
- [Optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#optional-base-class)
- [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#examples-2)
- [Parser implemented as module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-implemented-as-module)
- [Parser implemented as class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-implemented-as-class)
- [Parser extending optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-extending-optional-base-class)
- [Parser as preprocessor](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-as-preprocessor)
### [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-608)
Parsers are taken into use from the command line with the \--parser option using exactly the same semantics as with [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line). This includes specifying parsers as names or paths, giving arguments to parser classes, and so on:
```
robot --parser MyParser tests.custom
robot --parser path/to/MyParser.py tests.custom
robot --parser Parser1:arg --parser Parser2:a1:a2 path/to/tests
```
### [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-609)
Parsers can be implemented both as modules and classes. This section explains what attributes and methods they must contain.
#### [`EXTENSION` or `extension` attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-610)
This attribute specifies what file extension or extensions the parser supports. Both `EXTENSION` and `extension` names are accepted, and the former has precedence if both exist. The attribute can be either a string or a sequence of strings. Extensions are case-insensitive and can be specified with or without the leading dot. If a parser is implemented as a class, it is possible to set this attribute either as a class attribute or as an instance attribute.
Also extensions containing multiple parts like .example.ext or .robot.zip are supported.
Note
If a parser supports the .robot extension, it will be used for parsing these files instead of the standard parser.
#### [`parse` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-611)
The mandatory `parse` method is responsible for parsing [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files). It is called with each parsed file that has an extension that the parser supports. The method must return a [TestSuite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) object.
In simple cases `parse` can be implemented so that it accepts just a single argument that is a [pathlib.Path](https://docs.python.org/library/pathlib.html) object pointing to the file to parse. If the parser is interested in defaults for Test Setup, Test Teardown, Test Tags and Test Timeout set in higher level [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files), the `parse` method must accept two arguments. In that case the second argument is a [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) object.
#### [`parse_init` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-612)
The optional `parse_init` method is responsible for parsing [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) i.e. files in format `__init__.ext` where `.ext` is an extension supported by the parser. The method must return a [TestSuite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) object representing the whole directory. Suites created from child suite files and directories will be added to its child suites.
Also `parse_init` can be implemented so that it accepts one or two arguments, depending on is it interested in test related default values or not. If it accepts defaults, it can manipulate the passed [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) object and changes are seen when parsing child suite files.
This method is only needed if a parser needs to support suite initialization files.
#### [Optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-613)
Parsers do not need to implement any explicit interface, but it may be helpful to extend the optional [Parser](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.Parser) base class. The main benefit is that the base class has documentation and type hints. It also works as a bit more formal API specification.
### [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-614)
#### [Parser implemented as module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-615)
The first example demonstrates a simple parser implemented as a module and supporting one hard-coded extension. It just creates a dummy suite and does not actually parse anything.
```
from robot.api import TestSuite
EXTENSION = '.example'
def parse(source):
suite = TestSuite(name='Example', source=source)
test = suite.tests.create(name='Test')
test.body.create_keyword(name='Log', args=['Hello!'])
return suite
```
#### [Parser implemented as class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-616)
The second parser is implemented as a class that accepts the extension to use as an argument. The parser reads the given source file and creates dummy tests from each line it contains.
```
from pathlib import Path
from robot.api import TestSuite
class ExampleParser:
def __init__(self, extension: str):
self.extension = extension
def parse(self, source: Path) -> TestSuite:
name = TestSuite.name_from_source(source, self.extension)
suite = TestSuite(name, source=source)
for line in source.read_text().splitlines():
test = suite.tests.create(name=line)
test.body.create_keyword(name='Log', args=['Hello!'])
return suite
```
#### [Parser extending optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-617)
This parser extends the optional [Parser](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.Parser) base class. It supports parsing suite initialization files, uses [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) and registers multiple extensions.
```
from pathlib import Path
from robot.api import TestSuite
from robot.api.interfaces import Parser, TestDefaults
class ExampleParser(Parser):
extension = ('example', 'another')
def parse(self, source: Path, defaults: TestDefaults) -> TestSuite:
"""Create a suite and set possible defaults from init files to tests."""
suite = TestSuite(TestSuite.name_from_source(source), source=source)
for line in source.read_text().splitlines():
test = suite.tests.create(name=line, doc='Example')
test.body.create_keyword(name='Log', args=['Hello!'])
defaults.set_to(test)
return suite
def parse_init(self, source: Path, defaults: TestDefaults) -> TestSuite:
"""Create a dummy suite and set some defaults.
This method is called only if there is an initialization file with
a supported extension.
"""
defaults.tags = ('tags', 'from init')
defaults.setup = {'name': 'Log', 'args': ['Hello from init!']}
return TestSuite(TestSuite.name_from_source(source.parent), doc='Example',
source=source, metadata={'Example': 'Value'})
```
#### [Parser as preprocessor](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-618)
The final example parser acts as a preprocessor for Robot Framework data files that supports headers in format `=== Test Cases ===` in addition to `*** Test Cases ***`. In this kind of usage it is convenient to use [TestSuite.from\_string](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_string), [TestSuite.from\_model](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_model) and [TestSuite.from\_file\_system](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_file_system) factory methods for constructing the returned suite.
```
from pathlib import Path
from robot.running import TestDefaults, TestSuite
class RobotPreprocessor:
extension = '.robot'
def parse(self, source: Path, defaults: TestDefaults) -> TestSuite:
data = source.read_text()
for header in 'Settings', 'Variables', 'Test Cases', 'Keywords':
data = data.replace(f'=== {header} ===', f'*** {header} ***')
suite = TestSuite.from_string(data, defaults=defaults)
return suite.config(name=TestSuite.name_from_source(source), source=source)
```
# [5 Supporting Tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-153)
- [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-documentation-tool-libdoc)
- [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-documentation-tool-testdoc)
- [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-clean-up-tool-tidy)
- [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-tools)
## [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-619)
- [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage)
- [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#writing-documentation)
- [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax)
- [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking-1)
- [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#representing-arguments)
- [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example)
Libdoc is Robot Framework's built-in tool that can generate documentation for Robot Framework libraries and resource files. It can generate HTML documentation for humans as well as machine readable spec files in XML and JSON formats. Libdoc also has few special commands to show library or resource information on the console.
Documentation can be created for:
- libraries implemented using the normal static library [API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries),
- libraries using the [dynamic API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-libraries), including remote libraries,
- [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files),
- [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), and
- [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files).
Additionally it is possible to use XML and JSON spec files created by Libdoc earlier as an input.
Note
Support for generating documentation for suite files and suite initialization files is new in Robot Framework 6.0.
### [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-623)
#### Synopsis
```
libdoc [options] library_or_resource output_file
libdoc [options] library_or_resource list|show|version [names]
```
#### Options
> | | |
> |---|---|
> | `-f, --format <html|xml|json|libspec>` | |
> | | Specifies whether to generate an HTML output for humans or a machine readable spec file in XML or JSON format. The `libspec` format means XML spec with documentations converted to HTML. The default format is got from the output file extension. |
> | `-s, --specdocformat <raw|html>` | |
> | | Specifies the documentation format used with XML and JSON spec files. `raw` means preserving the original documentation format and `html` means converting documentation to HTML. The default is `raw` with XML spec files and `html` with JSON specs and when using the special `libspec` format. |
> | `-F, --docformat <robot|html|text|rest>` | |
> | | Specifies the source documentation format. Possible values are Robot Framework's documentation format, HTML, plain text, and reStructuredText. Default value can be specified in test library source code and the initial default value is `robot`. |
> | `--theme <dark|light|none>` | |
> | | Use dark or light HTML theme. If this option is not used, or the value is `none`, the theme is selected based on the browser color scheme. Only applicable with HTML outputs. New in Robot Framework 6.0. |
> | `--language <lang>` | |
> | | Set the default language in documentation. `lang` must be a code of a built-in language, which are `en` and `fi`. New in Robot Framework 7.2. |
> | `-N, --name <newname>` | |
> | | Sets the name of the documented library or resource. |
> | `-V, --version <newversion>` | |
> | | Sets the version of the documented library or resource. The default value for test libraries is [defined in the source code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version). |
> | `-P, --pythonpath <path>` | |
> | | Additional locations where to search for libraries and resources similarly as when [running tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-pythonpath-option). |
> | `--quiet` | Do not print the path of the generated output file to the console. |
> | `-h, --help` | Prints this help. |
#### Executing Libdoc
The easiest way to run Libdoc is using the `libdoc` command created as part of the normal installation:
```
libdoc ExampleLibrary ExampleLibrary.html
```
Alternatively it is possible to execute the `robot.libdoc` module directly. This approach is especially useful if you have installed Robot Framework using multiple Python versions and want to use a specific version with Libdoc:
```
python -m robot.libdoc ExampleLibrary ExampleLibrary.html
python3.9 -m robot.libdoc ExampleLibrary ExampleLibrary.html
```
Yet another alternative is running the `robot.libdoc` module as a script:
```
python path/to/robot/libdoc.py ExampleLibrary ExampleLibrary.html
```
Note
The separate `libdoc` command is new in Robot Framework 4.0.
#### Specifying library or resource file
##### Python libraries and dynamic libraries with name or path
When documenting libraries implemented with Python or that use the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api), it is possible to specify the library either by using just the library name or path to the library source code:
```
libdoc ExampleLibrary ExampleLibrary.html
libdoc src/ExampleLibrary.py docs/ExampleLibrary.html
```
In the former case the library is searched using the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) and its name must be in the same format as when [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries) in Robot Framework test data.
If these libraries require arguments when they are imported, the arguments must be catenated with the library name or path using two colons like `MyLibrary::arg1::arg2`. If arguments change what keywords the library provides or otherwise alter its documentation, it might be a good idea to use \--name option to also change the library name accordingly.
##### Resource files with path
Resource files must always be specified using a path:
```
libdoc example.resource example.html
```
If the path does not exist, resource files are also searched from all directories in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) similarly as when executing test cases.
##### Libdoc spec files
Earlier generated Libdoc XML or JSON spec files can also be used as inputs. This works if spec files use either \*.xml, \*.libspec or \*.json extension:
```
libdoc Example.xml Example.html
libdoc Example.libspec Example.html
libdoc Example.json Example.html
```
Note
Support for the \*.libspec extension is new in Robot Framework 3.2.
Note
Support for the \*.json extension is new in Robot Framework 4.0.
#### Generating documentation
Libdoc can generate documentation in HTML (for humans) and XML or JSON (for tools) formats. The file where to write the documentation is specified as the second argument after the library/resource name or path, and the output format is got from the output file extension by default.
##### Libdoc HTML documentation
Most Robot Framework libraries use Libdoc to generate library documentation in HTML format. This format is thus familiar for most people who have used Robot Framework. A simple example can be seen below, and it has been generated based on the example found a [bit later in this section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries).
[](https://robotframework.org/robotframework/latest/images/ExampleLibrary.html)
The HTML documentation starts with general library introduction, continues with a section about configuring the library when it is imported (when applicable), and finally has shortcuts to all keywords and the keywords themselves. The magnifying glass icon on the lower right corner opens the keyword search dialog that can also be opened by simply pressing the `s` key.
Libdoc automatically creates HTML documentation if the output file extension is \*.html. If there is a need to use some other extension, the format can be specified explicitly with the \--format option.
Starting from Robot Framework 7.2, it is possible to localise the static texts in the HTML documentation by using the \--language option.
See the `README.rst` file in `src/web/libodc` directory in the project repository for up to date information about how to add new languages for the localisation.
```
libdoc OperatingSystem OperatingSystem.html
libdoc --name MyLibrary Remote::http://10.0.0.42:8270 MyLibrary.html
libdoc --format HTML test/resource.robot doc/resource.htm
```
##### Libdoc XML spec files
Libdoc can also generate documentation in XML format that is suitable for external tools such as editors. It contains all the same information as the HTML format but in a machine readable format.
XML spec files also contain library and keyword source information so that the library and each keyword can have source path (`source` attribute) and line number (`lineno` attribute). The source path is relative to the directory where the spec file is generated thus does not refer to a correct file if the spec is moved. The source path is omitted with keywords if it is the same as with the library, and both the source path and the line number are omitted if getting them from the library fails for whatever reason.
Libdoc automatically uses the XML format if the output file extension is \*.xml or \*.libspec. When using the special \*.libspec extension, Libdoc automatically enables the options `-f XML -s HTML` which means creating an XML output file where keyword documentation is converted to HTML. If needed, the format can be explicitly set with the \--format option.
```
libdoc OperatingSystem OperatingSystem.xml
libdoc test/resource.robot doc/resource.libspec
libdoc --format xml MyLibrary MyLibrary.spec
libdoc --format xml -s html MyLibrary MyLibrary.xml
```
The exact Libdoc spec file format is documented with an [XML schema](https://en.wikipedia.org/wiki/XML_Schema_\(W3C\)) (XSD) at <https://github.com/robotframework/robotframework/tree/master/doc/schema>. The spec file format may change between Robot Framework major releases.
To make it easier for external tools to know how to parse a certain spec file, the spec file root element has a dedicated `specversion` attribute. It was added in Robot Framework 3.2 with value `2` and earlier spec files can be considered to have version `1`. The spec version will be incremented in the future if and when changes are made. Robot Framework 4.0 introduced new spec version `3` which is incompatible with earlier versions.
Note
The `XML:HTML` format introduced in Robot Framework 3.2. has been replaced by the format `LIBSPEC` ot the option combination `--format XML --specdocformat HTML`.
Note
Including source information and spec version are new in Robot Framework 3.2.
##### Libdoc JSON spec files
Since Robot Framework 4.0 Libdoc can also generate documentation in JSON format that is suitable for external tools such as editors or web pages. It contains all the same information as the HTML format but in a machine readable format.
Similar to XML spec files the JSON spec files contain all information and can also be used as input to Libdoc. From that format any other output format can be created. By default the library documentation strings are converted to HTML format within the JSON output file.
The exact JSON spec file format is documented with an [JSON schema](https://json-schema.org/) at <https://github.com/robotframework/robotframework/tree/master/doc/schema>. The spec file format may change between Robot Framework major releases.
#### Viewing information on console
Libdoc has three special commands to show information on the console. These commands are used instead of the name of the output file, and they can also take additional arguments.
`list`
List names of the keywords the library/resource contains. Can be limited to show only certain keywords by passing optional patterns as arguments. Keyword is listed if its name contains given pattern.
`show`
Show library/resource documentation. Can be limited to show only certain keywords by passing names as arguments. Keyword is shown if its name matches any given name. Special argument `intro` will show only the library introduction and importing sections.
`version`
Show library version
Optional patterns given to `list` and `show` are case and space insensitive. Both also accept `*` and `?` as wildcards.
Examples:
```
libdoc Dialogs list
libdoc SeleniumLibrary list browser
libdoc Remote::10.0.0.42:8270 show
libdoc Dialogs show PauseExecution execute*
libdoc SeleniumLibrary show intro
libdoc SeleniumLibrary version
```
### [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-624)
This section discusses writing documentation for [Python](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries) based test libraries that use the static library API as well as for [dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-libraries) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-documentation). [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) is described in more details elsewhere in the User Guide.
#### Python libraries
The documentation for Python libraries that use the [static library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords) is written simply as doc strings for the library class or module and for methods implementing keywords. The first line of the method documentation is considered as a short documentation for the keyword (used, for example, as a tool tip in links in the generated HTML documentation), and it should thus be as describing as possible, but not too long.
The simple example below illustrates how to write the documentation in general. How the HTML documentation generated based on this example looks like can be seen [above](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-html-documentation), and there is also a [bit longer example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example) at the end of this chapter.
```
class ExampleLibrary:
"""Library for demo purposes.
This library is only used in an example and it doesn't do anything useful.
"""
def my_keyword(self):
"""Does nothing."""
pass
def your_keyword(self, arg):
"""Takes one argument and *does nothing* with it.
Examples:
| Your Keyword | xxx |
| Your Keyword | yyy |
"""
pass
```
Tip
If you library does some initialization work that should not be done when using Libdoc, you can [easily detect is Robot Framework running](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#detecting-is-robot-framework-running)
Tip
For more information on Python documentation strings, see [PEP-257](http://www.python.org/dev/peps/pep-0257).
#### Dynamic libraries
To be able to generate meaningful documentation for dynamic libraries, the libraries must return keyword argument names and documentation using `get_keyword_arguments` and `get_keyword_documentation` methods (or using their camelCase variants `getKeywordArguments` and `getKeywordDocumentation`). Libraries can also support general library documentation via special `__intro__` and `__init__` values to the `get_keyword_documentation` method.
See the [Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) section for more information about how to create these methods.
#### Importing section
A separate section about how the library is imported is created based on its initialization methods. If the library has an `__init__` method that takes arguments in addition to `self`, its documentation and arguments are shown.
```
class TestLibrary:
def __init__(self, mode='default')
"""Creates new TestLibrary. `mode` argument is used to determine mode."""
self.mode = mode
def some_keyword(self, arg):
"""Does something based on given `arg`.
What is done depends on the `mode` specified when `importing` the library.
"""
if self.mode == 'secret':
# ...
```
#### Resource file documentation
Keywords in resource files can have documentation using \[Documentation\] setting, and this documentation is also used by Libdoc. First line of the documentation (until the first [implicit newline](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines) or explicit `\n`) is considered to be the short documentation similarly as with test libraries.
Also the resource file itself can have Documentation in the Setting section for documenting the whole resource file.
Possible variables in resource files can not be documented.
```
*** Settings ***
Documentation Resource file for demo purposes.
... This resource is only used in an example and it doesn't do anything useful.
*** Keywords ***
My Keyword
[Documentation] Does nothing
No Operation
Your Keyword
[Arguments] ${arg}
[Documentation] Takes one argument and *does nothing* with it.
...
... Examples:
... | Your Keyword | xxx |
... | Your Keyword | yyy |
No Operation
```
### [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-625)
Libdoc supports documentation in Robot Framework's own [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1), HTML, plain text, and [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText). The format to use can be specified in [library source code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) using `ROBOT_LIBRARY_DOC_FORMAT` attribute or given from the command line using \--docformat (-F) option. In both cases the possible case-insensitive values are `ROBOT` (default), `HTML`, `TEXT` and `reST`.
Robot Framework's own documentation format is the default and generally recommended format. Other formats are especially useful when using existing code with existing documentation in test libraries.
#### Robot Framework documentation syntax
Most important features in Robot Framework's [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1) are formatting using `*bold*` and `_italic_`, custom links and automatic conversion of URLs to links, and the possibility to create tables and pre-formatted text blocks (useful for examples) simply with pipe character. If documentation gets longer, support for section titles can also be handy.
Some of the most important formatting features are illustrated in the example below. Notice that since this is the default format, there is no need to use `ROBOT_LIBRARY_DOC_FORMAT` attribute nor give the format from the command line.
```
"""Example library in Robot Framework format.
- Formatting with *bold* and _italic_.
- URLs like http://example.com are turned to links.
- Custom links like [http://robotframework.org|Robot Framework] are supported.
- Linking to `My Keyword` works.
"""
def my_keyword():
"""Nothing more to see here."""
```
##### Creating table of contents automatically
With bigger libraries it is often useful to add a table of contents to the library introduction. When using the Robot Framework documentation format, this can be done automatically by adding a special `%TOC%` marker into a line on its own. The table of contents is created based on the top-level [section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles) (e.g. `= Section =`) used in the introduction. In addition to them, the TOC also gets links to the [automatically created sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-automatic-sections) for shortcuts and keywords as well as for importing and tags sections when applicable.
```
"""Example library demonstrating TOC generation.
The %TOC% marker only creates the actual table of contents and possible
header or other explanation needs to be added separately like done below.
== Table of contents ==
%TOC%
= Section title =
The top-level section titles are automatically added to the TOC.
= Second section =
== Sub section ==
Sub section titles are not added to the TOC.
"""
def my_keyword():
"""Nothing more to see here."""
```
Note
Automatic TOC generation is a new feature in Robot Framework 3.2.
#### HTML documentation syntax
When using HTML format, you can create documentation pretty much freely using any syntax. The main drawback is that HTML markup is not that human friendly, and that can make the documentation in the source code hard to maintain and read. Documentation in HTML format is used by Libdoc directly without any transformation or escaping. The special syntax for [linking to keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-keywords) using syntax like \`My Keyword\` is supported, however.
Example below contains the same formatting examples as the previous example. Now `ROBOT_LIBRARY_DOC_FORMAT` attribute must be used or format given on the command line like `--docformat HTML`.
```
"""Example library in HTML format.
<ul>
<li>Formatting with <b>bold</b> and <i>italic</i>.
<li>URLs are not turned to links automatically.
<li>Custom links like <a href="http://www.w3.org/html">HTML</a> are supported.
<li>Linking to `My Keyword` works.
</ul>
"""
ROBOT_LIBRARY_DOC_FORMAT = 'HTML'
def my_keyword():
"""Nothing more to see here."""
```
#### Plain text documentation syntax
When the plain text format is used, Libdoc uses the documentation as-is. Newlines and other whitespace are preserved except for indentation, and HTML special characters (`<>&`) escaped. The only formatting done is turning URLs into clickable links and supporting [internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking) like \`My Keyword\`.
```
"""Example library in plain text format.
- Formatting is not supported.
- URLs like http://example.com are turned to links.
- Custom links are not supported.
- Linking to `My Keyword` works.
"""
ROBOT_LIBRARY_DOC_FORMAT = 'text'
def my_keyword():
"""Nothing more to see here."""
```
#### reStructuredText documentation syntax
[reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) is simple yet powerful markup syntax used widely in Python projects (including this User Guide) and elsewhere. The main limitation is that you need to have the [docutils](https://pypi.python.org/pypi/docutils) module installed to be able to generate documentation using it. Because backtick characters have special meaning in reStructuredText, [linking to keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-keywords) requires them to be escaped like \\\`My Keyword\\\`.
One of the nice features that reStructured supports is the ability to mark code blocks that can be syntax highlighted. Syntax highlight requires additional [Pygments](http://pygments.org/) module and supports all the languages that Pygments supports.
```
"""Example library in reStructuredText format.
- Formatting with **bold** and *italic*.
- URLs like http://example.com are turned to links.
- Custom links like reStructuredText__ are supported.
- Linking to \`My Keyword\` works but requires backtics to be escaped.
__ http://docutils.sourceforge.net
.. code:: robotframework
*** Test Cases ***
Example
My keyword # How cool is this!!?!!?!1!!
"""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def my_keyword():
"""Nothing more to see here."""
```
### [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-626)
Libdoc supports internal linking to keywords and different sections in the documentation. Linking is done by surrounding the target name with backtick characters like \`target\`. Target names are case-insensitive and possible targets are explained in the subsequent sections.
There is no error or warning if a link target is not found, but instead Libdoc just formats the text in italics. Earlier this formatting was recommended to be used when referring to keyword arguments, but that was problematic because it could accidentally create internal links. Nowadays it is recommended to use [inline code style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles) with double backticks like \``argument\`` instead. The old formatting of single backticks may even be removed in the future in favor of giving an error when a link target is not found.
In addition to the examples in the following sections, internal linking and argument formatting is shown also in the [longer example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example) at the end of this chapter.
#### Linking to keywords
All keywords the library have automatically create link targets and they can be linked using syntax \`Keyword Name\`. This is illustrated with the example below where both keywords have links to each others.
```
def keyword(log_level="INFO"):
"""Does something and logs the output using the given level.
Valid values for log level` are "INFO" (default) "DEBUG" and "TRACE".
See also `Another Keyword`.
"""
# ...
def another_keyword(argument, log_level="INFO"):
"""Does something with the given argument else and logs the output.
See `Keyword` for information about valid log levels.
"""
# ...
```
Note
When using [reStructuredText documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-documentation-syntax), backticks must be escaped like \\\`Keyword Name\\\`.
#### Linking to automatic sections
The documentation generated by Libdoc always contains sections for overall library introduction and for keywords. If a library itself takes arguments, there is also separate [importing section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-section). If any of the keywords has [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags), a separate selector for them is also shown in the overview.
All the sections act as targets that can be linked, and the possible target names are listed in the table below. Using these targets is shown in the example of the next section.
| Section | Target |
|---|---|
| Introduction | \`introduction\` and \`library introduction\` |
| Importing | \`importing\` and \`library importing\` |
| Keywords | \`keywords\` |
Note
Before Robot Framework 4.0 there were also sections for tags and shortcuts. In Robot Framework 4.0 these have been removed in favor of the overview menu. This means that prior linking to shortcuts or tags sections does not work.
#### Linking to custom sections
Robot Framework's [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1) supports custom [section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles), and the titles used in the library or resource file introduction automatically create link targets. The example below illustrates linking both to automatic and custom sections:
```
"""Library for Libdoc demonstration purposes.
This library does not do anything useful.
= My section =
We do have a custom section in the documentation, though.
"""
def keyword():
"""Does nothing.
See `introduction` for more information and `My section` to test how
linking to custom sections works.
"""
pass
```
Note
Linking to custom sections works only when using [Robot Framework documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-framework-documentation-syntax).
### [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-627)
Libdoc shows information about keywords' arguments automatically.
#### Included information
The following information is shown for all keywords regardless are they implemented in libraries or in resource files:
- Argument name. User keyword arguments are shown without the `${}` decoration to make arguments look the same regardless where keywords originate from.
- Marker telling is the argument [positional-only](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments), [named-only](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-only-arguments), [free positional](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#varargs-library), [free named](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#kwargs-library), or [normal argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) that can be given either by position or by name.
- Possible default value. Shown like `= 42`.
- Possible type. Shown like `<int>`. Can be a link to type documentation as explained in the next section.
When referring to arguments in keyword documentation, it is recommended to use [inline code style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles) like \``argument\``.
#### Automatically listing type documentation
As mentioned above, Libdoc automatically shows possible type information when listing arguments. If the type is a custom type based on [Enum](https://docs.python.org/library/enum.html#enum.Enum) or [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict), the type is [automatically converted](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions), or the type has [custom converter](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters), also the type itself is listed separately to show more information about it. When these types are used in arguments, the type name also becomes a link to the type information.
All listed data types show possible type documentation as well as what argument types are supported. In addition to that, types based on `Enum` list available members and types based on `TypedDict` show the dictionary structure.
Note
Automatically listing types based on `Enum` and `TypedDict` is new in Robot Framework 4.0. Listing other types is new in Robot Framework 5.0.
### [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-628)
The following example illustrates how to use the most important [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) possibilities, [internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking), and so on. [Click here](https://robotframework.org/robotframework/latest/images/LoggingLibrary.html) to see how the generated documentation looks like.
```
class LoggingLibrary:
"""Library for logging messages.
= Table of contents =
%TOC%
= Usage =
This library has several keyword, for example `Log Message`, for logging
messages. In reality the library is used only for _Libdoc_ demonstration
purposes.
= Valid log levels =
Valid log levels are ``INFO``, ``DEBUG``, and ``TRACE``. The default log
level can be set during `importing`.
= Examples =
Notice how keywords are linked from examples.
| `Log Message` | My message | | |
| `Log Two Messages` | My message | Second message | level=DEBUG |
| `Log Messages` | First message | Second message | Third message |
"""
ROBOT_LIBRARY_VERSION = '0.1'
def __init__(self, default_level='INFO'):
"""The default log level can be given at library import time.
See `Valid log levels` section for information about available log
levels.
Examples:
| =Setting= | =Value= | =Value= | =Comment= |
| Library | LoggingLibrary | | # Use default level (INFO) |
| Library | LoggingLibrary | DEBUG | # Use the given level |
"""
self.default_level = self._verify_level(default_level)
def _verify_level(self, level):
level = level.upper()
if level not in ['INFO', 'DEBUG', 'TRACE']:
raise RuntimeError("Invalid log level'%s'. Valid levels are "
"'INFO', 'DEBUG', and 'TRACE'")
return level
def log_message(self, message, level=None):
"""Writes given message to the log file using the specified log level.
The message to log and the log level to use are defined using
``message`` and ``level`` arguments, respectively.
If no log level is given, the default level given during `library
importing` is used.
"""
level = self._verify_level(level) if level else self.default_level
print("*%s* %s" % (level, message))
def log_two_messages(self, message1, message2, level=None):
"""Writes given messages to the log file using the specified log level.
See `Log Message` keyword for more information.
"""
self.log_message(message1, level)
self.log_message(message2, level)
def log_messages(self, *messages):
"""Logs given messages using the log level set during `importing`.
See also `Log Message` and `Log Two Messages`.
"""
for msg in messages:
self.log_message(msg)
```
All [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) have documentation generated by Libdoc and their documentation (and source code) act as a more realistic examples.
## [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-620)
- [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage-1)
- [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-documentation-1)
Testdoc is Robot Framework's built-in tool for generating high level documentation based on test cases. The created documentation is in HTML format and it includes name, documentation and other metadata of each test suite and test case, as well as the top-level keywords and their arguments.
Note
The built-in Testdoc tool is deprecated and will be removed in Robot Framework 8.0. Use the new and enhanced [external Testdoc](https://github.com/MarvKler/robotframework-testdoc) instead.
### [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-629)
#### Synopsis
```
python -m robot.testdoc [options] data_sources output_file
```
#### Options
> | | |
> |---|---|
> | `-T, --title <title>` | |
> | | Set the title of the generated documentation. Underscores in the title are converted to spaces. The default title is the name of the top level suite. |
> | `-N, --name <name>` | |
> | | Override the name of the top level test suite. |
> | `-D, --doc <doc>` | |
> | | Override the documentation of the top level test suite. |
> | `-M, --metadata <name:value>` | |
> | | Set/override free metadata of the top level test suite. |
> | `-G, --settag <tag>` | |
> | | Set given tag(s) to all test cases. |
> | `-t, --test <name>` | |
> | | Include tests by name. |
> | `-s, --suite <name>` | |
> | | Include suites by name. |
> | `-i, --include <tag>` | |
> | | Include tests by tags. |
> | `-e, --exclude <tag>` | |
> | | Exclude tests by tags. |
> | `-A, --argumentfile <path>` | |
> | | Text file to read more arguments from. Works exactly like [argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) when running tests. |
> | `-h, --help` | Print this help in the console. |
All options except \--title have exactly the same semantics as same options have when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution).
### [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-630)
Data can be given as a single file, directory, or as multiple files and directories. In all these cases, the last argument must be the file where to write the output.
Testdoc can be executed as an installed module like `python -m robot.testdoc` or as a script like `python path/robot/testdoc.py`.
Examples:
```
python -m robot.testdoc my_test.robot testdoc.html
python path/to/robot/testdoc.py --name "Smoke tests" --include smoke path/to/tests smoke.html
```
## [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-621)
The built-in Tidy tool was deprecated in Robot Framework 4.1 in favor of the new and enhanced external [Robotidy](https://robotidy.readthedocs.io/) tool. It was removed altogether in Robot Framework 5.0.
## [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-622)
There are plenty of external tools that can be used with Robot Framework. These tools include plugins for various IDEs and text editors, tools for parallel execution and data-driven testing, plugins for continuous integration systems, and so on.
These tools are developed as separate projects independently from Robot Framework itself. For a list of the available tools see <http://robotframework.org/>.
# [6 Appendices](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-166)
- [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings)
- [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options)
- [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations)
- [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting)
- [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format)
- [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-arguments)
- [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions)
- [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registrations)
## [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-631)
This appendix lists all settings that can be used in different sections.
Note
Settings can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
- [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-section-1)
- [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-section)
- [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-section-1)
### [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-639)
The Setting section is used to import 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 section can only include settings for importing libraries, resources, and variables.
| Name | Description |
|---|---|
| Library | Used for [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries). |
| Resource | Used for [taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use). |
| Variables | Used for [taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use). |
| Name | Used for setting a custom [suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name). |
| Documentation | Used for specifying a [suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation) or [resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-resource-files) documentation. |
| Metadata | Used for setting [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata). |
| Suite Setup | Used for specifying the [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). |
| Suite Teardown | Used for specifying the [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). |
| Test Tags | Used for specifying [test case tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-tags) for all tests in a suite. |
| Force Tags, Default Tags | [Deprecated settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecation-of-force-tags-and-default-tags) for specifying test case tags. |
| Keyword Tags | Used for specifying [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) for all keywords in a certain file. |
| Test Setup | Used for specifying a default [test setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| Test Teardown | Used for specifying a default [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| Test Template | Used for specifying a default [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) for test cases. |
| Test Timeout | Used for specifying a default [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). |
| Task Setup, Task Teardown, Task Template, Task Timeout | Aliases for Test Setup, Test Teardown, Test Template and Test Timeout, respectively, that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks). |
### [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-640)
The settings in the Test Case section are always specific to the test case for which they are defined. Some of these settings override the default values defined in the Settings section.
Exactly same settings are available when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) in the Task section.
| Name | Description |
|---|---|
| \[Documentation\] | Used for specifying a [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). |
| \[Tags\] | Used for [tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases). |
| \[Setup\] | Used for specifying a [test setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| \[Teardown\] | Used for specifying a [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| \[Template\] | Used for specifying a [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates). |
| \[Timeout\] | Used for specifying a [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). |
### [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-641)
Settings in the Keyword section are specific to the user keyword for which they are defined.
| Name | Description |
|---|---|
| \[Documentation\] | Used for specifying a [user keyword documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation). |
| \[Tags\] | Used for specifying [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags). |
| \[Arguments\] | Used for specifying [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments). |
| \[Setup\] | Used for specifying a [user keyword setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup). New in Robot Framework 7.0. |
| \[Teardown\] | Used for specifying [user keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown). |
| \[Timeout\] | Used for specifying a [user keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout). |
| \[Return\] | Used for specifying [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values). Deprecated in Robot Framework 7.0. Use the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement instead. |
## [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-632)
This appendix lists all the command line options that are available when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). Also environment variables affecting execution and post-processing are listed.
- [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-test-execution)
- [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-post-processing-outputs)
- [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables-for-execution-and-post-processing)
### [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-642)
> | | |
> |---|---|
> | `--rpa` | Turn on [generic automation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) mode. |
> | `--language <lang>` | |
> | | Activate [localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). `lang` can be a name or a code of a [built-in language](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations), or a path or a module name of a custom language file. |
> | `-F, --extension <value>` | |
> | | [Parse only these files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) when executing a directory. |
> | `-I, --parseinclude <pattern>` | |
> | | [Parse only matching files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) when executing a directory. |
> | `-N, --name <name>` | |
> | | [Sets the name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) of the top-level test suite. |
> | `-D, --doc <document>` | |
> | | [Sets the documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) of the top-level test suite. |
> | `-M, --metadata <name:value>` | |
> | | [Sets free metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata) for the top level test suite. |
> | `-G, --settag <tag>` | |
> | | [Sets the tag(s)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags) to all executed test cases. |
> | `-t, --test <name>` | |
> | | [Selects the test cases by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names). |
> | `--task <name>` | Alias for \--test that can be used when [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks). |
> | `-s, --suite <name>` | |
> | | [Selects the test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) by name. |
> | `-R, --rerunfailed <file>` | |
> | | [Selects failed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-cases) from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) to be re-executed. |
> | `-S, --rerunfailedsuites <file>` | |
> | | [Selects failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-suites) from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) to be re-executed. |
> | `-i, --include <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-e, --exclude <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `--skip <tag>` | Tests having given tag will be [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped). Tag can be a pattern. |
> | `--skiponfailure <tag>` | |
> | | Tests having given tag will be [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped) if they fail. |
> | `-v, --variable <name:value>` | |
> | | Sets [individual variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables). |
> | `-V, --variablefile <path:args>` | |
> | | Sets variables using [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files). |
> | `-d, --outputdir <dir>` | |
> | | Defines where to [create output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory). |
> | `-o, --output <file>` | |
> | | Sets the path to the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file). |
> | `--legacyoutput` | Creates output file in [Robot Framework 6.x compatible format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#legacy-xml-format). |
> | `-l, --log <file>` | |
> | | Sets the path to the generated [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). |
> | `-r, --report <file>` | |
> | | Sets the path to the generated [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file). |
> | `-x, --xunit <file>` | |
> | | Sets the path to the generated [xUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file). |
> | `-b, --debugfile <file>` | |
> | | A [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) that is written during execution. |
> | `-T, --timestampoutputs` | |
> | | [Adds a timestamp](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files) to [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) listed above. |
> | `--splitlog` | [Split log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs) into smaller pieces that open in browser transparently. |
> | `--logtitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test log. |
> | `--reporttitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test report. |
> | `--reportbackground <colors>` | |
> | | [Sets background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors) of the generated report. |
> | `--maxerrorlines <lines>` | |
> | | Sets the number of [error lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports) shown in report when tests fail. |
> | `--maxassignlength <characters>` | |
> | | Sets the number of characters shown in log when [variables are assigned](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-logging-assigned-variable-value). |
> | `-L, --loglevel <level>` | |
> | | [Sets the threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level) for logging. Optionally the default [visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level) can be given separated with a colon (:). |
> | `--suitestatlevel <level>` | |
> | | Defines how many [levels to show](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics) in the *Statistics by Suite* table in outputs. |
> | `--tagstatinclude <tag>` | |
> | | [Includes only these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) in the *Statistics by Tag* table. |
> | `--tagstatexclude <tag>` | |
> | | [Excludes these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) from the *Statistics by Tag* table. |
> | `--tagstatcombine <tags:title>` | |
> | | Creates [combined statistics based on tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics). |
> | `--tagdoc <pattern:doc>` | |
> | | Adds [documentation to the specified tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags). |
> | `--tagstatlink <pattern:link:title>` | |
> | | Adds [external links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names) to the *Statistics by Tag* table. |
> | `--expandkeywords <name:pattern|tag:pattern>` | |
> | | Automatically [expand keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords) in the generated log file. |
> | `--removekeywords <all|passed|name:pattern|tag:pattern|for|while|wuks>` | |
> | | [Removes keyword data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) from the generated log file. |
> | `--flattenkeywords <for|while|iteration|name:pattern|tag:pattern>` | |
> | | [Flattens keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) in the generated log file. |
> | `--listener <name:args>` | |
> | | [Sets a listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners) for monitoring test execution. |
> | `--nostatusrc` | Sets the [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) to zero regardless of failures in test cases. Error codes are returned normally. |
> | `--runemptysuite` | |
> | | Executes tests also if the selected [test suites are empty](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). |
> | `--dryrun` | In the [dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run) mode tests are run without executing keywords originating from test libraries. Useful for validating test data syntax. |
> | `-X, --exitonfailure` | |
> | | [Stops test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-when-first-test-case-fails) if any test fails. |
> | `--exitonerror` | [Stops test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error) if any error occurs when parsing test data, importing libraries, and so on. |
> | `--skipteardownonexit` | |
> | | [Skips teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-teardowns) if test execution is prematurely stopped. |
> | `--prerunmodifier <name:args>` | |
> | | Activate [programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data). |
> | `--prerebotmodifier <name:args>` | |
> | | Activate [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results). |
> | `--randomize <all|suites|tests|none>` | |
> | | [Randomizes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order) test execution order. |
> | `--console <verbose|dotted|quiet|none>` | |
> | | [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type). |
> | `--dotted` | Shortcut for `--console dotted`. |
> | `--quiet` | Shortcut for `--console quiet`. |
> | `-W, --consolewidth <width>` | |
> | | [Sets the width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-width) of the console output. |
> | `-C, --consolecolors <auto|on|ansi|off>` | |
> | | [Specifies are colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) used on the console. |
> | `--consolelinks <auto|off>` | |
> | | Controls [making paths to results files hyperlinks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links). |
> | `-K, --consolemarkers <auto|on|off>` | |
> | | Show [markers on the console](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-markers) when top level keywords in a test case end. |
> | `-P, --pythonpath <path>` | |
> | | Additional locations to add to the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). |
> | `-A, --argumentfile <path>` | |
> | | A text file to [read more arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) from. |
> | `-h, --help` | Prints [usage instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
> | `--version` | Prints the [version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
### [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-643)
> | | |
> |---|---|
> | `--rpa` | Turn on [generic automation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) mode. |
> | `-R, --merge` | Changes result combining behavior to [merging](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs). |
> | `-N, --name <name>` | |
> | | [Sets the name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) of the top level test suite. |
> | `-D, --doc <document>` | |
> | | [Sets the documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) of the top-level test suite. |
> | `-M, --metadata <name:value>` | |
> | | [Sets free metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata) for the top-level test suite. |
> | `-G, --settag <tag>` | |
> | | [Sets the tag(s)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags) to all processed test cases. |
> | `-t, --test <name>` | |
> | | [Selects the test cases by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names). |
> | `--task <name>` | Alias for \--test. |
> | `-s, --suite <name>` | |
> | | [Selects the test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) by name. |
> | `-i, --include <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-e, --exclude <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-d, --outputdir <dir>` | |
> | | Defines where to [create output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory). |
> | `-o, --output <file>` | |
> | | Sets the path to the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file). |
> | `--legacyoutput` | Creates output file in [Robot Framework 6.x compatible format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#legacy-xml-format). |
> | `-l, --log <file>` | |
> | | Sets the path to the generated [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). |
> | `-r, --report <file>` | |
> | | Sets the path to the generated [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file). |
> | `-x, --xunit <file>` | |
> | | Sets the path to the generated [xUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file). |
> | `-T, --timestampoutputs` | |
> | | [Adds a timestamp](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files) to [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) listed above. |
> | `--splitlog` | [Split log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs) into smaller pieces that open in browser transparently. |
> | `--logtitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test log. |
> | `--reporttitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test report. |
> | `--reportbackground <colors>` | |
> | | [Sets background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors) of the generated report. |
> | `-L, --loglevel <level>` | |
> | | [Sets the threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level) to select log messages. Optionally the default [visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level) can be given separated with a colon (:). |
> | `--suitestatlevel <level>` | |
> | | Defines how many [levels to show](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics) in the *Statistics by Suite* table in outputs. |
> | `--tagstatinclude <tag>` | |
> | | [Includes only these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) in the *Statistics by Tag* table. |
> | `--tagstatexclude <tag>` | |
> | | [Excludes these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) from the *Statistics by Tag* table. |
> | `--tagstatcombine <tags:title>` | |
> | | Creates [combined statistics based on tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics). |
> | `--tagdoc <pattern:doc>` | |
> | | Adds [documentation to the specified tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags). |
> | `--tagstatlink <pattern:link:title>` | |
> | | Adds [external links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names) to the *Statistics by Tag* table. |
> | `--expandkeywords <name:pattern|tag:pattern>` | |
> | | Automatically [expand keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords) in the generated log file. |
> | `--removekeywords <all|passed|name:pattern|tag:pattern|for|wuks>` | |
> | | [Removes keyword data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) from the generated outputs. |
> | `--flattenkeywords <for|foritem|name:pattern|tag:pattern>` | |
> | | [Flattens keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) in the generated outputs. |
> | `--starttime <timestamp>` | |
> | | Sets the [starting time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution) of test execution when creating reports. |
> | `--endtime <timestamp>` | |
> | | Sets the [ending time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution) of test execution when creating reports. |
> | `--nostatusrc` | Sets the [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) to zero regardless of failures in test cases. Error codes are returned normally. |
> | `--processemptysuite` | |
> | | Processes output files even if files contain [empty test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). |
> | `--prerebotmodifier <name:args>` | |
> | | Activate [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results). |
> | `-C, --consolecolors <auto|on|ansi|off>` | |
> | | [Specifies are colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) used on the console. |
> | `--consolelinks <auto|off>` | |
> | | Controls [making paths to results files hyperlinks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links). |
> | `-P, --pythonpath <path>` | |
> | | Additional locations to add to the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). |
> | `-A, --argumentfile <path>` | |
> | | A text file to [read more arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) from. |
> | `-h, --help` | Prints [usage instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
> | `--version` | Prints the [version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
### [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-644)
ROBOT\_OPTIONS
and
REBOT\_OPTIONS
Space separated list of default options to be placed [in front of any explicit options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-options-and-rebot-options-environment-variables) on the command line.
ROBOT\_SYSLOG\_FILE
Path to a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) file where Robot Framework writes internal information about parsing test case files and running tests.
ROBOT\_SYSLOG\_LEVEL
Log level to use when writing to the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) file.
ROBOT\_INTERNAL\_TRACES
When set to any non-empty value, Robot Framework's internal methods are included in [error tracebacks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems).
## [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-633)
Robot Framework supports translating [section headers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections), [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings), [Given/When/Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) used in Behavior Driven Development (BDD) as well as [true and false strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) used in automatic Boolean argument conversion. This appendix lists all translations for all languages, excluding English, that Robot Framework supports out-of-the-box.
How to actually activate translations is explained in the [Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization) section. That section also explains how to create custom language definitions and how to contribute new translations.
- [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
### [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-645)
New in Robot Framework 7.3.
#### Section headers
| Header | Translation |
|---|---|
| Settings | الإعدادات |
| Variables | المتغيرات |
| Test Cases | وضعيات الاختبار |
| Tasks | المهام |
| Keywords | الأوامر |
| Comments | التعليقات |
#### Settings
| Setting | Translation |
|---|---|
| Library | المكتبة |
| Resource | المورد |
| Variables | المتغيرات |
| Name | الاسم |
| Documentation | التوثيق |
| Metadata | البيانات الوصفية |
| Suite Setup | إعداد المجموعة |
| Suite Teardown | تفكيك المجموعة |
| Test Setup | تهيئة الاختبار |
| Task Setup | تهيئة المهمة |
| Test Teardown | تفكيك الاختبار |
| Task Teardown | تفكيك المهمة |
| Test Template | قالب الاختبار |
| Task Template | قالب المهمة |
| Test Timeout | مهلة الاختبار |
| Task Timeout | مهلة المهمة |
| Test Tags | علامات الاختبار |
| Task Tags | علامات المهمة |
| Keyword Tags | علامات الأوامر |
| Tags | العلامات |
| Setup | إعداد |
| Teardown | تفكيك |
| Template | قالب |
| Timeout | المهلة الزمنية |
| Arguments | المعطيات |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | بافتراض |
| When | عندما, لما |
| Then | إذن, عندها |
| And | و |
| But | لكن |
#### Boolean strings
| True/False | Values |
|---|---|
| True | نعم, صحيح |
| False | لا, خطأ |
### [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-646)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Настройки |
| Variables | Променливи |
| Test Cases | Тестови случаи |
| Tasks | Задачи |
| Keywords | Ключови думи |
| Comments | Коментари |
#### Settings
| Setting | Translation |
|---|---|
| Library | Библиотека |
| Resource | Ресурс |
| Variables | Променлива |
| Name | |
| Documentation | Документация |
| Metadata | Метаданни |
| Suite Setup | Първоначални настройки на комплекта |
| Suite Teardown | Приключване на комплекта |
| Test Setup | Първоначални настройки на тестове |
| Task Setup | Първоначални настройки на задачи |
| Test Teardown | Приключване на тестове |
| Task Teardown | Приключване на задачи |
| Test Template | Шаблон за тестове |
| Task Template | Шаблон за задачи |
| Test Timeout | Таймаут за тестове |
| Task Timeout | Таймаут за задачи |
| Test Tags | Етикети за тестове |
| Task Tags | Етикети за задачи |
| Keyword Tags | Етикети за ключови думи |
| Tags | Етикети |
| Setup | Първоначални настройки |
| Teardown | Приключване |
| Template | Шаблон |
| Timeout | Таймаут |
| Arguments | Аргументи |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | В случай че |
| When | Когато |
| Then | Тогава |
| And | И |
| But | Но |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Вярно, Да, Включен |
| False | Невярно, Не, Изключен, Нищо |
### [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-647)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Postavke |
| Variables | Varijable |
| Test Cases | Test Cases |
| Tasks | Taskovi |
| Keywords | Keywords |
| Comments | Komentari |
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteka |
| Resource | Resursi |
| Variables | Varijable |
| Name | |
| Documentation | Dokumentacija |
| Metadata | Metadata |
| Suite Setup | Suite Postavke |
| Suite Teardown | Suite Teardown |
| Test Setup | Test Postavke |
| Task Setup | Task Postavke |
| Test Teardown | Test Teardown |
| Task Teardown | Task Teardown |
| Test Template | Test Template |
| Task Template | Task Template |
| Test Timeout | Test Timeout |
| Task Timeout | Task Timeout |
| Test Tags | Test Tagovi |
| Task Tags | Task Tagovi |
| Keyword Tags | Keyword Tagovi |
| Tags | Tagovi |
| Setup | Postavke |
| Teardown | Teardown |
| Template | Template |
| Timeout | Timeout |
| Arguments | Argumenti |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Uslovno |
| When | Kada |
| Then | Tada |
| And | I |
| But | Ali |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-648)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Nastavení |
| Variables | Proměnné |
| Test Cases | Testovací případy |
| Tasks | Úlohy |
| Keywords | Klíčová slova |
| Comments | Komentáře |
#### Settings
| Setting | Translation |
|---|---|
| Library | Knihovna |
| Resource | Zdroj |
| Variables | Proměnná |
| Name | Název |
| Documentation | Dokumentace |
| Metadata | Metadata |
| Suite Setup | Příprava sady |
| Suite Teardown | Ukončení sady |
| Test Setup | Příprava testu |
| Task Setup | Příprava úlohy |
| Test Teardown | Ukončení testu |
| Task Teardown | Ukončení úlohy |
| Test Template | Šablona testu |
| Task Template | Šablona úlohy |
| Test Timeout | Časový limit testu |
| Task Timeout | Časový limit úlohy |
| Test Tags | Štítky testů |
| Task Tags | Štítky úloh |
| Keyword Tags | Štítky klíčových slov |
| Tags | Štítky |
| Setup | Příprava |
| Teardown | Ukončení |
| Template | Šablona |
| Timeout | Časový limit |
| Arguments | Argumenty |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Pokud |
| When | Když |
| Then | Pak |
| And | A |
| But | Ale |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Pravda, Ano, Zapnuto |
| False | Nepravda, Ne, Vypnuto, Nic |
### [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-649)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Einstellungen |
| Variables | Variablen |
| Test Cases | Testfälle |
| Tasks | Aufgaben |
| Keywords | Schlüsselwörter |
| Comments | Kommentare |
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliothek |
| Resource | Ressource |
| Variables | Variablen |
| Name | Name |
| Documentation | Dokumentation |
| Metadata | Metadaten |
| Suite Setup | Suitevorbereitung |
| Suite Teardown | Suitenachbereitung |
| Test Setup | Testvorbereitung |
| Task Setup | Aufgabenvorbereitung |
| Test Teardown | Testnachbereitung |
| Task Teardown | Aufgabennachbereitung |
| Test Template | Testvorlage |
| Task Template | Aufgabenvorlage |
| Test Timeout | Testzeitlimit |
| Task Timeout | Aufgabenzeitlimit |
| Test Tags | Testmarker |
| Task Tags | Aufgabenmarker |
| Keyword Tags | Schlüsselwortmarker |
| Tags | Marker |
| Setup | Vorbereitung |
| Teardown | Nachbereitung |
| Template | Vorlage |
| Timeout | Zeitlimit |
| Arguments | Argumente |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Angenommen |
| When | Wenn |
| Then | Dann |
| And | Und |
| But | Aber |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Wahr, Ja, An, Ein |
| False | Falsch, Nein, Aus, Unwahr |
### [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-650)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Configuraciones |
| Variables | Variables |
| Test Cases | Casos de prueba |
| Tasks | Tareas |
| Keywords | Palabras clave |
| Comments | Comentarios |
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recursos |
| Variables | Variable |
| Name | Nombre |
| Documentation | Documentación |
| Metadata | Metadatos |
| Suite Setup | Configuración de la Suite |
| Suite Teardown | Desmontaje de la Suite |
| Test Setup | Configuración de prueba |
| Task Setup | Configuración de tarea |
| Test Teardown | Desmontaje de la prueba |
| Task Teardown | Desmontaje de tareas |
| Test Template | Plantilla de prueba |
| Task Template | Plantilla de tareas |
| Test Timeout | Tiempo de espera de la prueba |
| Task Timeout | Tiempo de espera de las tareas |
| Test Tags | Etiquetas de la prueba |
| Task Tags | Etiquetas de las tareas |
| Keyword Tags | Etiquetas de palabras clave |
| Tags | Etiquetas |
| Setup | Configuración |
| Teardown | Desmontaje |
| Template | Plantilla |
| Timeout | Tiempo agotado |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Cuando |
| Then | Entonces |
| And | Y |
| But | Pero |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadero, Si, On |
| False | Falso, No, Off, Ninguno |
### [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-651)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Asetukset |
| Variables | Muuttujat |
| Test Cases | Testit |
| Tasks | Tehtävät |
| Keywords | Avainsanat |
| Comments | Kommentit |
#### Settings
| Setting | Translation |
|---|---|
| Library | Kirjasto |
| Resource | Resurssi |
| Variables | Muuttujat |
| Name | Nimi |
| Documentation | Dokumentaatio |
| Metadata | Metatiedot |
| Suite Setup | Setin Alustus |
| Suite Teardown | Setin Alasajo |
| Test Setup | Testin Alustus |
| Task Setup | Tehtävän Alustus |
| Test Teardown | Testin Alasajo |
| Task Teardown | Tehtävän Alasajo |
| Test Template | Testin Malli |
| Task Template | Tehtävän Malli |
| Test Timeout | Testin Aikaraja |
| Task Timeout | Tehtävän Aikaraja |
| Test Tags | Testin Tagit |
| Task Tags | Tehtävän Tagit |
| Keyword Tags | Avainsanan Tagit |
| Tags | Tagit |
| Setup | Alustus |
| Teardown | Alasajo |
| Template | Malli |
| Timeout | Aikaraja |
| Arguments | Argumentit |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Oletetaan |
| When | Kun |
| Then | Niin |
| And | Ja |
| But | Mutta |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Tosi, Kyllä, Päällä |
| False | Epätosi, Ei, Pois |
### [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-652)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Paramètres |
| Variables | Variables |
| Test Cases | Unités de test |
| Tasks | Tâches |
| Keywords | Mots-clés |
| Comments | Commentaires |
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliothèque |
| Resource | Ressource |
| Variables | Variable |
| Name | Nom |
| Documentation | Documentation |
| Metadata | Méta-donnée |
| Suite Setup | Mise en place de suite |
| Suite Teardown | Démontage de suite |
| Test Setup | Mise en place de test |
| Task Setup | Mise en place de tâche |
| Test Teardown | Démontage de test |
| Task Teardown | Démontage de test |
| Test Template | Modèle de test |
| Task Template | Modèle de tâche |
| Test Timeout | Délai de test |
| Task Timeout | Délai de tâche |
| Test Tags | Étiquette de test |
| Task Tags | Étiquette de tâche |
| Keyword Tags | Etiquette de mot-clé |
| Tags | Étiquette |
| Setup | Mise en place |
| Teardown | Démontage |
| Template | Modèle |
| Timeout | Délai d'attente |
| Arguments | Arguments |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Étant donné, Étant donné que, Étant donné qu', Soit, Sachant que, Sachant qu', Sachant, Etant donné, Etant donné que, Etant donné qu', Etant donnée, Etant données |
| When | Lorsque, Quand, Lorsqu' |
| Then | Alors, Donc |
| And | Et, Et que, Et qu' |
| But | Mais, Mais que, Mais qu' |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Vrai, Oui, Actif |
| False | Faux, Non, Désactivé, Aucun |
### [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-653)
#### Section headers
| Header | Translation |
|---|---|
| Settings | स्थापना |
| Variables | चर |
| Test Cases | नियत कार्य प्रवेशिका |
| Tasks | कार्य प्रवेशिका |
| Keywords | कुंजीशब्द |
| Comments | टिप्पणी |
#### Settings
| Setting | Translation |
|---|---|
| Library | कोड़ प्रतिबिंब संग्रह |
| Resource | संसाधन |
| Variables | चर |
| Name | |
| Documentation | प्रलेखन |
| Metadata | अधि-आंकड़ा |
| Suite Setup | जांच की शुरुवात |
| Suite Teardown | परीक्षण कार्य अंत |
| Test Setup | परीक्षण कार्य प्रारंभ |
| Task Setup | परीक्षण कार्य प्रारंभ |
| Test Teardown | परीक्षण कार्य अंत |
| Task Teardown | परीक्षण कार्य अंत |
| Test Template | परीक्षण ढांचा |
| Task Template | परीक्षण ढांचा |
| Test Timeout | परीक्षण कार्य समय समाप्त |
| Task Timeout | कार्य समयबाह्य |
| Test Tags | जाँचका उपनाम |
| Task Tags | कार्यका उपनाम |
| Keyword Tags | कुंजीशब्द का उपनाम |
| Tags | निशान |
| Setup | व्यवस्थापना |
| Teardown | विमोचन |
| Template | साँचा |
| Timeout | समय समाप्त |
| Arguments | प्राचल |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | दिया हुआ |
| When | जब |
| Then | तब |
| And | और |
| But | परंतु |
#### Boolean strings
| True/False | Values |
|---|---|
| True | यथार्थ, निश्चित, हां, पर |
| False | गलत, नहीं, हालाँकि, यद्यपि, नहीं, हैं |
### [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-654)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Impostazioni |
| Variables | Variabili |
| Test Cases | Casi Di Test |
| Tasks | Attività |
| Keywords | Parole Chiave |
| Comments | Commenti |
#### Settings
| Setting | Translation |
|---|---|
| Library | Libreria |
| Resource | Risorsa |
| Variables | Variabile |
| Name | Nome |
| Documentation | Documentazione |
| Metadata | Metadati |
| Suite Setup | Configurazione Suite |
| Suite Teardown | Distruzione Suite |
| Test Setup | Configurazione Test |
| Task Setup | Configurazione Attività |
| Test Teardown | Distruzione Test |
| Task Teardown | Distruzione Attività |
| Test Template | Modello Test |
| Task Template | Modello Attività |
| Test Timeout | Timeout Test |
| Task Timeout | Timeout Attività |
| Test Tags | Tag Del Test |
| Task Tags | Tag Attività |
| Keyword Tags | Tag Parola Chiave |
| Tags | Tag |
| Setup | Configurazione |
| Teardown | Distruzione |
| Template | Template |
| Timeout | Timeout |
| Arguments | Parametri |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dato |
| When | Quando |
| Then | Allora |
| And | E |
| But | Ma |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Vero, Sì, On |
| False | Falso, No, Off, Nessuno |
### [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-655)
New in Robot Framework 7.0.1.
#### Section headers
| Header | Translation |
|---|---|
| Settings | 設定 |
| Variables | 変数 |
| Test Cases | テスト ケース |
| Tasks | タスク |
| Keywords | キーワード |
| Comments | コメント |
#### Settings
| Setting | Translation |
|---|---|
| Library | ライブラリ |
| Resource | リソース |
| Variables | 変数 |
| Name | 名前 |
| Documentation | ドキュメント |
| Metadata | メタデータ |
| Suite Setup | スイート セットアップ |
| Suite Teardown | スイート ティアダウン |
| Test Setup | テスト セットアップ |
| Task Setup | タスク セットアップ |
| Test Teardown | テスト ティアダウン |
| Task Teardown | タスク ティアダウン |
| Test Template | テスト テンプレート |
| Task Template | タスク テンプレート |
| Test Timeout | テスト タイムアウト |
| Task Timeout | タスク タイムアウト |
| Test Tags | テスト タグ |
| Task Tags | タスク タグ |
| Keyword Tags | キーワード タグ |
| Tags | タグ |
| Setup | セットアップ |
| Teardown | ティアダウン |
| Template | テンプレート |
| Timeout | タイムアウト |
| Arguments | 引数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 仮定, 指定, 前提条件 |
| When | 条件, 次の場合, もし, 実行条件 |
| Then | アクション, その時, 動作 |
| And | および, 及び, かつ, 且つ, ならびに, 並びに, そして, それから |
| But | ただし, 但し |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 有効, はい, オン |
| False | 偽, 無効, いいえ, オフ |
### [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-656)
New in Robot Framework 7.1.
#### Section headers
| Header | Translation |
|---|---|
| Settings | 설정 |
| Variables | 변수 |
| Test Cases | 테스트 사례 |
| Tasks | 작업 |
| Keywords | 키워드 |
| Comments | 의견 |
#### Settings
| Setting | Translation |
|---|---|
| Library | 라이브러리 |
| Resource | 자료 |
| Variables | 변수 |
| Name | 이름 |
| Documentation | 문서 |
| Metadata | 메타데이터 |
| Suite Setup | 스위트 설정 |
| Suite Teardown | 스위트 중단 |
| Test Setup | 테스트 설정 |
| Task Setup | 작업 설정 |
| Test Teardown | 테스트 중단 |
| Task Teardown | 작업 중단 |
| Test Template | 테스트 템플릿 |
| Task Template | 작업 템플릿 |
| Test Timeout | 테스트 시간 초과 |
| Task Timeout | 작업 시간 초과 |
| Test Tags | 테스트 태그 |
| Task Tags | 작업 태그 |
| Keyword Tags | 키워드 태그 |
| Tags | 태그 |
| Setup | 설정 |
| Teardown | 중단 |
| Template | 템플릿 |
| Timeout | 시간 초과 |
| Arguments | 주장 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 주어진 |
| When | 때 |
| Then | 보다 |
| And | 그리고 |
| But | 하지만 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 참, 네, 켜기 |
| False | 거짓, 아니오, 끄기 |
### [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-657)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Instellingen |
| Variables | Variabelen |
| Test Cases | Testgevallen |
| Tasks | Taken |
| Keywords | Actiewoorden |
| Comments | Opmerkingen |
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliotheek |
| Resource | Resource |
| Variables | Variabele |
| Name | Naam |
| Documentation | Documentatie |
| Metadata | Metadata |
| Suite Setup | Suitevoorbereiding |
| Suite Teardown | Suite-afronding |
| Test Setup | Testvoorbereiding |
| Task Setup | Taakvoorbereiding |
| Test Teardown | Testafronding |
| Task Teardown | Taakafronding |
| Test Template | Testsjabloon |
| Task Template | Taaksjabloon |
| Test Timeout | Testtijdslimiet |
| Task Timeout | Taaktijdslimiet |
| Test Tags | Testlabels |
| Task Tags | Taaklabels |
| Keyword Tags | Actiewoordlabels |
| Tags | Labels |
| Setup | Voorbereiding |
| Teardown | Afronding |
| Template | Sjabloon |
| Timeout | Tijdslimiet |
| Arguments | Parameters |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Stel, Gegeven |
| When | Als |
| Then | Dan |
| And | En |
| But | Maar |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Waar, Ja, Aan |
| False | Onwaar, Nee, Uit, Geen |
### [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-658)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Ustawienia |
| Variables | Zmienne |
| Test Cases | Przypadki Testowe |
| Tasks | Zadania |
| Keywords | Słowa Kluczowe |
| Comments | Komentarze |
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteka |
| Resource | Zasób |
| Variables | Zmienne |
| Name | Nazwa |
| Documentation | Dokumentacja |
| Metadata | Metadane |
| Suite Setup | Inicjalizacja Zestawu |
| Suite Teardown | Ukończenie Zestawu |
| Test Setup | Inicjalizacja Testu |
| Task Setup | Inicjalizacja Zadania |
| Test Teardown | Ukończenie Testu |
| Task Teardown | Ukończenie Zadania |
| Test Template | Szablon Testu |
| Task Template | Szablon Zadania |
| Test Timeout | Limit Czasowy Testu |
| Task Timeout | Limit Czasowy Zadania |
| Test Tags | Znaczniki Testu |
| Task Tags | Znaczniki Zadania |
| Keyword Tags | Znaczniki Słowa Kluczowego |
| Tags | Znaczniki |
| Setup | Inicjalizacja |
| Teardown | Ukończenie |
| Template | Szablon |
| Timeout | Limit Czasowy |
| Arguments | Argumenty |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Zakładając, Zakładając, że, Mając |
| When | Jeżeli, Jeśli, Gdy, Kiedy |
| Then | Wtedy |
| And | Oraz, I |
| But | Ale |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Prawda, Tak, Włączone |
| False | Fałsz, Nie, Wyłączone, Nic |
### [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-659)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Definições |
| Variables | Variáveis |
| Test Cases | Casos de Teste |
| Tasks | Tarefas |
| Keywords | Palavras-Chave |
| Comments | Comentários |
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recurso |
| Variables | Variável |
| Name | Nome |
| Documentation | Documentação |
| Metadata | Metadados |
| Suite Setup | Inicialização de Suíte |
| Suite Teardown | Finalização de Suíte |
| Test Setup | Inicialização de Teste |
| Task Setup | Inicialização de Tarefa |
| Test Teardown | Finalização de Teste |
| Task Teardown | Finalização de Tarefa |
| Test Template | Modelo de Teste |
| Task Template | Modelo de Tarefa |
| Test Timeout | Tempo Limite de Teste |
| Task Timeout | Tempo Limite de Tarefa |
| Test Tags | Etiquetas de Testes |
| Task Tags | Etiquetas de Tarefas |
| Keyword Tags | Etiquetas de Palavras-Chave |
| Tags | Etiquetas |
| Setup | Inicialização |
| Teardown | Finalização |
| Template | Modelo |
| Timeout | Tempo Limite |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Quando |
| Then | Então |
| And | E |
| But | Mas |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadeiro, Verdade, Sim, Ligado |
| False | Falso, Não, Desligado, Desativado, Nada |
### [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-660)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Configurações |
| Variables | Variáveis |
| Test Cases | Casos de Teste |
| Tasks | Tarefas |
| Keywords | Palavras-Chave |
| Comments | Comentários |
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recurso |
| Variables | Variável |
| Name | Nome |
| Documentation | Documentação |
| Metadata | Metadados |
| Suite Setup | Configuração da Suíte |
| Suite Teardown | Finalização de Suíte |
| Test Setup | Inicialização de Teste |
| Task Setup | Inicialização de Tarefa |
| Test Teardown | Finalização de Teste |
| Task Teardown | Finalização de Tarefa |
| Test Template | Modelo de Teste |
| Task Template | Modelo de Tarefa |
| Test Timeout | Tempo Limite de Teste |
| Task Timeout | Tempo Limite de Tarefa |
| Test Tags | Test Tags |
| Task Tags | Task Tags |
| Keyword Tags | Keyword Tags |
| Tags | Etiquetas |
| Setup | Inicialização |
| Teardown | Finalização |
| Template | Modelo |
| Timeout | Tempo Limite |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Quando |
| Then | Então |
| And | E |
| But | Mas |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadeiro, Verdade, Sim, Ligado |
| False | Falso, Não, Desligado, Desativado, Nada |
### [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-661)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Setari |
| Variables | Variabile |
| Test Cases | Cazuri De Test |
| Tasks | Sarcini |
| Keywords | Cuvinte Cheie |
| Comments | Comentarii |
#### Settings
| Setting | Translation |
|---|---|
| Library | Librarie |
| Resource | Resursa |
| Variables | Variabila |
| Name | Nume |
| Documentation | Documentatie |
| Metadata | Metadate |
| Suite Setup | Configurare De Suita |
| Suite Teardown | Configurare De Intrerupere |
| Test Setup | Setare De Test |
| Task Setup | Configuarare activitate |
| Test Teardown | Inrerupere De Test |
| Task Teardown | Intrerupere activitate |
| Test Template | Sablon De Test |
| Task Template | Sablon de activitate |
| Test Timeout | Timp Expirare Test |
| Task Timeout | Timp de expirare activitate |
| Test Tags | Taguri De Test |
| Task Tags | Etichete activitate |
| Keyword Tags | Etichete metode |
| Tags | Etichete |
| Setup | Setare |
| Teardown | Intrerupere |
| Template | Sablon |
| Timeout | Expirare |
| Arguments | Argumente |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Fie ca |
| When | Cand |
| Then | Atunci |
| And | Si |
| But | Dar |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Adevarat, Da, Cand |
| False | Fals, Nu, Oprit, Niciun |
### [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-662)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Настройки |
| Variables | Переменные |
| Test Cases | Заголовки тестов |
| Tasks | Задача |
| Keywords | Ключевые слова |
| Comments | Комментарии |
#### Settings
| Setting | Translation |
|---|---|
| Library | Библиотека |
| Resource | Ресурс |
| Variables | Переменные |
| Name | |
| Documentation | Документация |
| Metadata | Метаданные |
| Suite Setup | Инициализация комплекта тестов |
| Suite Teardown | Завершение комплекта тестов |
| Test Setup | Инициализация теста |
| Task Setup | Инициализация задания |
| Test Teardown | Завершение теста |
| Task Teardown | Завершение задания |
| Test Template | Шаблон теста |
| Task Template | Шаблон задания |
| Test Timeout | Лимит выполнения теста |
| Task Timeout | Лимит задания |
| Test Tags | Теги тестов |
| Task Tags | Метки заданий |
| Keyword Tags | Метки ключевых слов |
| Tags | Метки |
| Setup | Инициализация |
| Teardown | Завершение |
| Template | Шаблон |
| Timeout | Лимит |
| Arguments | Аргументы |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Дано |
| When | Когда |
| Then | Тогда |
| And | И |
| But | Но |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-663)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Inställningar |
| Variables | Variabler |
| Test Cases | Testfall |
| Tasks | Taskar |
| Keywords | Nyckelord |
| Comments | Kommentarer |
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliotek |
| Resource | Resurs |
| Variables | Variabel |
| Name | Namn |
| Documentation | Dokumentation |
| Metadata | Metadata |
| Suite Setup | Svit konfigurering |
| Suite Teardown | Svit nedrivning |
| Test Setup | Test konfigurering |
| Task Setup | Task konfigurering |
| Test Teardown | Test nedrivning |
| Task Teardown | Task nedrivning |
| Test Template | Test mall |
| Task Template | Task mall |
| Test Timeout | Test timeout |
| Task Timeout | Task timeout |
| Test Tags | Test taggar |
| Task Tags | Arbetsuppgift taggar |
| Keyword Tags | Nyckelord taggar |
| Tags | Taggar |
| Setup | Konfigurering |
| Teardown | Nedrivning |
| Template | Mall |
| Timeout | Timeout |
| Arguments | Argument |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Givet |
| When | När |
| Then | Då |
| And | Och |
| But | Men |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Sant, Ja, På |
| False | Falskt, Nej, Av, Ingen |
### [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-664)
#### Section headers
| Header | Translation |
|---|---|
| Settings | การตั้งค่า |
| Variables | กำหนดตัวแปร |
| Test Cases | การทดสอบ |
| Tasks | งาน |
| Keywords | คำสั่งเพิ่มเติม |
| Comments | คำอธิบาย |
#### Settings
| Setting | Translation |
|---|---|
| Library | ชุดคำสั่งที่ใช้ |
| Resource | ไฟล์ที่ใช้ |
| Variables | ชุดตัวแปร |
| Name | |
| Documentation | เอกสาร |
| Metadata | รายละเอียดเพิ่มเติม |
| Suite Setup | กำหนดค่าเริ่มต้นของชุดการทดสอบ |
| Suite Teardown | คืนค่าของชุดการทดสอบ |
| Test Setup | กำหนดค่าเริ่มต้นของการทดสอบ |
| Task Setup | กำหนดค่าเริ่มต้นของงาน |
| Test Teardown | คืนค่าของการทดสอบ |
| Task Teardown | คืนค่าของงาน |
| Test Template | โครงสร้างของการทดสอบ |
| Task Template | โครงสร้างของงาน |
| Test Timeout | เวลารอของการทดสอบ |
| Task Timeout | เวลารอของงาน |
| Test Tags | กลุ่มของการทดสอบ |
| Task Tags | กลุ่มของงาน |
| Keyword Tags | กลุ่มของคำสั่งเพิ่มเติม |
| Tags | กลุ่ม |
| Setup | กำหนดค่าเริ่มต้น |
| Teardown | คืนค่า |
| Template | โครงสร้าง |
| Timeout | หมดเวลา |
| Arguments | ค่าที่ส่งเข้ามา |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | กำหนดให้ |
| When | เมื่อ |
| Then | ดังนั้น |
| And | และ |
| But | แต่ |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-665)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Ayarlar |
| Variables | Değişkenler |
| Test Cases | Test Durumları |
| Tasks | Görevler |
| Keywords | Anahtar Kelimeler |
| Comments | Yorumlar |
#### Settings
| Setting | Translation |
|---|---|
| Library | Kütüphane |
| Resource | Kaynak |
| Variables | Değişkenler |
| Name | |
| Documentation | Dokümantasyon |
| Metadata | Üstveri |
| Suite Setup | Takım Kurulumu |
| Suite Teardown | Takım Bitişi |
| Test Setup | Test Kurulumu |
| Task Setup | Görev Kurulumu |
| Test Teardown | Test Bitişi |
| Task Teardown | Görev Bitişi |
| Test Template | Test Taslağı |
| Task Template | Görev Taslağı |
| Test Timeout | Test Zaman Aşımı |
| Task Timeout | Görev Zaman Aşımı |
| Test Tags | Test Etiketleri |
| Task Tags | Görev Etiketleri |
| Keyword Tags | Anahtar Kelime Etiketleri |
| Tags | Etiketler |
| Setup | Kurulum |
| Teardown | Bitiş |
| Template | Taslak |
| Timeout | Zaman Aşımı |
| Arguments | Argümanlar |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Diyelim ki |
| When | Eğer ki |
| Then | O zaman |
| And | Ve |
| But | Ancak |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Doğru, Evet, Açik |
| False | Yanliş, Hayir, Kapali |
### [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-666)
#### Section headers
| Header | Translation |
|---|---|
| Settings | Налаштування |
| Variables | Змінні |
| Test Cases | Тест-кейси |
| Tasks | Завдань |
| Keywords | Ключових слова |
| Comments | Коментарів |
#### Settings
| Setting | Translation |
|---|---|
| Library | Бібліотека |
| Resource | Ресурс |
| Variables | Змінна |
| Name | |
| Documentation | Документація |
| Metadata | Метадані |
| Suite Setup | Налаштування Suite |
| Suite Teardown | Розбірка Suite |
| Test Setup | Налаштування тесту |
| Task Setup | Налаштування завдання |
| Test Teardown | Розбирання тестy |
| Task Teardown | Розбір завдання |
| Test Template | Тестовий шаблон |
| Task Template | Шаблон завдання |
| Test Timeout | Час тестування |
| Task Timeout | Час очікування завдання |
| Test Tags | Тестові теги |
| Task Tags | Теги завдань |
| Keyword Tags | Теги ключових слів |
| Tags | Теги |
| Setup | Встановлення |
| Teardown | Cпростовувати пункт за пунктом |
| Template | Шаблон |
| Timeout | Час вийшов |
| Arguments | Аргументи |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Дано |
| When | Коли |
| Then | Тоді |
| And | Та |
| But | Але |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-667)
New in Robot Framework 6.1.
#### Section headers
| Header | Translation |
|---|---|
| Settings | Cài Đặt |
| Variables | Các biến số |
| Test Cases | Các kịch bản kiểm thử |
| Tasks | Các nghiệm vụ |
| Keywords | Các từ khóa |
| Comments | Các chú thích |
#### Settings
| Setting | Translation |
|---|---|
| Library | Thư viện |
| Resource | Tài nguyên |
| Variables | Biến số |
| Name | Tên |
| Documentation | Tài liệu hướng dẫn |
| Metadata | Dữ liệu tham chiếu |
| Suite Setup | Tiền thiết lập bộ kịch bản kiểm thử |
| Suite Teardown | Hậu thiết lập bộ kịch bản kiểm thử |
| Test Setup | Tiền thiết lập kịch bản kiểm thử |
| Task Setup | Tiền thiểt lập nhiệm vụ |
| Test Teardown | Hậu thiết lập kịch bản kiểm thử |
| Task Teardown | Hậu thiết lập nhiệm vụ |
| Test Template | Mẫu kịch bản kiểm thử |
| Task Template | Mẫu nhiễm vụ |
| Test Timeout | Thời gian chờ kịch bản kiểm thử |
| Task Timeout | Thời gian chờ nhiệm vụ |
| Test Tags | Các nhãn kịch bản kiểm thử |
| Task Tags | Các nhãn nhiệm vụ |
| Keyword Tags | Các từ khóa nhãn |
| Tags | Các thẻ |
| Setup | Tiền thiết lập |
| Teardown | Hậu thiết lập |
| Template | Mẫu |
| Timeout | Thời gian chờ |
| Arguments | Các đối số |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Đã cho |
| When | Khi |
| Then | Thì |
| And | Và |
| But | Nhưng |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Đúng, Vâng, Mở |
| False | Sai, Không, Tắt, Không Có Gì |
### [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-668)
#### Section headers
| Header | Translation |
|---|---|
| Settings | 设置 |
| Variables | 变量 |
| Test Cases | 用例 |
| Tasks | 任务 |
| Keywords | 关键字 |
| Comments | 备注 |
#### Settings
| Setting | Translation |
|---|---|
| Library | 程序库 |
| Resource | 资源文件 |
| Variables | 变量文件 |
| Name | |
| Documentation | 说明 |
| Metadata | 元数据 |
| Suite Setup | 用例集启程 |
| Suite Teardown | 用例集终程 |
| Test Setup | 用例启程 |
| Task Setup | 任务启程 |
| Test Teardown | 用例终程 |
| Task Teardown | 任务终程 |
| Test Template | 用例模板 |
| Task Template | 任务模板 |
| Test Timeout | 用例超时 |
| Task Timeout | 任务超时 |
| Test Tags | 用例标签 |
| Task Tags | 任务标签 |
| Keyword Tags | 关键字标签 |
| Tags | 标签 |
| Setup | 启程 |
| Teardown | 终程 |
| Template | 模板 |
| Timeout | 超时 |
| Arguments | 参数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 假定 |
| When | 当 |
| Then | 那么 |
| And | 并且 |
| But | 但是 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 是, 开 |
| False | 假, 否, 关, 空 |
### [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-669)
#### Section headers
| Header | Translation |
|---|---|
| Settings | 設置 |
| Variables | 變量 |
| Test Cases | 案例 |
| Tasks | 任務 |
| Keywords | 關鍵字 |
| Comments | 備註 |
#### Settings
| Setting | Translation |
|---|---|
| Library | 函式庫 |
| Resource | 資源文件 |
| Variables | 變量文件 |
| Name | |
| Documentation | 說明 |
| Metadata | 元數據 |
| Suite Setup | 測試套啟程 |
| Suite Teardown | 測試套終程 |
| Test Setup | 測試啟程 |
| Task Setup | 任務啟程 |
| Test Teardown | 測試終程 |
| Task Teardown | 任務終程 |
| Test Template | 測試模板 |
| Task Template | 任務模板 |
| Test Timeout | 測試逾時 |
| Task Timeout | 任務逾時 |
| Test Tags | 測試標籤 |
| Task Tags | 任務標籤 |
| Keyword Tags | 關鍵字標籤 |
| Tags | 標籤 |
| Setup | 啟程 |
| Teardown | 終程 |
| Template | 模板 |
| Timeout | 逾時 |
| Arguments | 参数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 假定 |
| When | 當 |
| Then | 那麼 |
| And | 並且 |
| But | 但是 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 是, 開 |
| False | 假, 否, 關, 空 |
## [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-634)
It is possible to use simple HTML formatting with [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation), [test case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation) and [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation) documentation and [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) in the test data, as well as when [documenting test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-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.
- [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-whitespace-in-test-data)
- [Newlines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines)
- [Spaces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spaces)
- [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs)
- [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles)
- [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls)
- [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-links-and-images)
- [Link with text content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#link-with-text-content)
- [Link with image content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#link-with-image-content)
- [Image with title text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#image-with-title-text)
- [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles)
- [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tables)
- [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists)
- [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text)
- [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#horizontal-ruler)
### [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-670)
#### [Newlines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-671)
When documenting test suites, test cases and user keywords or adding metadata to test suites, newlines can be added manually using `\n` [escape sequence](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escape-sequence).
```
*** Settings ***
Documentation First line.\n\nSecond paragraph. This time\nwith multiple lines.
Metadata Example list - first item\n- second item\n- third
```
Note
As explained in the [Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs) section below, the single newline in `Second paragraph, this time\nwith multiple lines.` does not actually affect how that paragraph is rendered. Newlines are needed when creating [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists) or other such constructs, though.
Adding newlines manually to a long documentation takes some effort and extra characters also make the documentation harder to read. This can be avoided, though, as newlines are inserted automatically between [continued documentation and metadata lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows). In practice this means that the above example could be written also as follows.
```
*** Settings ***
Documentation
... First line.
...
... Second paragraph. This time
... with multiple lines.
Metadata
... Example list
... - first item
... - second item
... - third
```
No automatic newline is added if a line already ends with a literal newline or if it ends with an [escaping backslash](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping):
```
*** Test Cases ***
Ends with newline
[Documentation] Ends with a newline and\n
... automatic newline is not added.
Ends with backslash
[Documentation] Ends with a backslash and \
... no newline is added.
```
#### [Spaces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-672)
Unlike elsewhere in Robot Framework data, leading spaces and consecutive internal spaces are preserved in documentation and metadata. This makes it possible, for example, to split [list items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists) to multiple rows and have [preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text) with spaces:
```
*** Test Cases ***
Long list item
[Documentation]
... List:
... - Short item.
... - Second item is pretty long and it is split to
... multiple rows. Leading spaces are preserved.
... - Another short item.
Preformatted text
[Documentation]
... Example with consecutive internal spaces:
...
... | *** Test Cases ***
... | Example
... | Keyword
```
Note
Preserving spaces in documentation and metadata is new in Robot Framework 6.1. With earlier versions spaces need to be escaped with a backslash.
### [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-673)
All regular text in the formatted HTML documentation is represented as paragraphs. In practice, lines separated by a single newline will be combined in a paragraph regardless whether the newline is added manually or automatically. Multiple paragraphs can be separated with an empty line (i.e. two newlines) and also tables, lists, and other specially formatted blocks discussed in subsequent sections end a paragraph.
For example, the following test suite or resource file documentation:
```
*** Settings ***
Documentation
... First paragraph has only one line.
...
... Second paragraph, this time created
... with multiple lines.
```
will be formatted in HTML as:
First paragraph has only one line.
Second paragraph, this time created with multiple lines.
### [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-674)
The documentation syntax supports inline styles **bold**, *italic* and `code`. 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*_`.
The code style is created using double backticks like \``code\``. The result is monospaced text with light gray background.
Asterisks, underscores or double backticks alone, or in the middle of a word, do not start formatting, but punctuation characters before or after them are allowed. When multiple lines form a [paragraph](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs), all inline styles can span over multiple lines.
| Unformatted | Formatted |
|---|---|
| \*bold\* | **bold** |
| \_italic\_ | *italic* |
| \_\*bold italic\*\_ | ***bold italic*** |
| \``code\`` | `code` |
| \*bold\*, then \_italic\_ and finally \``some code\`` | **bold**, then *italic* and finally `some code` |
| This is \*bold\\n on multiple\\n lines\*. | This is **bold** **on multiple** **lines**. |
### [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-675)
All strings that look like URLs are automatically converted into clickable links. Additionally, URLs that end with extension .jpg, .jpeg, .png, .gif, .bmp or .svg (case-insensitive) will automatically create images. For example, URLs like `http://example.com` are turned into links, and `http:///host/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, and for test suite metadata.
Note
.svg image support is new in Robot Framework 3.2.
### [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-676)
It is possible to create custom links and embed images using special syntax `[link|content]`. This creates a link or image depending are `link` and `content` images. They are considered images if they have the same image extensions that are special with [URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls) or start with `data:image/`. The surrounding square brackets and the pipe character between the parts are mandatory in all cases.
Note
Support for the `data:image/` prefix is new in Robot Framework 3.2.
#### [Link with text content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-677)
If neither `link` nor `content` is an image, the end result is a normal link where `link` is the link target and `content` the visible text:
```
[file.html|this file] -> <a href="file.html">this file</a>
[http://host|that host] -> <a href="http://host">that host</a>
```
#### [Link with image content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-678)
If `content` is an image, you get a link where the link content is an image. Link target is created by `link` and it can be either text or image:
```
[robot.html|robot.png] -> <a href="robot.html"><img src="robot.png"></a>
[robot.html|data:image/png;base64,oooxxx=] -> <a href="robot.html"><img src="data:image/png;base64,oooxxx="></a>
[image.jpg|thumb.jpg] -> <a href="image.jpg"><img src="thumb.jpg"></a>
```
#### [Image with title text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-679)
If `link` is an image but `content` is not, the syntax creates an image where the `content` is the title text shown when mouse is over the image:
```
[robot.jpeg|Robot rocks!] -> <img src="robot.jpeg" title="Robot rocks!">
[data:image/png;base64,oooxxx=|Robot rocks!] -> <img src="data:image/png;base64,oooxxx=" title="Robot rocks!">
```
### [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-680)
If documentation gets longer, it is often a good idea to split it into sections. It is possible to separate sections with titles using syntax `= My Title =`, where the number of equal signs denotes the level of the title:
```
= First section =
== Subsection ==
Some text.
== Second subsection ==
More text.
= Second section =
You probably got the idea.
```
Notice that only three title levels are supported and that spaces between equal signs and the title text are mandatory.
### [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-681)
Tables are created using pipe characters with spaces around them as column separators and newlines as row separators. Header cells can be created by surrounding the cell content with equal signs and optional spaces like `= Header =` or `=Header=`. Tables cells can also contain links and formatting such as bold and italic:
```
| =A= | =B= | = C = |
| _1_ | Hello | world! |
| _2_ | Hi |
```
The created table always has a thin border and normal text is left-aligned. Text in header cells is bold and centered. Empty cells are automatically added to make rows equally long. For example, the above example would be formatted like this in HTML:
| A | B | C |
|---|---|---|
| *1* | Hello | world |
| *2* | Hi | |
### [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-682)
Lists are created by starting a line with a hyphen and space ('- '). List items can be split into multiple lines by indenting continuing lines with one or more spaces. A line that does not start with '- ' and is not indented ends the list:
```
Example:
- a list item
- second list item
is continued
This is outside the list.
```
The above documentation is formatted like this in HTML:
Example:
- a list item
- second list item is continued
This is outside the list.
### [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-683)
It is possible to embed blocks of preformatted text in the documentation. Preformatted block is created by starting lines with '\| ', one space being mandatory after the pipe character except on otherwise empty lines. The starting '\| ' sequence will be removed from the resulting HTML, but all other whitespace is preserved.
In the following documentation, the two middle lines form a preformatted block when converted to HTML:
```
Doc before block:
| inside block
| some additional whitespace
After block.
```
The above documentation is formatted like this:
Doc before block:
```
inside block
some additional whitespace
```
After block.
### [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-684)
Horizontal rulers (the `<hr>` tag) make it possible to separate larger sections from each others, and they can be created by having three or more hyphens alone on a line:
```
Some text here.
---
More text...
```
The above documentation is formatted like this:
Some text here.
***
More text...
## [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-635)
Robot Framework has its own time format that is both flexible to use and easy to understand. It is used by several keywords (for example, [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Sleep and Wait Until Keyword Succeeds), [DateTime](https://robotframework.org/robotframework/latest/libraries/DateTime.html) library, and [timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts).
- [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number)
- [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string)
- [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string)
### [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-685)
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.
Note
In some contexts plain numbers can be interpreted otherwise as times. For example, with [WHILE loop limit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-while-loop-iterations) integers denote the maximum iteration count.
### [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-686)
Representing the time as a time string 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 it is possible to add `-` prefix to specify negative times. The available time specifiers are:
- weeks, week, w
- days, day, d
- hours, hour, h
- minutes, minute, mins, min, m
- seconds, second, secs, sec, s
- milliseconds, millisecond, millis, ms
- microseconds, microsecond, us, μs
- nanoseconds, nanosecond, ns
Examples:
```
1 min 30 secs
1.5 minutes
90 s
1 day 2 hours 3 minutes 4 seconds 5 milliseconds 6 microseconds 7 nanoseconds
8 weeks 7 days 6 hours 5 minutes 4 seconds 3 milliseconds 2 microseconds 1 nanosecond
1d 2h 3m 4s 5ms 6μs 7 ns
8w 7d 6h 5m 4s 3ms 2μs 1ns
- 10 seconds
```
Note
Support for micro and nanoseconds is new in Robot Framework 6.0. Support for weeks is new in Robot Framework 7.1.
### [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-687)
Time can also be given in timer like format `hh:mm:ss.mil`. In this format both hour and millisecond parts are optional, leading and trailing zeros can be left out when they are not meaningful, and negative times can be represented by adding the `-` prefix. For example, following timer and time string values are identical:
| Timer | Time string |
|---|---|
| 00:00:01 | 1 second |
| 01:02:03 | 1 hour 2 minutes 3 seconds |
| 1:00:00 | 1 hour |
| 100:00:00 | 100 hours |
| 00:02 | 2 seconds |
| 42:00 | 42 minutes |
| 00:01:02.003 | 1 minute 2 seconds 3 milliseconds |
| 00:01.5 | 1\.5 seconds |
| \-01:02.345 | \- 1 minute 2 seconds 345 milliseconds |
## [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-636)
Many keywords in Robot Framework [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) accept arguments that are handled as Boolean values true or false. If such an argument is given as a string, it is considered false if it is an empty string or equal to `FALSE`, `NONE`, `NO`, `OFF` or `0`, case-insensitively. Other strings are considered true unless the keyword documentation explicitly states otherwise, and other argument types are tested using the same [rules as in Python](http://docs.python.org/library/stdtypes.html#truth-value-testing).
```
*** Keywords ***
True examples
Should Be Equal ${x} ${y} Custom error values=True # Strings are generally true.
Should Be Equal ${x} ${y} Custom error values=yes # Same as the above.
Should Be Equal ${x} ${y} Custom error values=${TRUE} # Python `True` is true.
Should Be Equal ${x} ${y} Custom error values=${42} # Numbers other than 0 are true.
False examples
Should Be Equal ${x} ${y} Custom error values=False # String `false` is false.
Should Be Equal ${x} ${y} Custom error values=no # Also string `no` is false.
Should Be Equal ${x} ${y} Custom error values=${EMPTY} # Empty string is false.
Should Be Equal ${x} ${y} Custom error values=${FALSE} # Python `False` is false.
Should Be Equal ${x} ${y} Custom error values=no values # Special false string with this keyword.
```
Note
Considering `OFF` and `0` false is new in Robot Framework 3.1.
## [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-637)
This appendix explains how expressions are evaluated using Python in different contexts and how variables in expressions are handled.
- [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-4)
- [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluation-namespace)
- [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables-1)
- [Normal `${variable}` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#normal-variable-syntax)
- [Special `$variable` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#special-variable-syntax)
### [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-688)
Constructs such as [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures), [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) and [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) as well as several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords accept an expression that is evaluated in Python:
```
*** Test Cases ***
IF/ELSE
IF ${x} > 0
Log to console ${x} is positive
ELSE
Log to console ${x} is negative
END
Inline Python evaluation
Log to console ${x} is ${{'positive' if ${x} > 0 else 'negative'}}
Evaluate keyword
${type} = Evaluate 'positive' if ${x} > 0 else 'negative'
Log to console ${x} is ${type}
Should Be True keyword
Should Be True ${x} > 0
```
Notice that instead of creating complicated expressions, it is often better to move the logic into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries). That typically eases maintenance and also enhances execution speed.
### [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-689)
Expressions are evaluated using Python's [eval](http://docs.python.org/library/functions.html#eval) function so that normal Python constructs like `'${x}' == 'expected'`, `${x} > 0` and `'${x}'.upper() not in ('FAIL', 'BAD')` can be used and all builtin functions like `len()` and `int()` are available. In addition to that, all unrecognized Python variables are considered to be modules that are automatically imported. It is possible to use all available Python modules, including the standard modules and the installed third party modules.
The following examples demonstrate using Python builtins as well as modules using the [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) syntax, but same expressions would also work with [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) and [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords without the need to use the `${{}}` decoration around the expression:
```
*** Variables ***
${VAR} 123
*** Test Cases ***
Python syntax
Should Be True ${{'${VAR}' == '123'}}
Should Be True ${{'${VAR}'.startswith('x') or '${VAR}' in '012345'}}
Python builtins
Should Be Equal ${{len('${VAR}')}} ${3}
Should Be Equal ${{int('${VAR}')}} ${123}
Access modules
Should Be Equal ${{os.sep}} ${/}
Should Be Equal ${{round(math.pi, 2)}} ${3.14}
Should Start With ${{robot.__version__}} 4.
```
A limitation of using modules is that nested modules like `rootmod.submod` can only be used if the root module automatically imports the submodule. That is not always the case and using such modules is not possible. An concrete example that is relevant in the automation context is the `selenium` module that is implemented, at least at the time of this writing, so that just importing `selenium` does not import the `selenium.webdriver` submodule. Another limitation is that modules cannot be used in the expression part of a list comprehension. A workaround to both of these problems is using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Evaluate that accepts modules to be imported and added to the evaluation namespace as an argument:
```
*** Test Cases ***
Does not work due to nested module structure
Log ${{selenium.webdriver.ChromeOptions()}}
Evaluate keyword with nested module
${options} = Evaluate selenium.webdriver.ChromeOptions() modules=selenium.webdriver
Log ${options}
Does not work due to list comprehension
Log ${{[json.loads(item) for item in ('1', '"b"')]}}
Evaluate keyword with list comprehension
${items} = Evaluate [json.loads(item) for item in ('1', '"b"')] modules=json
Log ${items}
```
The Evaluate keyword also supports custom evaluation namespaces if further customization is needed. See its documentation in the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library for more details.
### [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-690)
#### [Normal `${variable}` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-691)
When a variable is used in the expression using the normal `${variable}` syntax, its value is replaced before the expression is evaluated. This means that the value used in the expression will be the string representation of the variable value, not the variable value itself. This is not a problem with numbers and other objects that have a string representation that can be evaluated directly. For example, if we have a return code as an integer in variable `${rc}`, using something like `${rc} > 0` is fine.
With other objects the behavior depends on the string representation. Most importantly, strings must always be quoted either with single or double quotes like `'${x}'`, and if they can contain newlines, they must be triple-quoted like `'''${x}'''`. Strings containing quotes themselves cause additional problems, but triple-quoting typically handles them. Also the backslash character \\ is problematic, but can be handled by using Python's raw-string notation like `r'${path}'`.
```
*** Test Cases ***
Using normal variable syntax
Should Be True ${rc} > 0
IF '${status}'.upper() == 'PASS'
Log Passed
END
IF 'FAIL' in r'''${output}'''
Log Output contains FAIL
END
```
#### [Special `$variable` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-692)
Quoting strings is not that convenient, but there are cases where replacing the variable with its string representation causes even bigger problems. For example, if the variable value can be either a string or Python `None`, quoting like `'${var}'` is needed because otherwise strings do not work, but then `None` is interpreted to be a string as well. Luckily there is an easy solution to these problems discussed in this section.
Actual variables values are available in the evaluation namespace and can be accessed using special variable syntax without the curly braces like `$variable`. Such variables should never be quoted, not even if they contain strings.
Compare this these examples with the example in the previous section:
```
*** Test Cases ***
Using special variable syntax
Should Be True $rc > 0
IF $status.upper() == 'PASS'
Log Passed
END
IF 'FAIL' in $output
Log Output contains FAIL
END
Only possible using special variable syntax
Should Be True $example is not None
Should Be True len($result) > 1 and $result[1] == 'OK'
```
Using the `$variable` syntax slows down expression evaluation a little. This should not typically matter, but should be taken into account if complex expressions are evaluated often and there are strict time constrains. Moving such logic to test libraries is typically a good idea anyway.
Note
Due to technical reasons, these special variables are available during evaluation as local variables. That makes them unavailable in non-local scopes such as in the expression part of list comprehensions and inside lambdas.
## [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-638)
This appendix lists file extensions, media types, and so on, that are associated with Robot Framework.
### [6\.8.1 Suite file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-222)
[Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) with the following extensions are parsed automatically:
.robot
Suite file using the [plain text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#plain-text-format).
.robot.rst
Suite file using the [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
.rbt
Suite file using the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
Using other extensions is possible, but it requires [separate configuration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse).
### [6\.8.2 Resource file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-223)
[Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) can use the following extensions:
.resource
Recommended when using the plain text format.
.robot, .txt and .tsv
Supported with the plain text format for backwards compatibility reasons. .resource is recommended and may be mandated in the future.
.rst and .rest
Resource file using the [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format).
.rsrc and .json
Resource file using the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format).
### [6\.8.3 Media type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-224)
The media type to use with Robot Framework data is `text/robotframework`.
### [6\.8.4 Remote server port](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-225)
The default [remote server](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface) port is 8270. The port has been [registered by IANA](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=8270).
***
Generated by [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText). Syntax highlighting by [Pygments](http://pygments.org/). |
| Readable Markdown | ## Version 7.4.2
Copyright © 2008-2015 Nokia Networks
Copyright © 2016- Robot Framework Foundation
Table of Contents
- [1 Getting started](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-started)
- [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction)
- [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#why-robot-framework)
- [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#high-level-architecture)
- [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#screenshots)
- [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-more-information)
- [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#copyright-and-license)
- [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions)
- [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-installation)
- [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-using-pip)
- [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-from-source)
- [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#verifying-installation)
- [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dependencies)
- [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments)
- [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#demonstrations)
- [2 Creating test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data)
- [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-syntax)
- [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#files-and-directories)
- [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections)
- [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats)
- [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rules-for-parsing-the-data)
- [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization)
- [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#style)
- [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases)
- [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax)
- [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments)
- [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures)
- [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation)
- [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases)
- [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown)
- [2\.2.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates)
- [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-case-styles)
- [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks)
- [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-syntax)
- [2\.3.2 Task related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-settings)
- [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites)
- [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files)
- [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories)
- [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name)
- [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation)
- [2\.4.5 Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata)
- [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown)
- [2\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries)
- [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries)
- [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import)
- [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library)
- [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries)
- [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries)
- [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables)
- [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-1)
- [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables)
- [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables)
- [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables)
- [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes)
- [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-variable-features)
- [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords)
- [2\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-syntax)
- [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation)
- [2\.7.3 User keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags)
- [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments)
- [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name)
- [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values)
- [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown)
- [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#private-user-keywords)
- [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#recursion)
- [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files)
- [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files)
- [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#control-structures)
- [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops)
- [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops)
- [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-control-using-break-and-continue)
- [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-syntax)
- [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax)
- [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-syntax)
- [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-features)
- [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names)
- [2\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts)
- [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parallel-execution-of-keywords)
- [3 Executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases)
- [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage-1)
- [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution)
- [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-command-line-options)
- [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-results)
- [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files)
- [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information)
- [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-start-up-scripts)
- [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#making-robot-files-executable)
- [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems)
- [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-execution)
- [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-flow)
- [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-and-suite-statuses)
- [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuing-on-failure)
- [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully)
- [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution)
- [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generic-automation-mode)
- [3\.3.2 Task related command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-command-line-options)
- [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs)
- [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-rebot)
- [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-reports-logs-and-output-files)
- [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs)
- [3\.4.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs)
- [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-output-files)
- [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution)
- [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse)
- [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases)
- [3\.5.3 Setting metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-metadata)
- [3\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions)
- [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-variables)
- [3\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run)
- [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order)
- [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data)
- [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-console-output)
- [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners)
- [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-files)
- [3\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files)
- [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels)
- [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs)
- [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics)
- [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords)
- [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords)
- [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution)
- [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports)
- [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results)
- [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)
- [4 Extending Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-robot-framework)
- [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries)
- [4\.1.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-2)
- [4\.1.2 Creating test library class or module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-library-class-or-module)
- [4\.1.3 Creating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords)
- [4\.1.4 Communicating with Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#communicating-with-robot-framework)
- [4\.1.5 Distributing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#distributing-test-libraries)
- [4\.1.6 Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api)
- [4\.1.7 Hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api)
- [4\.1.8 Handling Robot Framework's timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-robot-framework-s-timeouts)
- [4\.1.9 Using Robot Framework's internal modules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules)
- [4\.1.10 Extending existing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extending-existing-test-libraries)
- [4\.2 Remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface)
- [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-3)
- [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#putting-remote-library-to-use)
- [4\.2.3 Supported argument and return value types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types)
- [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol)
- [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface)
- [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-structure)
- [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions)
- [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-listeners-into-use)
- [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-calling-order)
- [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-examples)
- [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface)
- [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-parsers-into-use)
- [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-api)
- [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#examples-2)
- [5 Supporting Tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supporting-tools)
- [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-documentation-tool-libdoc)
- [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage)
- [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#writing-documentation)
- [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax)
- [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking-1)
- [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#representing-arguments)
- [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example)
- [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-documentation-tool-testdoc)
- [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage-1)
- [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-documentation-1)
- [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-clean-up-tool-tidy)
- [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-tools)
- [6 Appendices](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#appendices)
- [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings)
- [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-section-1)
- [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-section)
- [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-section-1)
- [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options)
- [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-test-execution)
- [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-post-processing-outputs)
- [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables-for-execution-and-post-processing)
- [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations)
- [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
- [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting)
- [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-whitespace-in-test-data)
- [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs)
- [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles)
- [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls)
- [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-links-and-images)
- [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles)
- [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tables)
- [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists)
- [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text)
- [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#horizontal-ruler)
- [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format)
- [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number)
- [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string)
- [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string)
- [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-arguments)
- [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions)
- [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-4)
- [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluation-namespace)
- [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables-1)
- [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registrations)
- [6\.8.1 Suite file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-file-extensions)
- [6\.8.2 Resource file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-extensions)
- [6\.8.3 Media type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#media-type)
- [6\.8.4 Remote server port](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-server-port)
## [1 Getting started](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-1)
- [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction)
- [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#copyright-and-license)
- [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions)
- [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#demonstrations)
## [1\.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-226)
Robot Framework is a Python-based, extensible keyword-driven automation framework for acceptance testing, acceptance test driven development (ATDD), behavior driven development (BDD) and robotic process automation (RPA). It can be used in distributed, heterogeneous environments, where automation requires using different technologies and interfaces.
The framework has a rich ecosystem around it consisting of various generic libraries and tools that are developed as separate projects. For more information about Robot Framework and the ecosystem, see [http://robotframework.org](http://robotframework.org/).
Robot Framework is open source software released under the [Apache License 2.0](http://apache.org/licenses/LICENSE-2.0). Its development is sponsored by the [Robot Framework Foundation](http://robotframework.org/foundation).
Note
The official RPA support was added in Robot Framework 3.1. This User Guide still talks mainly about creating tests, test data, and test libraries, but same concepts apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
- [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#why-robot-framework)
- [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#high-level-architecture)
- [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#screenshots)
- [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-more-information)
- [Project pages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#project-pages)
- [Mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists)
### [1\.1.1 Why Robot Framework?](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-230)
- Enables easy-to-use tabular syntax for [creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) in a uniform way.
- Provides ability to create reusable [higher-level keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) from the existing keywords.
- Provides easy-to-read result [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) in HTML format.
- Is platform and application independent.
- Provides a simple [library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) for creating customized test libraries which can be implemented natively with Python.
- Provides a [command line interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and XML based [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for integration into existing build infrastructure (continuous integration systems).
- Provides support for testing web applications, rest APIs, mobile applications, running processes, connecting to remote systems via Telnet or SSH, and so on.
- Supports creating [data-driven test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
- Has built-in support for [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), practical particularly for testing in different environments.
- Provides [tagging](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) to categorize and [select test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) to be executed.
- Enables easy integration with source control: [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) are just files and directories that can be versioned with the production code.
- Provides [test-case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [test-suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) -level setup and teardown.
- The modular architecture supports creating tests even for applications with several diverse interfaces.
### [1\.1.2 High-level architecture](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-231)
Robot Framework is a generic, application and technology independent framework. It has a highly modular architecture illustrated in the diagram below.

Robot Framework architecture
The [test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data) is in simple, easy-to-edit tabular format. When Robot Framework is started, it processes the data, [executes test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) 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 [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries). Libraries can either use application interfaces directly or use lower level test tools as drivers.
### [1\.1.3 Screenshots](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-232)
Following screenshots show examples of the [test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-data) and created [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).

Test case file

Reports and logs
### [1\.1.4 Getting more information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-233)
#### [Project pages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-234)
The number one place to find more information about Robot Framework and the rich ecosystem around it is [http://robotframework.org](http://robotframework.org/). Robot Framework itself is hosted on [GitHub](https://github.com/robotframework/robotframework).
#### [Mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-235)
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](http://www.catb.org/~esr/faqs/smart-questions.html).
[robotframework-users](http://groups.google.com/group/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](http://groups.google.com/group/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](http://groups.google.com/group/robotframework-devel)
Discussion about Robot Framework development.
## [1\.2 Copyright and license](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-227)
Robot Framework is open source software provided under the [Apache License 2.0](http://apache.org/licenses/LICENSE-2.0). Robot Framework documentation such as this User Guide use the [Creative Commons Attribution 3.0 Unported](http://creativecommons.org/licenses/by/3.0) license. Most libraries and tools in the larger ecosystem around the framework are also open source, but they may use different licenses.
The full Robot Framework copyright notice is included below:
```
Copyright 2008-2015 Nokia Networks
Copyright 2016- Robot Framework Foundation
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
## [1\.3 Installation instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-228)
These instructions cover installing [Robot Framework](https://robotframework.org/) and its preconditions on different operating systems. If you already have [Python](http://python.org/) installed, you can install Robot Framework using the standard package manager [pip](https://pip.pypa.io/):
```
pip install robotframework
```
- [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-installation)
- [Installing Python on Linux](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-linux)
- [Installing Python on Windows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-windows)
- [Installing Python on macOS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-python-on-macos)
- [PyPy installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pypy-installation)
- [Configuring `PATH`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path)
- [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-using-pip)
- [Running `pip` command](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-pip-command)
- [Installing and uninstalling Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-and-uninstalling-robot-framework)
- [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installing-from-source)
- [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#verifying-installation)
- [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dependencies)
- [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments)
### [1\.3.1 Python installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-236)
[Robot Framework](https://robotframework.org/) is implemented using [Python](http://python.org/), and a precondition to install it is having Python or its alternative implementation [PyPy](https://pypy.org/) installed. Another recommended precondition is having the [pip](https://pip.pypa.io/) package manager available.
Robot Framework requires Python 3.8 or newer. The latest version that supports Python 3.6 and 3.7 is [Robot Framework 6.1.1](https://github.com/robotframework/robotframework/blob/v6.1.1/INSTALL.rst). If you need to use Python 2, [Jython](http://jython.org/) or [IronPython](http://ironpython.net/), you can use [Robot Framework 4.1.3](https://github.com/robotframework/robotframework/blob/v4.1.3/INSTALL.rst).
#### [Installing Python on Linux](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-237)
On Linux you should have suitable Python installation with [pip](https://pip.pypa.io/) available by default. If not, you need to consult your distributions documentation to learn how to install them. This is also true if you want to use some other Python version than the one provided by your distribution by default.
To check what Python version you have installed, you can run `python --version` command in a terminal:
```
$ python --version
Python 3.10.13
```
Notice that if your distribution provides also older Python 2, running `python` may use that. To use Python 3, you can use `python3` command or even more version specific command like `python3.8`. You need to use these version specific variants also if you have multiple Python 3 versions installed and need to pinpoint which one to use:
```
$ python3.11 --version
Python 3.11.7
$ python3.12 --version
Python 3.12.1
```
Installing Robot Framework directly under the system provided Python has a risk that possible problems can affect the whole Python installation used also by the operating system itself. Nowadays Linux distributions typically use [user installs](https://pip.pypa.io/en/stable/user_guide/#user-installs) by default to avoid such problems, but users can also themselves decide to use [virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#virtual-environments).
#### [Installing Python on Windows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-238)
On Windows Python is not available by default, but it is easy to install. The recommended way to install it is using the official Windows installers available at [http://python.org](http://python.org/). For other alternatives, such as installing from the Microsoft Store, see the [official Python documentation](https://docs.python.org/3/using/windows.html).
When installing Python on Windows, it is recommended to add Python to [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) to make it and tools like pip and Robot Framework easier to execute from the command line. When using the [official installer](https://docs.python.org/3/using/windows.html#windows-full), you just need to select the `Add Python 3.x to PATH` checkbox on the first dialog.
To make sure Python installation has been successful and Python has been added to `PATH`, you can open the command prompt and execute `python --version`:
```
C:\
Python 3.10.9
```
If you install multiple Python versions on Windows, the version that is used when you execute `python` is the one first in `PATH`. If you need to use others, the easiest way is using the [py launcher](https://docs.python.org/3/using/windows.html#launcher):
```
C:\
Python 3.10.9
C:\
Python 3.12.1
```
#### [Installing Python on macOS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-239)
MacOS does not provide Python 3 compatible Python version by default, so it needs to be installed separately. The recommended approach is using the official macOS installers available at [http://python.org](http://python.org/). If you are using a package manager like [Homebrew](https://brew.sh/), installing Python via it is possible as well.
You can validate Python installation on macOS using `python --version` like on other operating systems.
#### [PyPy installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-240)
[PyPy](https://pypy.org/) is an alternative Python implementation. Its main advantage over the standard Python implementation is that it can be faster and use less memory, but this depends on the context where and how it is used. If execution speed is important, at least testing PyPy is probably a good idea.
Installing PyPy is a straightforward procedure and you can find both installers and installation instructions at [http://pypy.org](http://pypy.org/). To validate that PyPy installation was successful, run `pypy --version` or `pypy3 --version`.
Note
Using Robot Framework with PyPy is officially supported only on Linux.
#### [Configuring `PATH`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-241)
The [PATH environment variable](https://en.wikipedia.org/wiki/PATH_\(variable\)) lists directories where commands executed in a system are searched from. To make using Python, [pip](https://pip.pypa.io/) and Robot Framework easier from the command line, it is recommended to add the Python installation directory as well as the directory where commands like `pip` and `robot` are installed into `PATH`.
When using Python on Linux or macOS, Python and tools installed with it should be automatically in `PATH`. If you nevertheless need to update `PATH`, you typically need to edit some system wide or user specific configuration file. Which file to edit and how depends on the operating system and you need to consult its documentation for more details.
On Windows the easiest way to make sure `PATH` is configured correctly is setting the `Add Python 3.x to PATH` checkbox when [running the installer](https://docs.python.org/3/using/windows.html#the-full-installer). To manually modify `PATH` on Windows, follow these steps:
1. Find `Environment Variables` under `Settings`. There are variables affecting the whole system and variables affecting only the current user. Modifying the former will require admin rights, but modifying the latter is typically enough.
2. Select `PATH` (often written like `Path`) and click `Edit`. If you are editing user variables and `PATH` does not exist, click `New` instead.
3. Add both the Python installation directory and the Scripts directory under the installation directory into `PATH`.
4. Exit the dialog with `Ok` to save the changes.
5. Start a new command prompt for the changes to take effect.
### [1\.3.2 Installing using pip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-242)
These instructions cover installing Robot Framework using [pip](https://pip.pypa.io/), the standard Python package manager. If you are using some other package manager like [Conda](https://conda.io/), you can use it instead but need to study its documentation for instructions.
When installing Python, you typically get pip installed automatically. If that is not the case, you need to check the documentation of that Python installation for instructions how to install it separately.
#### [Running `pip` command](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-243)
Typically you use pip by running the `pip` command, but on Linux you may need to use `pip3` or even more Python version specific variant like `pip3.8` instead. When running `pip` or any of its variants, the pip version that is found first in [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) will be used. If you have multiple Python versions installed, you may need to pinpoint which exact version you want to use. This is typically easiest done by running `python -m pip` and substituting `python` with the Python version you want to use.
To make sure you have pip available, you can run `pip --version` or equivalent.
Examples on Linux:
```
$ pip --version
pip 23.2.1 from ... (python 3.10)
$ python3.12 -m pip --version
pip 23.3.1 from ... (python 3.12)
```
Examples on Windows:
```
C:\
pip 23.2.1 from ... (python 3.10)
C:\
pip 23.3.2 from ... (python 3.12)
```
In the subsequent sections pip is always run using the `pip` command. You may need to use some of the other approaches explained above in your environment.
#### [Installing and uninstalling Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-244)
The easiest way to use pip is by letting it find and download packages it installs from the [Python Package Index (PyPI)](https://pypi.org/project/robotframework), but it can also install packages downloaded from the PyPI separately. The most common usages are shown below and [pip](https://pip.pypa.io/) documentation has more information and examples.
```
pip install robotframework
pip install --upgrade robotframework
pip install --upgrade --pre robotframework
pip install robotframework==7.0
pip install robotframework-7.0-py3-none-any.whl
pip install https://github.com/robotframework/robotframework/archive/master.zip
pip uninstall robotframework
```
### [1\.3.3 Installing from source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-245)
Another installation alternative is getting Robot Framework source code and installing it using the provided `setup.py` script. This approach is recommended only if you do not have [pip](https://pip.pypa.io/) available for some reason.
You can get the source code by downloading a source distribution package from [PyPI](https://pypi.org/project/robotframework) and extracting it. An alternative is cloning the [GitHub](https://github.com/robotframework/robotframework) repository and checking out the needed release tag.
Once you have the source code, you can install it with the following command:
```
python setup.py install
```
The `setup.py` script accepts several arguments allowing, for example, installation into a non-default location that does not require administrative rights. It is also used for creating different distribution packages. Run `python setup.py --help` for more details.
### [1\.3.4 Verifying installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-246)
To make sure that the correct Robot Framework version has been installed, run the following command:
```
$ robot --version
Robot Framework 7.0 (Python 3.10.3 on linux)
```
If running these commands fails with a message saying that the command is not found or recognized, a good first step is double-checking the [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path) configuration.
If you have installed Robot Framework under multiple Python versions, running `robot` will execute the one first in [PATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-path). To select explicitly, you can run `python -m robot` and substitute `python` with the right Python version.
```
$ python3.12 -m robot --version
Robot Framework 7.0 (Python 3.12.1 on linux)
C:\>py -3.11 -m robot --version
Robot Framework 7.0 (Python 3.11.7 on win32)
```
### [1\.3.5 Dependencies](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-247)
Robot Framework core functionality has no mandatory dependencies other than Python and its standard library. Some individual features may require optional dependencies to be installed, though. What dependencies are needed is always explained in the relevant documentation.
### [1\.3.6 Virtual environments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-248)
Python [virtual environments](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) allow Python packages to be installed in an isolated location for a particular system or application, rather than installing all packages into the same global location. They have two main use cases:
- Install packages needed by different projects into their own environments. This avoids conflicts if projects need different versions of same packages.
- Avoid installing everything under the global Python installation. This is especially important on Linux where the global Python installation may be used by the distribution itself and messing it up can cause severe problems.
## [1\.4 Demonstrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-229)
There are several demo projects that introduce Robot Framework and help getting started with it.
[Quick Start Guide](https://github.com/robotframework/QuickStartGuide/blob/master/QuickStart.rst)
Introduces the most important features of Robot Framework and acts as an executable demo.
[Robot Framework demo](https://github.com/robotframework/RobotDemo)
Simple example test cases. Demonstrates also creating custom test libraries.
[Web testing demo](https://github.com/robotframework/WebDemo)
Demonstrates how to create tests and higher level keywords. The system under test is a simple web page that is tested using [SeleniumLibrary](https://github.com/robotframework/SeleniumLibrary).
[ATDD with Robot Framework](https://code.google.com/p/atdd-with-robot-framework)
Demonstrates how to use Robot Framework when following Acceptance Test Driven Development (ATDD) process.
## [2 Creating test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-16)
- [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-syntax)
- [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases)
- [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks)
- [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites)
- [2\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries)
- [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables)
- [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords)
- [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files)
- [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#control-structures)
- [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-features)
## [2\.1 Test data syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-249)
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. Although this section mostly uses term *test*, the same rules apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
- [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#files-and-directories)
- [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections)
- [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats)
- [Space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format)
- [Pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format)
- [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format)
- [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format)
- [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rules-for-parsing-the-data)
- [Ignored data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignored-data)
- [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping)
- [Dividing data to several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows)
- [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization)
- [Enabling languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages)
- [Built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages)
- [Custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files)
- [Contributing translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations)
- [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#style)
### [2\.1.1 Files and directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-259)
The hierarchical structure for arranging test cases is built as follows:
- Test cases are created in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files).
- A test case file automatically creates a [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites) containing the test cases in that file.
- A directory containing test case files forms a higher-level test suite. Such a [suite directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories) has suites created from test case files as its child 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) configuring the created test suite.
In addition to this, there are:
- [Test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) containing the lowest-level keywords.
- [Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) with [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) and higher-level [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords).
- [Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) to provide more flexible ways to create variables than resource files.
Test case files, test suite initialization files and resource files are all created using Robot Framework test data syntax. Test libraries and variable files are created using "real" programming languages, most often Python.
### [2\.1.2 Test data sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-260)
Robot Framework data is defined in different sections, often also called tables, listed below:
| Section | Used for |
|---|---|
| Settings | 1\) Importing [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) and [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files). 2\) Defining metadata for [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) and [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase). |
| Variables | Defining [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) that can be used elsewhere in the test data. |
| Test Cases | [Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) from available keywords. |
| Tasks | [Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) using available keywords. Single file can only contain either tests or tasks. |
| Keywords | [Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) from existing lower-level keywords |
| Comments | Additional comments or data. Ignored by Robot Framework. |
Different sections are recognized by their header row. The recommended header format is `*** Settings ***`, but the header is case-insensitive, surrounding spaces are optional, and the number of asterisk characters can vary as long as there is at least one asterisk in the beginning. For example, also `*settings` would be recognized as a section header.
Robot Framework supports also singular headers like `*** Setting ***,` but that support was deprecated in Robot Framework 6.0. There is a visible deprecation warning starting from Robot Framework 7.0 and singular headers will eventually not be supported at all.
The header row can contain also other data than the actual section header. The extra data must be separated from the section header using the data format dependent separator, typically two or more spaces. These extra headers are ignored at parsing time, but they can be used for documenting purposes. This is especially useful when creating test cases using the [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
Possible data before the first section is ignored.
Note
Section headers can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
### [2\.1.3 Supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-261)
The most common approach to create Robot Framework data is using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format) where pieces of the data, such as keywords and their arguments, are separated from each others with two or more spaces. An alternative is using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format) where the separator is the pipe character surrounded with spaces (\|).
Suite files typically use the .robot extension, but what files are parsed [can be configured](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse). [Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) can use the .robot extension as well, but using the dedicated .resource extension is recommended and may be mandated in the future. Files containing non-ASCII characters must be saved using the UTF-8 encoding.
Robot Framework supports also [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) files so that normal Robot Framework data is [embedded into code blocks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format). Only files with the .robot.rst extension are parsed by default. If you would rather use just .rst or .rest extension, that needs to be configured separately.
Robot Framework data can also be created in the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format) that is targeted more for tool developers than normal Robot Framework users. Only JSON files with the custom .rbt extension are parsed by default.
Earlier Robot Framework versions supported data also in HTML and TSV formats. The TSV format still works if the data is compatible with the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format), but the support for the HTML format has been removed altogether. If you encounter such data files, you need to convert them to the plain text format to be able to use them with Robot Framework 3.2 or newer. The easiest way to do that is using the [Tidy](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tidy) tool, but you must use the version included with Robot Framework 3.1 because newer versions do not understand the HTML format at all.
#### [Space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-262)
When Robot Framework parses data, it first splits the data to lines and then lines to tokens such as keywords and arguments. When using the space separated format, the separator between tokens is two or more spaces or alternatively one or more tab characters. In addition to the normal ASCII space, any Unicode character considered to be a space (e.g. no-break space) works as a separator. The number of spaces used as separator can vary, as long as there are at least two, making it possible to align the data nicely in settings and elsewhere when it makes the data easier to understand.
```
*** Settings ***
Documentation Example using the space separated format.
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
*** Test Cases ***
My Test
[Documentation] Example test.
Log ${MESSAGE}
My Keyword ${CURDIR}
Another Test
Should Be Equal ${MESSAGE} Hello, world!
*** Keywords ***
My Keyword
[Arguments] ${path}
Directory Should Exist ${path}
```
Because tabs and consecutive spaces are considered separators, they must be escaped if they are needed in keyword arguments or elsewhere in the actual data. It is possible to use special escape syntax like `\t` for tab and `\xA0` for no-break space as well as [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) `${SPACE}` and `${EMPTY}`. See the [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) section for details.
Tip
Although using two spaces as a separator is enough, it is recommended to use four spaces to make the separator easier to recognize.
Note
Prior to Robot Framework 3.2, non-ASCII spaces used in the data were converted to ASCII spaces during parsing. Nowadays all data is preserved as-is.
#### [Pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-263)
The biggest problem of the space delimited format is that visually separating keywords from 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 delimited variant can work better because it makes the separator more visible.
One file can contain both space separated and pipe separated lines. Pipe separated lines are recognized by the mandatory leading pipe character, but the pipe at the end of the line is optional. There must always be at least one space or tab on both sides of the pipe except at the beginning and at the end of the line. There is no need to align the pipes, but that often makes the data easier to read.
```
| *** Settings *** |
| Documentation | Example using the pipe separated format.
| Library | OperatingSystem
| *** Variables *** |
| ${MESSAGE} | Hello, world!
| *** Test Cases *** | | |
| My Test | [Documentation] | Example test. |
| | Log | ${MESSAGE} |
| | My Keyword | ${CURDIR} |
| Another Test | Should Be Equal | ${MESSAGE} | Hello, world!
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
```
When using the pipe separated format, consecutive spaces or tabs inside arguments do not need to be escaped. Similarly empty columns do not need to be escaped except [if they are at the end](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping). Possible pipes surrounded by spaces in the actual test data must be escaped with a backslash, though:
```
| *** Test Cases *** | | | |
| Escaping Pipe | ${file count} = | Execute Command | ls -1 *.txt \| wc -l |
| | Should Be Equal | ${file count} | 42 |
```
Note
Preserving consecutive spaces and tabs in arguments is new in Robot Framework 3.2. Prior to it non-ASCII spaces used in the data were also converted to ASCII spaces.
#### [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-264)
[reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) (reST) is an 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. reST documents are most often compiled to HTML, but also other output formats are supported. Using reST with Robot Framework allows you to mix richly formatted documents and test data in a concise text format that is easy to work with using simple text editors, diff tools, and source control systems.
When using Robot Framework with reStructuredText files, normal Robot Framework data is embedded to so called code blocks. In standard reST code blocks are marked using the `code` directive, but Robot Framework supports also `code-block` or `sourcecode` directives used by the [Sphinx](http://sphinx-doc.org/) tool.
```
reStructuredText example
------------------------
This text is outside code blocks and thus ignored.
.. code:: robotframework
*** Settings ***
Documentation Example using the reStructuredText format.
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
*** Test Cases ***
My Test
[Documentation] Example test.
Log ${MESSAGE}
My Keyword ${CURDIR}
Another Test
Should Be Equal ${MESSAGE} Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
.. code:: robotframework
# Both space and pipe separated formats are supported.
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
.. code:: python
# This code block is ignored.
def example():
print('Hello, world!')
```
Robot Framework supports reStructuredText files using .robot.rst, .rst and .rest extensions. To avoid parsing unrelated reStructuredText files, only files with the .robot.rst extension are parsed by default when executing a directory. Parsing files with other extensions [can be enabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) by using either \--parseinclude or \--extension option.
When Robot Framework parses reStructuredText files, errors below level `SEVERE` are ignored to avoid noise about possible non-standard directives and other such markup. This may hide also real errors, but they can be seen when processing files using reStructuredText tooling normally.
Note
Parsing .robot.rst files automatically is new in Robot Framework 6.1.
#### [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-265)
Robot Framework supports data also in the [JSON](https://json.org/) format. This format is designed more for tool developers than for regular Robot Framework users and it is not meant to be edited manually. Its most important use cases are:
- Transferring data between processes and machines. A suite can be converted to JSON in one machine and recreated somewhere else.
- Saving a suite, possibly a nested suite, constructed from normal Robot Framework data into a single JSON file that is faster to parse.
- Alternative data format for external tools generating tests or tasks.
Note
The JSON data support is new in Robot Framework 6.1 and it can be enhanced in future Robot Framework versions. If you have an enhancement idea or believe you have encountered a bug, please submit an [issue](https://issues.robotframework.org/) or start a discussion thread on the `#devel` channel on our [Slack](http://slack.robotframework.org/).
##### Converting suite to JSON
A suite structure can be serialized into JSON by using the [TestSuite.to\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.to_json) method. When used without arguments, it returns JSON data as a string, but it also accepts a path or an open file where to write JSON data along with configuration options related to JSON formatting:
```
from robot.running import TestSuite
# Create suite based on data on the file system.
suite = TestSuite.from_file_system('/path/to/data')
# Get JSON data as a string.
data = suite.to_json()
# Save JSON data to a file with custom indentation.
suite.to_json('data.rbt', indent=2)
```
If you would rather work with Python data and then convert that to JSON or some other format yourself, you can use [TestSuite.to\_dict](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.to_dict) instead.
##### Creating suite from JSON
A suite can be constructed from JSON data using the [TestSuite.from\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_json) method. It works both with JSON strings and paths to JSON files:
```
from robot.running import TestSuite
# Create suite from JSON data in a file.
suite = TestSuite.from_json('data.rbt')
# Create suite from a JSON string.
suite = TestSuite.from_json('{"name": "Suite", "tests": [{"name": "Test"}]}')
# Execute suite. Notice that log and report needs to be created separately.
suite.run(output='example.xml')
```
If you have data as a Python dictionary, you can use [TestSuite.from\_dict](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_dict) instead. Regardless of how a suite is recreated, it exists only in memory and original data files on the file system are not recreated.
As the above example demonstrates, the created suite can be executed using the [TestSuite.run](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.run) method. It may, however, be easier to execute a JSON file directly as explained in the following section.
##### Executing JSON files
When executing tests or tasks using the `robot` command, JSON files with the custom .rbt extension are parsed automatically. This includes running individual JSON files like `robot tests.rbt` and running directories containing .rbt files. If you would rather use the standard .json extension, you need to [configure which files are parsed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse).
##### Adjusting suite source
Suite source in the data got from `TestSuite.to_json` and `TestSuite.to_dict` is in absolute format. If a suite is recreated later on a different machine, the source may thus not match the directory structure on that machine. To avoid that, it is possible to use the [TestSuite.adjust\_source](https://robot-framework.readthedocs.io/en/master/autodoc/robot.model.html#robot.model.testsuite.TestSuite.adjust_source) method to make the suite source relative before getting the data and add a correct root directory after the suite is recreated:
```
from robot.running import TestSuite
# Create a suite, adjust source and convert to JSON.
suite = TestSuite.from_file_system('/path/to/data')
suite.adjust_source(relative_to='/path/to')
suite.to_json('data.rbt')
# Recreate suite elsewhere and adjust source accordingly.
suite = TestSuite.from_json('data.rbt')
suite.adjust_source(root='/new/path/to')
```
##### JSON structure
Imports, variables and keywords created in suite files are included in the generated JSON along with tests and tasks. The exact JSON structure is documented in the running.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
### [2\.1.4 Rules for parsing the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-266)
#### [Ignored data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-267)
When Robot Framework parses the test data files, it ignores:
- All data before the first [test data section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections).
- Data in the [Comments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections) section.
- All empty rows.
- All empty cells at the end of rows when using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format).
- All single backslashes (\\) when not used for [escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping).
- All characters following the hash character (`#`), when it is the first character of a cell. This means that hash marks can be used to enter comments in the 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, place it to the documentation or other metadata of test cases or suites, or log it with the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Log or Comment.
#### [Escaping](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-268)
The escape character in Robot Framework test data is the backslash (\\) and additionally [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) `${EMPTY}` and `${SPACE}` can often be used for escaping. Different escaping mechanisms are discussed in the sections below.
##### Escaping special characters
The backslash character can be used to escape special characters so that their literal values are used.
| Character | Meaning | Examples |
|---|---|---|
| `\$` | Dollar sign, never starts a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable). | `\${notvar}` |
| `\@` | At sign, never starts a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable). | `\@{notvar}` |
| `\&` | Ampersand, never starts a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable). | `\&{notvar}` |
| `\%` | Percent sign, never starts an [environment variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variable). | `\%{notvar}` |
| `\#` | Hash sign, never starts a [comment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#comment). | `\# not comment` |
| `\=` | Equal sign, never part of [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). | `not\=named` |
| `\|` | Pipe character, not a separator in the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format). | `ls -1 *.txt \| wc -l` |
| `\\` | Backslash character, never escapes anything. | `c:\\temp, \\${var}` |
##### Forming escape sequences
The backslash character also allows creating special escape sequences that are recognized as characters that would otherwise be hard or impossible to create in the test data.
| Sequence | Meaning | Examples |
|---|---|---|
| `\n` | Newline character. | `first line\n2nd line` |
| `\r` | Carriage return character | `text\rmore text` |
| `\t` | Tab character. | `text\tmore text` |
| `\xhh` | Character with hex value `hh`. | `null byte: \x00, ä: \xE4` |
| `\uhhhh` | Character with hex value `hhhh`. | `snowman: \u2603` |
| `\Uhhhhhhhh` | Character with hex value `hhhhhhhh`. | `love hotel: \U0001f3e9` |
Note
All strings created in the test data, including characters like `\x02`, are Unicode and must be explicitly converted to byte strings if needed. This can be done, for example, using Convert To Bytes or Encode String To Bytes keywords in [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) and [String](https://robotframework.org/robotframework/latest/libraries/String.html) libraries, respectively, or with something like `value.encode('UTF-8')` in Python code.
Note
If invalid hexadecimal values are used with `\x`, `\u` or `\U` escapes, the end result is the original value without the backslash character. For example, `\xAX` (not hex) and `\U00110000` (too large value) result with `xAX` and `U00110000`, respectively. This behavior may change in the future, though.
Note
[Built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${\n}` can be used if operating system dependent line terminator is needed (`\r\n` on Windows and `\n` elsewhere).
##### Handling empty values
When using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format), the number of spaces used as a separator can vary and thus empty values cannot be recognized unless they are escaped. Empty cells can be escaped either with the backslash character or with [built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${EMPTY}`. The latter is typically recommended as it is easier to understand.
```
*** Test Cases ***
Using backslash
Do Something first arg \
Do Something \ second arg
Using ${EMPTY}
Do Something first arg ${EMPTY}
Do Something ${EMPTY} second arg
```
When using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format), empty values need to be escaped only when they are at the end of the row:
```
| *** Test Cases *** | | | |
| Using backslash | Do Something | first arg | \ |
| | Do Something | | second arg |
| | | | |
| Using ${EMPTY} | Do Something | first arg | ${EMPTY} |
| | Do Something | | second arg |
```
##### Handling spaces
Spaces, especially consecutive spaces, as part of arguments for keywords or needed otherwise are problematic for two reasons:
- Two or more consecutive spaces is considered a separator when using the [space separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-separated-format).
- Leading and trailing spaces are ignored when using the [pipe separated format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pipe-separated-format).
In these cases spaces need to be escaped. Similarly as when escaping empty values, it is possible to do that either by using the backslash character or by using the [built-in variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variable) `${SPACE}`.
| Escaping with backslash | Escaping with `${SPACE}` | Notes |
|---|---|---|
| \\ leading space | `${SPACE}leading space` | |
| trailing space \\ | `trailing space${SPACE}` | Backslash must be after the space. |
| \\ \\ | `${SPACE}` | Backslash needed on both sides. |
| consecutive \\ \\ spaces | `consecutive${SPACE * 3}spaces` | Using [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax). |
As the above examples show, using the `${SPACE}` variable often makes the test data easier to understand. It is especially handy in combination with the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) when more than one space is needed.
#### [Dividing data to several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-269)
If there is more data than readily fits a row, it is possible to split it and start continuing rows with ellipsis (`...`). Ellipses can be indented to match the indentation of the starting row and they must always be followed by the normal test data separator.
In most places split lines have exact same semantics as lines that are not split. Exceptions to this rule are [suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation), [test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation) and [keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation) documentation as well [suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata). With them split values are automatically [joined together with the newline character](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines) to ease creating multiline values.
The `...` syntax allows also splitting variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section). When long scalar variables (e.g. `${STRING}`) are split to multiple rows, the final value is got by concatenating the rows together. The separator is a space by default, but that can be changed by starting the value with `SEPARATOR=<sep>`.
Splitting lines is illustrated in the following two examples containing exactly same data without and with splitting.
```
*** Settings ***
Documentation Here we have documentation for this suite.\nDocumentation is often quite long.\n\nIt can also contain multiple paragraphs.
Test Tags test tag 1 test tag 2 test tag 3 test tag 4 test tag 5
*** Variables ***
${STRING} This is a long string. It has multiple sentences. It does not have newlines.
${MULTILINE} This is a long multiline string.\nThis is the second line.\nThis is the third and the last line.
@{LIST} this list is quite long and items in it can also be long
&{DICT} first=This value is pretty long. second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[Tags] you probably do not have this many tags in real life
Do X first argument second argument third argument fourth argument fifth argument sixth argument
${var} = Get X first argument passed to this keyword is pretty long second argument passed to this keyword is long too
```
```
*** Settings ***
Documentation Here we have documentation for this suite.
... Documentation is often quite long.
...
... It can also contain multiple paragraphs.
Test Tags test tag 1 test tag 2 test tag 3
... test tag 4 test tag 5
*** Variables ***
${STRING} This is a long string.
... It has multiple sentences.
... It does not have newlines.
${MULTILINE} SEPARATOR=\n
... This is a long multiline string.
... This is the second line.
... This is the third and the last line.
@{LIST} this list is quite long and
... items in it can also be long
&{DICT} first=This value is pretty long.
... second=This value is even longer. It has two sentences.
*** Test Cases ***
Example
[Tags] you probably do not have this many
... tags in real life
Do X first argument second argument third argument
... fourth argument fifth argument sixth argument
${var} = Get X
... first argument passed to this keyword is pretty long
... second argument passed to this keyword is long too
```
### [2\.1.5 Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-270)
Robot Framework localization efforts were started in Robot Framework 6.0 that allowed translation of [section headers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections), [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings), [Given/When/Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages) used in Behavior Driven Development (BDD), and [true and false strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) used in automatic Boolean argument conversion. The plan is to extend localization support in the future, for example, to log and report and possibly also to control structures.
This section explains how to [activate languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions), what [built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages) are supported, how to create [custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files) and how new translations can be [contributed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations).
#### [Enabling languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-271)
##### Using command line option
The main mechanism to activate languages is specifying them from the command line using the \--language option. When enabling [built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-languages), it is possible to use either the language name like `Finnish` or the language code like `fi`. Both names and codes are case and space insensitive and also the hyphen (`-`) is ignored. To enable multiple languages, the \--language option needs to be used multiple times:
```
robot --language Finnish testit.robot
robot --language pt --language ptbr testes.robot
```
The same \--language option is also used when activating [custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-language-files). With them the value can be either a path to the file or, if the file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), the module name:
```
robot --language Custom.py tests.robot
robot --language MyLang tests.robot
```
For backwards compatibility reasons, and to support partial translations, English is always activated automatically. Future versions may allow disabling it.
##### Pre-file configuration
It is also possible to enable languages directly in data files by having a line `Language: <value>` (case-insensitive) before any of the section headers. The value after the colon is interpreted the same way as with the \--language option:
```
Language: Finnish
*** Asetukset ***
Dokumentaatio Example using Finnish.
```
If there is a need to enable multiple languages, the `Language:` line can be repeated. These configuration lines cannot be in comments so something like `# Language: Finnish` has no effect.
Due to technical limitations, the per-file language configuration affects also parsing subsequent files as well as the whole execution. This behavior is likely to change in the future and *should not* be relied upon. If you use per-file configuration, use it with all files or enable languages globally with the \--language option.
#### [Built-in languages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-272)
The following languages are supported out-of-the-box. Click the language name to see the actual translations:
- [Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
All these translations have been provided by the awesome Robot Framework community. If a language you are interested in is not included, you can consider [contributing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#contributing-translations) it\!
#### [Custom language files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-273)
If a language you would need is not available as a built-in language, or you want to create a totally custom language for some specific need, you can easily create a custom language file. Language files are Python files that contain one or more language definitions that are all loaded when the language file is taken into use. Language definitions are created by extending the `robot.api.Language` base class and overriding class attributes as needed:
```
from robot.api import Language
class Example(Language):
test_cases_header = 'Validations'
tags_setting = 'Labels'
given_prefixes = ['Assuming']
true_strings = ['OK', '\N{THUMBS UP SIGN}']
```
Assuming the above code would be in file example.py, a path to that file or just the module name `example` could be used when the language file is [activated](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-languages).
The above example adds only some of the possible translations. That is fine because English is automatically enabled anyway. Most values must be specified as strings, but BDD prefixes and true/false strings allow more than one value and must be given as lists. For more examples, see Robot Framework's internal [languages](https://github.com/robotframework/robotframework/blob/master/src/robot/conf/languages.py) module that contains the `Language` class as well as all built-in language definitions.
#### [Contributing translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-274)
If you want to add translation for a new language or enhance existing, head to [Crowdin](https://robotframework.crowdin.com/) that we use for collaboration. For more details, see the separate [Localization](https://github.com/MarketSquare/localization) project, and for questions and free discussion join the `#localization` channel on our [Slack](http://slack.robotframework.org/).
### [2\.1.6 Style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-275)
Robot Framework syntax creates a simple programming language, and similarly as with other languages, it is important to think about the coding style. Robot Framework syntax is pretty flexible on purpose, but there are some generally recommended conventions:
- Four space indentation.
- Four space separation between keywords and arguments, settings and their values, etc... In some cases it makes sense to use more than four spaces. For example when aligning values in the Settings or Variables section or in [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style).
- Global [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) using capital letters like `${EXAMPLE}` and local variables using lower-case letters like `${example}`.
- Consistency within a single file and preferably within the whole project.
One case where there currently is no strong convention is keyword capitalization. Robot Framework itself typically uses title case like Example Keyword in documentation and elsewhere, and this style is often used in Robot Framework data as well. It does not work too well with longer, sentence-like keywords such as Log into system as an admin, though.
Teams and organizations using Robot Framework should have their own coding standards. The community developed [Robot Framework Style Guide](https://docs.robotframework.org/docs/style_guide) is an excellent starting point that can be amended as needed. It is also possible to enforce these conventions by using the [Robocop](https://robocop.readthedocs.io/) linter and the [Robotidy](https://robotidy.readthedocs.io/) code formatter.
## [2\.2 Creating test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-250)
This section describes the overall test case syntax. Organizing test cases into [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) using [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories) is discussed in the next section.
When using Robot Framework for other automation purposes than test automation, it is recommended to create *tasks* instead of tests. The task syntax is for most parts identical to the test syntax, and the differences are explained in the [Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) section.
- [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax)
- [Settings in the Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-test-case-section)
- [Test case related settings in the Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-related-settings-in-the-setting-section)
- [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments)
- [Positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments)
- [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values)
- [Variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments)
- [Named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments)
- [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments)
- [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments)
- [Arguments embedded to keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arguments-embedded-to-keyword-names)
- [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures)
- [When test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-test-case-fails)
- [Error messages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#error-messages)
- [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation)
- [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases)
- [Deprecation of Force Tags and Default Tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecation-of-force-tags-and-default-tags)
- [Reserved tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags)
- [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown)
- [2\.2.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates)
- [Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage)
- [Templates with multiple iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-multiple-iterations)
- [Templates with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-embedded-arguments)
- [Templates with `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-for-loops)
- [Templates with `IF/ELSE` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#templates-with-if-else-structures)
- [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-test-case-styles)
- [Keyword-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-driven-style)
- [Data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style)
- [Behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style)
### [2\.2.1 Test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-276)
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-277)
Test cases are constructed in test case sections from the available keywords. Keywords can be imported from [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) or [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files), or created in the [keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) of the test case file itself.
The first column in the test case section 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 section. It is an error to have something between the section headers and the first test.
The second column normally has keyword names. An exception to this rule is [setting variables from keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-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.
```
*** Test Cases ***
Valid Login
Open Login Page
Input Username 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
```
Note
Although test case names can contain any character, using `?` and especially `*` is not generally recommended because they are considered to be [wildcards](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#wildcards) when [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases). For example, trying to run only a test with name Example \* like `--test 'Example *'` will actually run any test starting with Example.
#### [Settings in the Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-278)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation).
\[Setup\], \[Teardown\]
Specify [test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown).
\[Tags\]
Used for [tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases).
\[Template\]
Specifies the [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) to use. The test itself will contain only data to use as arguments to that keyword.
\[Timeout\]
Used for setting a [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). [Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) are discussed in their own section.
Note
Setting names are case-insensitive, but the format used above is recommended. Settings used to be also space-insensitive, but that was deprecated in Robot Framework 3.1 and trying to use something like `[T a g s]` causes an error in Robot Framework 3.2. Possible spaces between brackets and the name (e.g. `[ Tags ]`) are still allowed.
Example test case with settings:
```
*** Test Cases ***
Test With Settings
[Documentation] Another dummy test
[Tags] dummy owner-johndoe
Log Hello, world!
```
### [2\.2.2 Using arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-280)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool, but the same information is available on documentation generated by generic documentation tools such as pydoc.
#### [Positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-281)
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 . 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](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html), takes no arguments.
```
*** Test Cases ***
Example
Create Directory ${TEMPDIR}/stuff
Copy File ${CURDIR}/file.txt ${TEMPDIR}/stuff
No Operation
```
#### [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-282)
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 . 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 . Trying to use it without any arguments or more than three arguments would not work.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-283)
It is also possible that a keyword accepts any number of arguments. These so called *varargs* can be combined with mandatory arguments and arguments with default values, but they are always given after them. In the documentation they have an asterisk before the argument name like `*varargs`.
For example, Remove Files and Join Paths keywords from the [OperatingSystem](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) library 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.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-284)
The named argument syntax makes using arguments with [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) more flexible, and allows explicitly labeling what a certain argument value means. Technically named arguments work exactly like [keyword arguments](http://docs.python.org/tutorial/controlflow.html#keyword-arguments) in Python.
##### Basic syntax
It is possible to name an argument given to a keyword by prefixing the value with the name of the argument like `arg=value`. This is especially useful when multiple arguments have default values, as it is possible to name only some the arguments and let others use their defaults. For example, if a keyword accepts arguments `arg1=a, arg2=b, arg3=c`, and it is called with one argument `arg3=override`, arguments `arg1` and `arg2` get their default values, but `arg3` gets value `override`. If this sounds complicated, the [named arguments example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-example) below hopefully makes it more clear.
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 neither `Arg=value` nor `ARG=value` works. The latter means that spaces are not allowed before the `=` sign, and possible spaces after it are considered part of the given value.
When the named argument syntax is used with [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords), the argument names must be given without the `${}` decoration. For example, user keyword with arguments `${arg1}=first, ${arg2}=second` must be used like `arg2=override`.
Using normal positional arguments after named arguments like, for example, `| Keyword | arg=value | positional |`, does not work. The relative order of the named arguments does not matter.
##### Named arguments with variables
It is possible to use [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in both named argument names and values. If the value is a single [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable), it is passed to the keyword as-is. This allows using any objects, not only strings, as values also when using the named argument syntax. For example, calling a keyword like `arg=${object}` will pass the variable `${object}` to the keyword without converting it to a string.
If variables are used in named argument names, variables are resolved before matching them against argument names.
The named argument syntax requires the equal sign to be written literally in the keyword call. This means that variable alone can never trigger the named argument syntax, not even if it has a value like `foo=bar`. This is important to remember especially when wrapping keywords into other keywords. If, for example, a keyword takes a [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) like `@{args}` and passes all of them to another keyword using the same `@{args}` syntax, possible `named=arg` syntax used in the calling side is not recognized. This is illustrated by the example below.
```
*** Test Cases ***
Example
Run Program shell=True # This will not come as a named argument to Run Process
*** Keywords ***
Run Program
[Arguments] @{args}
Run Process program.py @{args} # Named arguments are not recognized from inside @{args}
```
If keyword needs to accept and pass forward any named arguments, it must be changed to accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments). See [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) for a wrapper keyword version that can pass both positional and named arguments forward.
##### Escaping named arguments syntax
The named argument syntax is used only when the part of the argument before the equal sign matches one of the keyword's arguments. It is possible that there is a positional argument with a literal value like `foo=quux`, and also an unrelated argument with name `foo`. In this case the argument `foo` either incorrectly gets the value `quux` or, more likely, there is a syntax error.
In these rare cases where there are accidental matches, it is possible to use the backslash character to [escape](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) the syntax like `foo\=quux`. Now the argument will get a literal value `foo=quux`. Note that escaping is not needed if there are no arguments with name `foo`, but because it makes the situation more explicit, it may nevertheless be a good idea.
##### Where named arguments are supported
As already explained, the named argument syntax works with keywords. In addition to that, it also works when [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries).
Naming arguments is supported by [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) and by most [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries). The only exceptions are Python keywords explicitly using [positional-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments).
##### Named arguments example
The following example demonstrates using the named arguments syntax with library keywords, user keywords, and when importing the [Telnet](https://robotframework.org/robotframework/latest/libraries/Telnet.html) test library.
```
*** Settings ***
Library Telnet prompt=$ default_log_level=DEBUG
*** Test Cases ***
Example
Open connection 10.0.0.42 port=${PORT} alias=example
List files options=-lh
List files path=/tmp options=-l
*** Keywords ***
List files
[Arguments] ${path}=. ${options}=
Execute command ls ${options} ${path}
```
#### [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-285)
Robot Framework supports *free named arguments*, often also called *free keyword arguments* or *kwargs*, similarly as [Python supports \*\*kwargs](http://docs.python.org/tutorial/controlflow.html#keyword-arguments). What this means is that a keyword can receive all arguments that use the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) (`name=value`) and do not match any arguments specified in the signature of the keyword.
Free named arguments are supported by same keyword types than [normal named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#where-named-arguments-are-supported). How keywords specify that they accept free named arguments depends on the keyword type. For example, [Python based keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-keyword-arguments-kwargs) simply use `**kwargs` and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords) use `&{kwargs}`.
Free named arguments support variables similarly as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-with-variables). In practice that means that variables can be used both in names and values, but the escape sign must always be visible literally. For example, both `foo=${bar}` and `${foo}=${bar}` are valid, as long as the variables that are used exist. An extra limitation is that free argument names must always be strings.
##### Examples
As the first example of using free named arguments, let's take a look at Run Process keyword in the [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library. It has a signature `command, *arguments, **configuration`, which means that it takes the command to execute (`command`), its arguments as [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) (`*arguments`) and finally optional configuration parameters as free named arguments (`**configuration`). The example below also shows that variables work with free keyword arguments exactly like when [using the named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments-with-variables).
```
*** Test Cases ***
Free Named Arguments
Run Process program.py arg1 arg2 cwd=/home/user
Run Process program.py argument shell=True env=${ENVIRON}
```
See [Free keyword arguments (\*\*kwargs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-keyword-arguments-kwargs) section under [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) for more information about using the free named arguments syntax in your custom test libraries.
As the second example, let's create a wrapper [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) for running the `program.py` in the above example. The wrapper keyword Run Program accepts all positional and named arguments and passes them forward to Run Process along with the name of the command to execute.
```
*** Test Cases ***
Free Named Arguments
Run Program arg1 arg2 cwd=/home/user
Run Program argument shell=True env=${ENVIRON}
*** Keywords ***
Run Program
[Arguments] @{args} &{config}
Run Process program.py @{args} &{config}
```
#### [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-286)
Keywords can accept arguments that must always be named using the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). If, for example, a keyword would accept a single named-only argument `example`, it would always need to be used like `example=value` and using just `value` would not work. This syntax is inspired by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102) syntax.
For most parts named-only arguments work the same way as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments). The main difference is that libraries implemented with Python 2 using the [static library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords) [do not support this syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-only-arguments).
As an example of using the [named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords), here is a variation of the Run Program in the above [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) that only supports configuring `shell`:
```
*** Test Cases ***
Named-only Arguments
Run Program arg1 arg2 # 'shell' is False (default)
Run Program argument shell=True # 'shell' is True
*** Keywords ***
Run Program
[Arguments] @{args} ${shell}=False
Run Process program.py @{args} shell=${shell}
```
#### [Arguments embedded to keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-287)
A totally different approach to specify arguments is embedding them into keyword names. This syntax is supported by both [test library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names) and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
### [2\.2.3 Failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-288)
#### [When test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-289)
A test case fails if any of the keyword it uses fails. Normally this means that execution of that test case is stopped, possible [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) is executed, and then execution continues from the next test case. It is also possible to use special [continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) if stopping test execution is not desired.
#### [Error messages](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-290)
The error message assigned to a failed test case is got directly from the failed keyword. Often the error message is created by the keyword itself, but some keywords allow configuring them.
In some circumstances, for example when continuable failures are used, a test case can fail multiple times. In that case the final error message is got by combining the individual errors. Very long error messages are [automatically cut from the middle](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports) to keep [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) easier to read, but full error messages are always visible in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as messages of the failed keywords.
By default error messages are normal text, but they can [contain HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#html-in-error-messages). This is enabled by starting the error message with marker string `*HTML*`. This marker will be removed from the final error message shown in reports and logs. Using HTML in a custom message is shown in the second example below.
```
*** Test Cases ***
Normal Error
Fail This is a rather boring example...
HTML Error
${number} = Get Number
Should Be Equal ${number} 42 *HTML* Number is not my <b>MAGIC</b> number.
```
### [2\.2.4 Test case name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-291)
The test case name comes directly from the Test Case section: 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatic-variables) `${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.
Starting from Robot Framework 3.2, possible [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in the test case name are resolved so that the final name will contain the variable value. If the variable does not exist, its name is left unchanged.
```
*** Variables ***
${MAX AMOUNT} ${5000000}
*** Test Cases ***
Amount cannot be larger than ${MAX AMOUNT}
# ...
```
The \[Documentation\] setting allows setting free form documentation for a test case. That text is shown in the command line output and in the resulting logs and reports. If documentation gets long, it can be [split into multiple rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows). It is possible to use simple [HTML formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) and [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can be used to make the documentation dynamic. Possible non-existing variables are left unchanged.
```
*** Test Cases ***
Simple
[Documentation] Simple and short documentation.
No Operation
Multiple lines
[Documentation] First row of the documentation.
...
... Documentation continues here. These rows form
... a paragraph when shown in HTML outputs.
No Operation
Formatting
[Documentation]
... This list has:
... - *bold*
... - _italics_
... - 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases).
### [2\.2.5 Tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-292)
Using tags in Robot Framework is a simple, yet powerful mechanism for classifying test cases and also [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). Tags are free text and Robot Framework itself has no special meaning for them except for the [reserved tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) discussed below. Tags can be used at least for the following purposes:
- They are shown in test [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file), [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) and, of course, in the test data, so they provide metadata to test cases.
- [Statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics) about test cases (total, passed, failed and skipped) are automatically collected based on them.
- They can be used to [include and exclude](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) as well as to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) test cases.
There are multiple ways how to specify tags for test cases explained below:
Test Tags setting in the Settings section
All tests in a test case file with this setting always get specified tags. If this setting is used in a [suite initialization file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files), all tests in child suites get these tags.
\[Tags\] setting with each test case
Tests get these tags in addition to tags specified using the Test Tags setting. The \[Tags\] setting also allows removing tags set with Test Tags by using the `-tag` syntax.
\--settag command line option
All tests get tags set with this option in addition to tags they got elsewhere.
Set Tags, Remove Tags, Fail and Pass Execution keywords
These [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords can be used to manipulate tags dynamically during the test execution.
Example:
```
*** Settings ***
Test Tags requirement: 42 smoke
*** Variables ***
${HOST} 10.0.1.42
*** Test Cases ***
No own tags
[Documentation] Test has tags 'requirement: 42' and 'smoke'.
No Operation
Own tags
[Documentation] Test has tags 'requirement: 42', 'smoke' and 'not ready'.
[Tags] not ready
No Operation
Own tags with variable
[Documentation] Test has tags 'requirement: 42', 'smoke' and 'host: 10.0.1.42'.
[Tags] host: ${HOST}
No Operation
Remove common tag
[Documentation] Test has only tag 'requirement: 42'.
[Tags] -smoke
No Operation
Remove common tag using a pattern
[Documentation] Test has only tag 'smoke'.
[Tags] -requirement: *
No Operation
Set Tags and Remove Tags keywords
[Documentation] This test has tags 'smoke', 'example' and 'another'.
Set Tags example another
Remove Tags requirement: *
```
As the example shows, tags can be created using variables, but otherwise they preserve the exact name used in the data. When tags are compared, for example, to collect statistics, to select test to be executed, or to remove duplicates, comparisons are case, space and underscore insensitive.
As demonstrated by the above examples, removing tags using `-tag` syntax supports [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) like `-requirement: *`. Tags starting with a hyphen have no special meaning otherwise than with the \[Tags\] setting. If there is a need to set a tag starting with a hyphen with \[Tags\], it is possible to use the [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) format like `\-tag`.
At the moment the `-tag` syntax can be used for removing tags only with the \[Tags\] setting, but the plan is to support this functionality also with the Test Tags setting in Robot Framework 8.0 ([\#5250](https://github.com/robotframework/robotframework/issues/5250)). Setting tags having a literal value that starts with a hyphen in Test Tags was deprecated in Robot Framework 7.2 ([\#5252](https://github.com/robotframework/robotframework/issues/5252)). The escaped format like `\-tag` can be used if tags with such values are needed.
Note
The Test Tags setting is new in Robot Framework 6.0. Earlier versions support Force Tags and Default Tags settings discussed in the next section.
Note
The `-tag` syntax for removing tags using the \[Tags\] setting is new in Robot Framework 7.0.
### [2\.2.6 Test setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-295)
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.
A setup and a 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) for that purpose. An alternative solution is executing multiple keywords using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keywords.
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. In addition, all the keywords in the teardown are also executed even if one of them fails. This [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section. Individual test cases can also have their own setup or teardown. They are defined with the \[Setup\] or \[Teardown\] settings in the test case section 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. It is also possible to use value `NONE` to indicate that a test has no setup/teardown.
```
*** Settings ***
Test Setup Open Application App A
Test Teardown Close Application
*** Test Cases ***
Default values
[Documentation] Setup and teardown from setting section
Do Something
Overridden setup
[Documentation] Own setup, teardown from setting section
[Setup] Open Application App B
Do Something
No teardown
[Documentation] Default setup, no teardown at all
Do Something
[Teardown]
No teardown 2
[Documentation] Setup and teardown can be disabled also with special value NONE
Do Something
[Teardown] NONE
Using variables
[Documentation] Setup and teardown specified using variables
[Setup] ${SETUP}
Do Something
[Teardown] ${TEARDOWN}
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). 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.7 Test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-296)
Test templates convert normal [keyword-driven](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-driven-style) test cases into [data-driven](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) tests. Whereas the body of a keyword-driven test case is constructed from keywords and their possible arguments, test cases with template contain only the arguments for the template keyword. Instead of repeating the same keyword multiple times per test and/or with all tests in a file, it is possible to use it only per test or just once per file.
Template keywords can accept both normal positional and named arguments, as well as arguments embedded to the keyword name. Unlike with other settings, it is not possible to define a template using a variable.
#### [Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-297)
How a keyword accepting normal positional arguments can be used as a template is illustrated by the following example test cases. These two tests are functionally fully identical.
```
*** Test Cases ***
Normal test case
Example keyword first argument second argument
Templated test case
[Template] Example keyword
first argument second argument
```
As the example 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 section, 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 section, and an empty value for \[Template\] means that the test has no template even when Test Template is used. It is also possible to use value `NONE` to indicate that a test has no template.
Using keywords with [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) or accepting [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments), as well as using [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) and [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments), work with templates exactly like they work otherwise. Using [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) in arguments is also supported normally.
#### [Templates with multiple iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-298)
If a templated test case has multiple data rows in its body, the template is applied for all the rows one by one. This means that the same keyword is executed multiple times, once with data on each row.
```
*** Settings ***
Test Template Example keyword
*** Test Cases ***
Templated test case
first round 1 first round 2
second round 1 second round 2
third round 1 third round 2
```
Templated tests are special so that all iterations are executed even if one or more of them is failed or skipped. The aggregated result of a templated test with multiple iterations is:
- FAIL if any of the iterations failed.
- PASS if there were no failures and at least one iteration passed.
- SKIP if all iterations were skipped.
Note
It is possible to use the [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) mode also with normal tests, but with the templated tests the mode is on automatically. If needed, the mode can also be [disabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags) with templates by using the `robot:stop-on-failure` tag.
Note
Running all iterations if one or more is skipped is new in Robot Framework 7.2. With earlier versions the execution stopped for the first skipped iteration and the test got the SKIP status regardless of the status of the earlier iterations.
#### [Templates with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-299)
Templates support a variation of the [embedded argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-argument-syntax). With templates this syntax works so that if the template keyword has variables in its name, they are considered placeholders for arguments and replaced with the actual arguments used with the template. The resulting keyword is then used without positional arguments. This is best illustrated with an example:
```
*** Test Cases ***
Normal test case with embedded arguments
The result of 1 + 1 should be 2
The result of 1 + 2 should be 3
Template with embedded arguments
[Template] The result of ${calculation} should be ${expected}
1 + 1 2
1 + 2 3
*** Keywords ***
The result of ${calculation} should be ${expected}
${result} = Calculate ${calculation}
Should Be Equal ${result} ${expected}
```
When embedded arguments are used with templates, the number of arguments in the template keyword name must match the number of arguments it is used with. The argument names do not need to match the arguments of the original keyword, though, and it is also possible to use different arguments altogether:
```
*** Test Cases ***
Different argument names
[Template] The result of ${foo} should be ${bar}
1 + 1 2
1 + 2 3
Only some arguments
[Template] The result of ${calculation} should be 3
1 + 2
4 - 1
New arguments
[Template] The ${meaning} of ${life} should be 42
result 21 * 2
```
The main benefit of using embedded arguments with templates is that argument names are specified explicitly. When using normal arguments, the same effect can be achieved by naming the columns that contain arguments. This is illustrated by the [data-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) example in the next section.
#### [Templates with `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-300)
If templates are used with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
Template with FOR loop
[Template] Example keyword
FOR ${item} IN @{ITEMS}
${item} 2nd arg
END
FOR ${index} IN RANGE 42
1st arg ${index}
END
```
#### [Templates with `IF/ELSE` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-301)
[IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) can be also used together with templates. This can be useful, for example, when used together with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) to filter executed arguments.
```
*** Test Cases ***
Template with FOR and IF
[Template] Example keyword
FOR ${item} IN @{ITEMS}
IF ${item} < 5
${item} 2nd arg
END
END
```
### [2\.2.8 Different test case styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-302)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-303)
Workflow tests, such as the Valid Login test described [earlier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-tests), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-304)
Another style to write test cases is the *data-driven* approach where test cases use only one higher-level keyword, often created as a [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) functionality allows specifying the keyword to use only once.
```
*** Settings ***
Test Template Login with invalid credentials should fail
*** Test Cases *** USERNAME PASSWORD
Invalid User Name invalid ${VALID PASSWORD}
Invalid Password ${VALID USER} invalid
Invalid User Name and Password invalid invalid
Empty User Name ${EMPTY} ${VALID PASSWORD}
Empty Password ${VALID USER} ${EMPTY}
Empty User Name and Password ${EMPTY} ${EMPTY}
```
Tip
Naming columns like in the example above makes tests easier to understand. This is possible because on the header row other cells except the first one [are ignored](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections).
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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}
```
#### [Behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-305)
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](https://en.wikipedia.org/wiki/Acceptance_test-driven_development) (ATDD) or [Specification by Example](http://en.wikipedia.org/wiki/Specification_by_example).
One way to write these requirements/tests is *Given-When-Then* style popularized by [Behavior Driven Development](http://en.wikipedia.org/wiki/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 or But may be used if a step has more than one action.
```
*** Test Cases ***
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/But prefixes
Prefixes Given, When, Then, And and But can be omitted when creating keywords. For example, Given login page is open in the above example is typically implemented without the word Given so that the name is just Login page is open. Omitting prefixes allows using the same keyword with different prefixes. For example, Welcome page should be open could be used as Then welcome page should be open or and welcome page should be open.
Note
These prefixes can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
##### Embedding data to keywords
When writing concrete examples it is useful to be able to pass actual data to keyword implementations. This can be done by [embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
## [2\.3 Creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-251)
In addition to test automation, Robot Framework can be used for other automation purposes, including [robotic process automation](https://en.wikipedia.org/wiki/Robotic_process_automation) (RPA). It has always been possible, but Robot Framework 3.1 added official support for automating *tasks*, not only tests. For most parts creating tasks works the same way as [creating tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tests) and the only real difference is in terminology. Tasks can also be organized into [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-suites) exactly like test cases.
- [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-syntax)
- [2\.3.2 Task related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-settings)
### [2\.3.1 Task syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-306)
Tasks are created based on the available keywords exactly like test cases, and the task syntax is in general identical to the [test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax). The main difference is that tasks are created in Task sections instead of Test Case sections:
```
*** Tasks ***
Process invoice
Read information from PDF
Validate information
Submit information to backend system
Validate information is visible in web UI
```
It is an error to have both tests and tasks in same file.
## [2\.4 Creating test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-252)
Robot Framework [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) are created in test case files, which can be organized into directories. These files and directories create a hierarchical test suite structure. Same concepts apply also when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks), but the terminology differs.
- [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files)
- [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories)
- [Suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files)
- [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name)
- [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation)
- [2\.4.5 Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata)
- [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown)
### [2\.4.1 Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-308)
Robot Framework test cases [are created](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-cases) using test case sections in suite files, also known as 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#data-driven-style) is used, where one test case consists of only one high-level keyword.
The following settings in the Setting section can be used to customize the suite:
Name
Used for setting a custom [suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name). The default name is created based on the file or directory name.
Documentation
Used for specifying a [suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation).
Metadata
Used for setting [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) as name-value pairs.
Suite Setup, Suite Teardown
Specify [suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown).
Note
Setting names are case-insensitive, but the format used above is recommended.
### [2\.4.2 Suite directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-309)
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 in [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) are processed.
- Other files are ignored.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)) and the processing continues.
#### [Suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-310)
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 suite initialization file. An initialization file name must always be of the format \_\_init\_\_.ext, where the extension must be one of the [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) (typically \_\_init\_\_.robot). The name format is borrowed from Python, where files named in this manner denote that a directory is a module.
Starting from Robot Framework 6.1, it is also possible to define a suite initialization file for automatically created suite when starting the test execution by giving multiple [paths](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-executed).
Initialization files have the same structure and syntax as test case files, except that they cannot have test case sections and not all settings are supported. Variables and keywords created or imported in initialization files *are not* available in the lower level suites. If you need to share variables or keywords, you can put them into [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) that can be imported both by initialization and test case files.
The main usage for initialization files is specifying suite related settings similarly as in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), but setting some [test case related settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-related-settings-in-the-setting-section) is also possible. How to use different settings in the initialization files is explained below.
Name, Documentation, Metadata, Suite Setup, Suite Teardown
These suite specific settings work the same way in suite initialization files as in suite files.
Test Tags
Specified tags are unconditionally set to all tests in all suite files this directory contains, recursively. New in Robot Framework 6.1. The deprecated Force Tags needs to be used with older versions.
Test Setup, Test Teardown, Test Timeout
Set the default value for test setup/teardown or test timeout to all test cases this directory contains. Can be overridden on lower level. Notice that keywords used as setups and teardowns must be available in test case files where tests using them are. Defining keywords in the initialization file itself is not enough.
Task Setup, Task Teardown, Task Tags, Task Timeout
Aliases for Test Setup, Test Teardown, Test Tags and Test Timeout, respectively, that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks), not tests.
Test Template, Default Tags
Not supported in initialization files.
```
*** Settings ***
Documentation Example suite
Suite Setup Do Something ${MESSAGE}
Test Tags example
Library SomeLibrary
*** Variables ***
${MESSAGE} Hello, world!
*** Keywords ***
Do Something
[Arguments] ${args}
Some Keyword ${arg}
Another Keyword
```
Note
When you run a suite file or directory, possible suite initialization files in higher level directories are not taken into account. If that is not desired, run the appropriate higher level suite directory and use the [\--suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) option to select which child suite inside it is executed.
### [2\.4.3 Suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-311)
The test suite name is constructed from the file or directory name by default. 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.robot becomes Some Tests and My\_test\_directory becomes My test directory.
The file or directory name can contain a prefix to control the [execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.robot and 02\_\_more\_tests.robot create test suites Some Tests and More Tests, respectively, and the former is executed before the latter.
Starting from Robot Framework 6.1, it is also possible to give a custom name to a suite by using the Name setting in the Setting section:
```
*** Settings ***
Name Custom suite name
```
The name of the top-level suite [can be overridden](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) from the command line with the \--name option.
### [2\.4.4 Suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-312)
The documentation for a test suite is set using the Documentation setting in the Settings section. It can be used both in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and in [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files). Suite documentation has exactly the same characteristics regarding to where it is shown and how it can be created as [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). For details about the syntax see the [Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) appendix.
```
*** Settings ***
Documentation An example suite documentation with *some* _formatting_.
... Long documentation can be split into multiple lines.
```
The documentation of the top-level suite [can be overridden](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) from the command line with the \--doc option.
### [2\.4.6 Suite setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-314)
Not only [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) 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 suite 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 [suite initialization file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files).
Similarly as with test cases, a suite setup and teardown are keywords that may take arguments. They are defined in the Setting section with Suite Setup and Suite Teardown settings, respectively. 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. Note that 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\.5 Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-253)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). This section explains how to take test libraries into use and how to use the keywords they provide. [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) is described in a separate section.
- [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries)
- [Using `Library` setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-library-setting)
- [Using `Import Library` keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-import-library-keyword)
- [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import)
- [Using library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-library-name)
- [Using physical path to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-physical-path-to-library)
- [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library)
- [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries)
- [Normal standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#normal-standard-libraries)
- [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library)
- [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries)
### [2\.5.1 Importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-315)
Test libraries are typically imported using the Library setting, but it is also possible to use the Import Library keyword.
#### [Using `Library` setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-316)
Libraries are normally imported in the Settings section using the Library setting with the library name or path as its value. Unlike most of the other data, the library name or path is both case- and space-sensitive. If a library is in a package, the full name including the 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-arguments). Both the library name and arguments can be set using variables.
```
*** Settings ***
Library OperatingSystem
Library path/to/MyLibrary.py
Library my.package.TestLibrary
Library LibraryAcceptingArguments arg1 arg2
Library ${LIBRARY}
```
It is possible to import test libraries in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-317)
Another possibility to take a test library into use is using the keyword Import Library from the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library. This keyword takes the library name or path 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.
```
*** Test Cases ***
Example
Do Something
Import Library MyLibrary arg1 arg2
KW From MyLibrary
```
### [2\.5.2 Specifying library to import](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-318)
Libraries to import can be specified either by using the library name or the path to the library. These approaches work the same way regardless if the library is imported using the Library setting or the Import Library keyword.
#### [Using library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-319)
The most common way to specify a test library to import is using its name. In these cases Robot Framework tries to find the class or module implementing the library from the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). Libraries that are installed somehow ought to be in the module search path automatically, but with other libraries the search path may need to be configured separately.
```
*** Settings ***
Library OperatingSystem
Library CustomLibrary possible arguments
Library librarymodule.LibraryClass
```
The biggest benefit of this approach is that when the module search path has been configured, often using a custom [start-up script](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-320)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files). The main benefit of this approach is that there is no need to configure the module search path.
If the library is a file, the path to it must contain extension, i.e. .py. If a library is implemented as a directory, the path to it must have a trailing forward slash (`/`) if the path is relative. With absolute paths the trailing slash is optional. Following examples demonstrate these different usages.
```
*** Settings ***
Library PythonLibrary.py
Library relative/path/PythonDirLib/ possible arguments
Library ${RESOURCES}/Example.py
```
### [2\.5.3 Setting custom name to library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-321)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names). 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.
- 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 `AS` (case-sensitive) after the library name and then having the new name after that. The specified name is shown in logs and must be used in the test data when using keywords' full name (LibraryName.Keyword Name).
```
*** Settings ***
Library packagename.TestLib AS TestLib
Library ${LIBRARY} AS MyName
```
Possible arguments to the library are placed between the original library name and the `AS` marker. The following example illustrates how the same library can be imported several times with different arguments:
```
*** Settings ***
Library SomeLibrary localhost 1234 AS LocalLib
Library SomeLibrary server.domain 8080 AS RemoteLib
*** Test Cases ***
Example
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 section and when using the Import Library keyword.
Note
Prior to Robot Framework 6.0 the marker to use when giving a custom name to a library was `WITH NAME` instead of `AS`. The old syntax continues to work, but it is considered deprecated and will eventually be removed.
### [2\.5.4 Standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-322)
Some test libraries are distributed with Robot Framework and these libraries are called *standard libraries*. The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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.
#### [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-324)
In addition to the normal standard libraries listed above, there is also Remote library that 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface) section for more information about this concept.
### [2\.5.5 External libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-325)
Any test library that is not one of the standard libraries is, by definition, *an external library*. The Robot Framework open source community has implemented several generic libraries, such as [SeleniumLibrary](https://github.com/robotframework/SeleniumLibrary) and [SwingLibrary](https://github.com/robotframework/SwingLibrary), which are not packaged with the core framework. A list of publicly available libraries can be found from [http://robotframework.org](http://robotframework.org/).
Generic and custom libraries can obviously also be implemented by teams using Robot Framework. See [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) section for more information about that topic.
Different external libraries can have a totally different mechanism for installing them and taking them into use. Sometimes they may also require some other dependencies to be installed separately. All libraries should have clear installation and usage documentation and they should preferably automate the installation process.
## [2\.6 Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-254)
- [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-1)
- [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables)
- [Scalar variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable-syntax)
- [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable-syntax)
- [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable-syntax)
- [Accessing list and dictionary items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-list-and-dictionary-items)
- [Environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables)
- [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-variables)
- [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section)
- [Using variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variable-files)
- [Command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables)
- [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords)
- [`VAR` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax)
- [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords)
- [Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion)
- [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables)
- [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables)
- [Operating-system variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#operating-system-variables)
- [Number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#number-variables)
- [Boolean and None/null variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-and-none-null-variables)
- [Space and empty variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#space-and-empty-variables)
- [Automatic variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatic-variables)
- [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes)
- [Variable priorities](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities)
- [Variable scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-scopes)
- [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#advanced-variable-features)
- [Extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax)
- [Extended variable assignment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-assignment)
- [Variables inside variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables-inside-variables)
- [Inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation-1)
### [2\.6.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-326)
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 and Keyword sections, but also all settings allow variables in their values. A normal keyword name *cannot* be specified with a variable, but the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword can be used to get the same effect.
Robot Framework has its own variables that can be used as [scalars](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) or [dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variables) using syntax `${SCALAR}`, `@{LIST}` and `&{DICT}`, respectively. In addition to this, [environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables) can be used directly with syntax `%{ENV_VAR}`.
Variables are useful, for example, in these cases:
- When values used in multiple places in the data change often. When using variables, you only need to make changes in one place where the variable is defined.
- When creating system-independent and operating-system-independent data. Using variables instead of hard-coded values 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) when tests are started, changing system-specific variables is easy (for example,
```
--variable RESOURCES:/opt/resources
--variable HOST:10.0.0.2:1234
```
). This also facilitates localization testing, which often involves running the same tests with different localized strings.
- When there is a need to have objects other than strings as arguments for keywords. This is not possible without variables, unless keywords themselves support argument conversion.
- When different keywords, even in different test libraries, need to communicate. You can assign a return value from one keyword to a variable and pass it as an argument to another.
- When values in the test data are long or otherwise complicated. For example, using `${URL}` is more convenient than using something like `http://long.domain.name:8080/path/to/service?foo=1&bar=2&zap=42`.
If a non-existent 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) as in `\${NAME}`.
### [2\.6.2 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-327)
This section explains how to use variables using the normal scalar variable syntax `${var}`, how to expand lists and dictionaries like `@{var}` and `&{var}`, respectively, and how to use environment variables like `%{var}`. Different ways how to create variables are discussed in the next section.
Robot Framework variables, similarly as keywords, are case-insensitive, and also spaces and underscores are ignored. However, it is recommended to use capital letters with global variables (for example, `${PATH}` or `${TWO WORDS}`) and small letters with local variables that are only available in certain test cases or user keywords (for example, `${my var}`). Much more importantly, though, case should be used consistently.
A variable name, such as `${example}`, consists of the variable identifier (`$`, `@`, `&`, `%`), curly braces (`{`, `}`), and the base name between the braces. When creating variables, there may also be a [variable type definition](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) after the base name like `${example: int}`.
The variable base name can contain any characters. It is, however, highly recommended to use only alphabetic characters, numbers, underscores and spaces. That is a requirement for using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) already now and in the future that may be required with all variables.
#### [Scalar variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-328)
The most common way to use variables in Robot Framework test data is using the scalar variable syntax like `${var}`. When this syntax is used, the variable name is replaced with its value as-is. Most of the time variable values are strings, but variables can contain any object, including numbers, lists, dictionaries, or even custom objects.
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, these two example test cases are equivalent:
```
*** Test Cases ***
Constants
Log Hello
Log Hello, world!!
Variables
Log ${GREET}
Log ${GREET}, ${NAME}!!
```
When a scalar variable is used alone without any text or other variables around it, like in `${GREET}` above, the variable is replaced with its value as-is and the value can be any object. If the variable is not used alone, like `${GREER}, ${NAME}!!` above, its value is first converted into a string and then concatenated with the other data.
Note
Variable values are used as-is without string conversion also when passing arguments to keywords using the [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) syntax like `argname=${var}`.
The example below demonstrates the difference between having a variable in alone or with other content. First, let us assume that we have a variable `${STR}` set to a string and `${OBJ}` set to an instance of the following Python object:
```
class MyObj:
def __str__(self):
return "Hi, terra!"
```
With these two variables set, we then have the following test data:
```
*** Test Cases ***
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, terra!"`
##### Scalar variables containing bytes
Variables containing [bytes](https://docs.python.org/3/library/stdtypes.html#bytes-objects) or [bytearrays](https://docs.python.org/3/library/stdtypes.html#bytearray-objects) are handled slightly differently than other variables containing non-string values:
- If they are used alone, everything works exactly as with other objects and their values are passed to keywords as-is.
- If they are concatenated only with other variables that also contain bytes or bytearrays, the result is bytes instead of a string.
- If they are concatenated with strings or with variables containing other types than bytes or bytearrays, they are converted to strings like other objects, but they have a different string representation than they normally have in Python. With Python the string representation contains surrounding quotes and a `b` prefix like `b'\x00'`, but with Robot Framework quotes and the prefix are omitted, and each byte is mapped to a Unicode code point with the same ordinal. In practice this is same as converting bytes to strings using the Latin-1 encoding. This format has a big benefit that the resulting string can be converted back to bytes, for example, by using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Convert To Bytes or by automatic [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion).
The following examples demonstrates using bytes and bytearrays would work exactly the same way. Variable `${a}` is expected to contain bytes `\x00\x01` and variable `${b}` bytes `a\xe4`.
```
*** Test Cases ***
Bytes alone
[Documentation] Keyword gets bytes '\x00\x01'.
Keyword ${a}
Bytes concatenated with bytes
[Documentation] Keyword gets bytes '\x00\x01a\xe4'.
Keyword ${a}${b}
Bytes concatenated with others
[Documentation] Keyword gets string '=\x00\x01a\xe4='.
Keyword =${a}${b}=
```
Note
Getting bytes when variables containing bytes are concatenated is new in Robot Framework 7.2. With earlier versions the result was a string.
Note
All bytes being mapped to matching Unicode code points in string representation is new Robot Framework 7.2. With earlier versions, only bytes in the ASCII range were mapped directly to code points and other bytes were represented in an escaped format.
#### [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-329)
When a variable is used as a scalar like `${EXAMPLE}`, its value is be used as-is. If a variable value is a list or list-like, it is also possible to use it as a list variable like `@{EXAMPLE}`. In this case the list is expanded and individual items are passed in as separate arguments.
This is easiest to explain with an example. Assuming that a variable `${USER}` contains a list with two items `robot` and `secret`, the first two of these tests are equivalent:
```
*** Test Cases ***
Constants
Login robot secret
List variable
Login @{USER}
List as scalar
Keyword ${USER}
```
The third test above illustrates that a variable containing a list can be used also as a scalar. In that test the keyword gets the whole list as a single argument.
Starting from Robot Framework 4.0, list expansion can be used in combination with [list item access](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-sequence-items) making these usages possible:
```
*** Test Cases ***
Nested container
${nested} = Evaluate [['a', 'b', 'c'], {'key': ['x', 'y']}]
Log Many @{nested}[0] # Logs 'a', 'b' and 'c'.
Log Many @{nested}[1][key] # Logs 'x' and 'y'.
Slice
${items} = Create List first second third
Log Many @{items}[1:] # Logs 'second' and 'third'.
```
##### Using list variables with other data
It is possible to use list variables with other arguments, including other list variables.
```
*** Test Cases ***
Example
Keyword @{LIST} more args
Keyword ${SCALAR} @{LIST} constant
Keyword @{LIST} @{ANOTHER} @{ONE MORE}
```
##### Using list variables with settings
List variables can be used only with some of the [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-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.
```
*** Settings ***
Library ExampleLibrary @{LIB ARGS} # This works
Library ${LIBRARY} @{LIB ARGS} # This works
Library @{LIBRARY AND ARGS} # This does not work
Suite Setup Some Keyword @{KW ARGS} # This works
Suite Setup ${KEYWORD} @{KW ARGS} # This works
Suite Setup @{KEYWORD AND ARGS} # This does not work
Test Tags @{TAGS} # This works
```
#### [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-330)
As discussed above, a variable containing a list can be used as a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) to pass list items to a keyword as individual arguments. Similarly, a variable containing a Python dictionary or a dictionary-like object can be used as a dictionary variable like `&{EXAMPLE}`. In practice this means that the dictionary is expanded and individual items are passed as [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) to the keyword. Assuming that a variable `&{USER}` has a value `{'name': 'robot', 'password': 'secret'}`, the first two test cases below are equivalent:
```
*** Test Cases ***
Constants
Login name=robot password=secret
Dictionary variable
Login &{USER}
Dictionary as scalar
Keyword ${USER}
```
The third test above illustrates that a variable containing a dictionary can be used also as a scalar. In that test the keyword gets the whole dictionary as a single argument.
Starting from Robot Framework 4.0, dictionary expansion can be used in combination with [dictionary item access](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#accessing-individual-dictionary-items) making usages like `&{nested}[key]` possible.
##### Using dictionary variables with other data
It is possible to use dictionary variables with other arguments, including other dictionary variables. Because [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) requires positional arguments to be before named argument, dictionaries can only be followed by named arguments or other dictionaries.
```
*** Test Cases ***
Example
Keyword &{DICT} named=arg
Keyword positional @{LIST} &{DICT}
Keyword &{DICT} &{ANOTHER} &{ONE MORE}
```
##### Using dictionary variables with settings
Dictionary variables cannot generally be used with settings. The only exception are imports, setups and teardowns where dictionaries can be used as arguments.
```
*** Settings ***
Library ExampleLibrary &{LIB ARGS}
Suite Setup Some Keyword &{KW ARGS} named=arg
```
#### [Accessing list and dictionary items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-331)
It is possible to access items of subscriptable variables, e.g. lists and dictionaries, using special syntax like `${var}[item]` or `${var}[nested][item]`. Starting from Robot Framework 4.0, it is also possible to use item access together with [list expansion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-expansion) and [dictionary expansion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-expansion) by using syntax `@{var}[item]` and `&{var}[item]`, respectively.
Note
Prior to Robot Framework 3.1, the normal item access syntax was `@{var}[item]` with lists and `&{var}[item]` with dictionaries. Robot Framework 3.1 introduced the generic `${var}[item]` syntax along with some other nice enhancements and the old item access syntax was deprecated in Robot Framework 3.2.
##### Accessing sequence items
It is possible to access a certain item of a variable containing a [sequence](https://docs.python.org/3/glossary.html#term-sequence) (e.g. list, string or bytes) with the syntax `${var}[index]`, where `index` is the index of the selected value. Indices start from zero, negative indices can be used to access items from the end, and trying to access an item with too large an index causes an error. Indices are automatically converted to integers, and it is also possible to use variables as indices.
```
*** Test Cases ***
Positive index
Login ${USER}[0] ${USER}[1]
Title Should Be Welcome ${USER}[0]!
Negative index
Keyword ${SEQUENCE}[-1]
Index defined as variable
Keyword ${SEQUENCE}[${INDEX}]
```
Sequence item access supports also the [same "slice" functionality as Python](https://docs.python.org/glossary.html#term-slice) with syntax like `${var}[1:]`. With this syntax, you do not get a single item, but a *slice* of the original sequence. Same way as with Python, you can specify the start index, the end index, and the step:
```
*** Test Cases ***
Start index
Keyword ${SEQUENCE}[1:]
End index
Keyword ${SEQUENCE}[:4]
Start and end
Keyword ${SEQUENCE}[2:-1]
Step
Keyword ${SEQUENCE}[::2]
Keyword ${SEQUENCE}[1:-1:10]
```
Note
Prior to Robot Framework 3.2, item and slice access was only supported with variables containing lists, tuples, or other objects considered list-like. Nowadays all sequences, including strings and bytes, are supported.
##### Accessing individual dictionary items
It is possible to access a certain value of a dictionary variable with the syntax `${NAME}[key]`, where `key` is the name of the selected value. Keys are considered to be strings, but non-strings keys can be used as variables. Dictionary values accessed in this manner can be used similarly as scalar variables.
If a dictionary is created in Robot Framework data, it is possible to access values also using the attribute access syntax like `${NAME.key}`. See the [Creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) section for more details about this syntax.
```
*** Test Cases ***
Dictionary variable item
Login ${USER}[name] ${USER}[password]
Title Should Be Welcome ${USER}[name]!
Key defined as variable
Log Many ${DICT}[${KEY}] ${DICT}[${42}]
Attribute access
Login ${USER.name} ${USER.password}
Title Should Be Welcome ${USER.name}!
```
##### Nested item access
Also nested subscriptable variables can be accessed using the same item access syntax like `${var}[item1][item2]`. This is especially useful when working with JSON data often returned by REST services. For example, if a variable `${DATA}` contains , this tests would pass:
```
*** Test Cases ***
Nested item access
Should Be Equal ${DATA}[0][name] Robot
Should Be Equal ${DATA}[1][id] ${2}
```
#### [Environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-332)
Robot Framework allows using environment variables in the test data using the syntax `%{ENV_VAR_NAME}`. They are limited to string values. It is possible to specify a default value, that is used if the environment variable does not exists, by separating the variable name and the default value with an equal sign like `%{ENV_VAR_NAME=default value}`.
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](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) 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.
```
*** Test Cases ***
Environment variables
Log Current user: %{USER}
Run %{JAVA_HOME}${/}javac
Environment variable with default
Set Port %{APPLICATION_PORT=8080}
```
Note
Support for specifying the default value is new in Robot Framework 3.2.
### [2\.6.3 Creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-333)
Variables can be created using different approaches discussed in this section:
- In the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section)
- Using [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- On the [command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables)
- Based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords)
- Using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax)
- Using [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords)
In addition to this, there are various automatically available [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) and also [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) create variables. In most places where variables are created, it is possible to use [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) to easily create variables with non-string values. An important application for conversions is creating [secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables).
#### [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-334)
The most common source for variables are Variable sections in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files). Variable sections 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 variables cannot be created dynamically. If that is a problem, [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) can be used instead.
##### Creating scalar values
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 section 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.
```
*** Variables ***
${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.
```
*** Variables ***
${NAME} = Robot Framework
${VERSION} = 2.0
```
If a scalar variable has a long value, it can be [split into multiple rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) by using the `...` syntax. By default rows are concatenated together using a space, but this can be changed by using a `separator` configuration option after the last value:
```
*** Variables ***
${EXAMPLE} This value is joined
... together with a space.
${MULTILINE} First line.
... Second line.
... Third line.
... separator=\n
```
The `separator` option is new in Robot Framework 7.0, but also older versions support configuring the separator. With them the first value can contain a special `SEPARATOR` marker:
```
*** Variables ***
${MULTILINE} SEPARATOR=\n
... First line.
... Second line.
... Third line.
```
Both the `separator` option and the `SEPARATOR` marker are case-sensitive. Using the `separator` option is recommended, unless there is a need to support also older versions.
##### Creating lists
Creating lists is as easy as creating scalar values. Again, the variable name is in the first column of the Variable section and values in the subsequent columns, but this time the variable name must start with `@` instead of `$`. A list can have any number of items, including zero, and items can be [split into several rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) if needed.
```
*** Variables ***
@{NAMES} Matti Teppo
@{NAMES2} @{NAMES} Seppo
@{NOTHING}
@{MANY} one two three four
... five six seven
```
Note
As discussed in the [List variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable-syntax) section, variables containing lists can be used as scalars like `${NAMES}` and by using the list expansion syntax like `@{NAMES}`.
##### Creating dictionaries
Dictionaries can be created in the Variable section similarly as lists. The differences are that the name must now start with `&` and that items need to be created using the `name=value` syntax or based on existing dictionary variables. If there are multiple items with same name, the last value has precedence. If a name contains a literal equal sign, it can be [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with a backslash like `\=`.
```
*** Variables ***
&{USER 1} name=Matti address=xxx phone=123
&{USER 2} name=Teppo address=yyy phone=456
&{MANY} first=1 second=${2} ${3}=third
&{EVEN MORE} &{MANY} first=override empty=
... =empty key\=here=value
```
Note
As discussed in the [Dictionary variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable-syntax) section, variables containing dictionaries can be used as scalars like `${USER 1}` and by using the dictionary expansion syntax like `&{USER 1}`.
Unlike with normal Python dictionaries, values of dictionaries created using this syntax can be accessed as attributes, which means that it is possible to use [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${VAR.key}`. This only works if the key is a valid attribute name and does not match any normal attribute Python dictionaries have, though. For example, individual value `${USER}[name]` can also be accessed like `${USER.name}`, but using `${MANY.3}` is not possible.
Tip
With nested dictionaries keys are accessible like `${DATA.nested.key}`.
Dictionaries are also ordered. This means that if they are iterated, their items always come in the order they are defined. This can be useful, for example, if dictionaries are used as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) or otherwise. When a dictionary is used as a list variable, the actual value contains dictionary keys. For example, `@{MANY}` variable would have a value .
##### Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the variable name dynamically based on another variable:
```
*** Variables ***
${X} Y
${${X}} Z # Name is created based on '${X}'.
*** Test Cases ***
Dynamically created name
Should Be Equal ${Y} Z
```
#### [Using variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-335)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files).
#### [Command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-336)
Variables can be set from the command line either individually with the \--variable (-v) option or using the aforementioned variable files 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 section and in variable files imported in the Setting section.
The syntax for setting individual variables is \--variable name:value, where `name` is the name of the variable without the `${}` decoration and `value` is its value. Several variables can be set by using this option several times.
```
--variable EXAMPLE:value
--variable HOST:localhost:7272 --variable USER:robot
```
In the examples above, variables are set so that:
- `${EXAMPLE}` gets value `value`, and
- `${HOST}` and `${USER}` get values `localhost:7272` and `robot`, respectively.
The basic syntax for taking [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) into use from the command line is \--variablefile path/to/variables.py and the [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use) section explains this more thoroughly. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes).
#### [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-337)
Return values from keywords can also be assigned into variables. This allows communication between different keywords even in different libraries by passing created variables forward as arguments to other keywords.
Variables set in this manner are otherwise similar to any other variables, but they are available only in the [local scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#local-scope) where they are created. Thus it is not possible, for example, to set a variable like this 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 the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords) as explained in the subsequent sections.
##### Assigning scalar variables
Any value returned by a keyword can be assigned to a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable). As illustrated by the example below, the required syntax is very simple:
```
*** Test Cases ***
Returning
${x} = Get X an argument
Log We got ${x}!
```
In the above example the value returned by the Get X keyword is first set into the variable `${x}` and then used by the Log keyword. Having the equals sign `=` after the name of the assigned variable is not obligatory, but it makes the assignment more explicit. Creating local variables like this works both in test case and user keyword level.
Notice that although a value is assigned to a scalar variable, it can be used as a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) if it has a list-like value and as a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) if it has a dictionary-like value.
```
*** Test Cases ***
List assigned to scalar variable
${list} = Create List first second third
Length Should Be ${list} 3
Log Many @{list}
```
##### Assigning variable items
Starting from Robot Framework 6.1, when working with variables that support item assignment such as lists or dictionaries, it is possible to set their values by specifying the index or key of the item using the syntax `${var}[item]` where the `item` part can itself contain a variable:
```
*** Test Cases ***
List item assignment
${list} = Create List one two three four
${list}[0] = Set Variable first
${list}[${1}] = Set Variable second
${list}[2:3] = Create List third
${list}[-1] = Set Variable last
Log Many @{list} # Logs 'first', 'second', 'third' and 'last'
Dictionary item assignment
${dict} = Create Dictionary first_name=unknown
${dict}[first_name] = Set Variable John
${dict}[last_name] = Set Variable Doe
Log ${dictionary} # Logs {'first_name': 'John', 'last_name': 'Doe'}
```
##### Creating variable name based on another variable
Starting from Robot Framework 7.0, it is possible to create the name of the assigned variable dynamically based on another variable:
```
*** Test Cases ***
Dynamically created name
${x} = Set Variable y
${${x}} = Set Variable z # Name is created based on '${x}'.
Should Be Equal ${y} z
```
##### Assigning list variables
If a keyword returns a list or any list-like object, it is possible to assign it to a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable):
```
*** Test Cases ***
Assign to list variable
@{list} = Create List first second third
Length Should Be ${list} 3
Log Many @{list}
```
Because all Robot Framework variables are stored in the same namespace, there is not much difference between assigning a value to a scalar variable or a list variable. This can be seen by comparing the above example with the earlier example with the `List assigned to scalar variable` test case. The main differences are that when creating a list variable, Robot Framework automatically verifies that the value is a list or list-like, and the stored variable value will be a new list created from the return value. When assigning to a scalar variable, the return value is not verified and the stored value will be the exact same object that was returned.
##### Assigning dictionary variables
If a keyword returns a dictionary or any dictionary-like object, it is possible to assign it to a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable):
```
*** Test Cases ***
Assign to dictionary variable
&{dict} = Create Dictionary first=1 second=${2} ${3}=third
Length Should Be ${dict} 3
Do Something &{dict}
Log ${dict.first}
```
Because all Robot Framework variables are stored in the same namespace, it would also be possible to assign a dictionary into a scalar variable and use it later as a dictionary when needed. There are, however, some concrete benefits in creating a dictionary variable explicitly. First of all, Robot Framework verifies that the returned value is a dictionary or dictionary-like similarly as it verifies that list variables can only get a list-like value.
A bigger benefit is that the value is converted into a special dictionary that is used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Values in these dictionaries can be accessed using attribute access like `${dict.first}` in the above example.
##### Assigning multiple variables
If a keyword returns a list or a list-like object, it is possible to assign individual values into multiple scalar variables or into scalar variables and a list variable.
```
*** Test Cases ***
Assign multiple
${a} ${b} ${c} = Get Three
${first} @{rest} = Get Three
@{before} ${last} = Get Three
${begin} @{middle} ${end} = Get Three
```
Assuming that the keyword Get Three returns a list `[1, 2, 3]`, the following variables are created:
- `${a}`, `${b}` and `${c}` with values `1`, `2`, and `3`, respectively.
- `${first}` with value `1`, and `@{rest}` with value `[2, 3]`.
- `@{before}` with value `[1, 2]` and `${last}` with value `3`.
- `${begin}` with value `1`, `@{middle}` with value `[2]` and `${end}` with value `3`.
It is an error if the returned list has more or less values than there are scalar variables to assign. Additionally, only one list variable is allowed and dictionary variables can only be assigned alone.
##### Automatically logging assigned variable value
To make it easier to understand what happens during execution, the beginning of value that is assigned is automatically logged. The default is to show 200 first characters, but this can be changed by using the \--maxassignlength command line option when running tests. If the value is zero or negative, the whole assigned value is hidden.
```
--maxassignlength 1000
--maxassignlength 0
```
The reason the value is not logged fully is that it could be really big. If you always want to see a certain value fully, it is possible to use the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) Log keyword to log it after the assignment.
Note
The \--maxassignlength option is new in Robot Framework 5.0.
#### [`VAR` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-338)
Starting from Robot Framework 7.0, it is possible to create variables inside tests and user keywords using the `VAR` syntax. The `VAR` marker is case-sensitive and it must be followed by a variable name and value. Other than the mandatory `VAR`, the overall syntax is mostly the same as when creating variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section).
The new syntax aims to make creating variables simpler and more uniform. It is especially indented to replace the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Set Variable, Set Local Variable, Set Test Variable, Set Suite Variable and Set Global Variable, but it can be used instead of Catenate, Create List and Create Dictionary as well.
##### Creating scalar variables
In simple cases scalar variables are created by just giving a variable name and its value. The value can be a hard-coded string or it can itself contain a variable. If the value is long, it is possible to split it into multiple columns and rows. In that case parts are joined together with a space by default, but the separator to use can be specified with the `separator` configuration option. It is possible to have an optional `=` after the variable name the same way as when creating variables based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) and in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section).
```
*** Test Cases ***
Scalar examples
VAR ${simple} variable
VAR ${equals} = this works too
VAR ${variable} value contains ${simple}
VAR ${sentence} This is a bit longer variable value
... that is split into multiple rows.
... These parts are joined with a space.
VAR ${multiline} This is another longer value.
... This time there is a custom separator.
... As the result this becomes a multiline string.
... separator=\n
```
##### Creating lists and dictionaries
List and dictionary variables are created similarly as scalar variables, but the variable names must start with `@` and `&`, respectively. When creating dictionaries, items must be specified using the `name=value` syntax.
```
*** Test Cases ***
List examples
VAR @{two items} Robot Framework
VAR @{empty list}
VAR @{lot of stuff}
... first item
... second item
... third item
... fourth item
... last item
Dictionary examples
VAR &{two items} name=Robot Framework url=http://robotframework.org
VAR &{empty dict}
VAR &{lot of stuff}
... first=1
... second=2
... third=3
... fourth=4
... last=5
```
##### Scope
Variables created with the `VAR` syntax are are available only within the test or user keyword where they are created. That can, however, be altered by using the `scope` configuration option. Supported values are:
`LOCAL`
Make the variable available in the current local scope. This is the default.
`TEST`
Make the variable available within the current test. This includes all keywords called by the test. If used on the suite level, makes the variable available in suite setup and teardown, but not in tests or possible child suites. Prior to Robot Framework 7.2, using this scope on the suite level was an error.
`TASK`
Alias for `TEST` that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks).
`SUITE`
Make the variable available within the current suite. This includes all subsequent tests in that suite, but not tests in possible child suites.
`SUITES`
Make the variable available within the current suite and in its child suites. New in Robot Framework 7.1.
`GLOBAL`
Make the variable available globally. This includes all subsequent keywords and tests.
Although Robot Framework variables are case-insensitive, it is recommended to use capital letters with non-local variable names.
```
*** Variables ***
${SUITE} this value is overridden
*** Test Cases ***
Scope example
VAR ${local} local value
VAR ${TEST} test value scope=TEST
VAR ${SUITE} suite value scope=SUITE
VAR ${SUITES} nested suite value scope=SUITES
VAR ${GLOBAL} global value scope=GLOBAL
Should Be Equal ${local} local value
Should Be Equal ${TEST} test value
Should Be Equal ${SUITE} suite value
Should Be Equal ${SUITES} nested suite value
Should Be Equal ${GLOBAL} global value
Keyword
Should Be Equal ${TEST} new test value
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
Scope example, part 2
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
*** Keywords ***
Keyword
Should Be Equal ${TEST} test value
Should Be Equal ${SUITE} suite value
Should Be Equal ${SUITES} nested suite value
Should Be Equal ${GLOBAL} global value
VAR ${TEST} new ${TEST} scope=TEST
VAR ${SUITE} new ${SUITE} scope=SUITE
VAR ${SUITES} new ${SUITES} scope=SUITES
VAR ${GLOBAL} new ${GLOBAL} scope=GLOBAL
Should Be Equal ${TEST} new test value
Should Be Equal ${SUITE} new suite value
Should Be Equal ${SUITES} new nested suite value
Should Be Equal ${GLOBAL} new global value
```
##### Creating variables conditionally
The `VAR` syntax works with [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) which makes it easy to create variables conditionally. In simple cases using [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) can be convenient.
```
*** Test Cases ***
IF/ELSE example
IF "${ENV}" == "devel"
VAR ${address} 127.0.0.1
VAR ${name} demo
ELSE
VAR ${address} 192.168.1.42
VAR ${name} robot
END
Inline IF
IF "${ENV}" == "devel" VAR ${name} demo ELSE VAR ${name} robot
```
##### Creating variable name based on another variable
If there is a need, variable name can also be created dynamically based on another variable.
```
*** Test Cases ***
Dynamic name
VAR ${x} y # Normal assignment.
VAR ${${x}} z # Name created dynamically.
Should Be Equal ${y} z
```
#### [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-339)
Note
The `VAR` syntax is recommended over these keywords when using Robot Framework 7.0 or newer.
The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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. It is an error to call Set Test Variable outside the scope of a test (e.g. in a Suite Setup or Teardown).
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 section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) in the test data file or importing them from [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 variables on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) using the \--variable and \--variablefile options. Because this keyword can change variables everywhere, it should be used with care.
Note
Set Test/Suite/Global Variable keywords set named variables directly into [test, suite or global variable scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-scopes) and return nothing. On the other hand, another [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Set Variable sets local variables using [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords).
#### [Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-340)
Variable values are typically strings, but non-string values are often needed as well. Various ways how to create variables with non-string values has already been discussed:
- [Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) allow creating any kind of objects.
- [Return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) can contain any objects.
- Variables can be created based on existing variables that contain non-string values.
- `@{list}` and `&{dict}` syntax allows creating lists and dictionaries natively.
In addition to the above, it is possible to specify the variable type like `${name: int}` when creating variables, and the value is converted to the specified type automatically. This is called *variable type conversion* and how it works in practice is discussed in this section.
Note
Variable type conversion is new in Robot Framework 7.3.
##### Variable type syntax
The general variable types syntax is `${name: type}` [in the data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-in-data) and `name: type:value` [on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-on-command-line). The space after the colon is mandatory in both cases. Although variable name can in some contexts be created dynamically based on another variable, the type and the type separator must be always specified as literal values.
Variable type conversion supports the same base types that the [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) supports with library keywords. For example, `${number: int}` means that the value of the variable `${number}` is converted to an integer.
Variable type conversion supports also [specifying multiple possible types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-multiple-possible-types) using the union syntax. For example, `${number: int | float}` means that the value is first converted to an integer and, if that fails, then to a floating point number.
Also [parameterized types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parameterized-types) are supported. For example, `${numbers: list[int]}` means that the value is converted to a list of integers.
The biggest limitations compared to the argument conversion with library keywords is that `Enum` and `TypedDict` conversions are not supported and that custom converters cannot be used. These limitations may be lifted in the future versions.
Note
Variable conversion is supported only when variables are created, not when they are used.
##### Variable conversion in data
In the data variable conversion works when creating variables in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section), with the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) and based on [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords):
```
*** Variables ***
${VERSION: float} 7.3
${CRITICAL: list[int]} [3278, 5368, 5417]
*** Test Cases ***
Variables section
Should Be Equal ${VERSION} ${7.3}
Should Be Equal ${CRITICAL} ${{[3278, 5368, 5417]}}
VAR syntax
VAR ${number: int} 42
Should Be Equal ${number} ${42}
Assignment
# In simple cases the VAR syntax is more convenient.
${number: int} = Set Variable 42
Should Be Equal ${number} ${42}
# In this case conversion is more useful.
${match} ${version: float} = Should Match Regexp RF 7.3 ^RF (\\d+\\.\\d+)$
Should Be Equal ${match} RF 7.3
Should Be Equal ${version} ${7.3}
```
Note
In addition to the above, variable type conversion works also with [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments) and with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). See their documentation for more details.
Note
Variable type conversion *does not* work with [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords). The [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) needs to be used instead.
##### Conversion with `@{list}` and `&{dict}` variables
Type conversion works also when creating [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-lists) and [dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) using `@{list}` and `&{dict}` syntax. With lists the type is specified like `@{name: type}` and the type is the type of the list items. With dictionaries the type of the dictionary values can be specified like `&{name: type}`. If there is a need to specify also the key type, it is possible to use syntax `&{name: ktype=vtype}`.
```
*** Variables ***
@{NUMBERS: int} 1 2 3 4 5
&{DATES: date} rc1=2025-05-08 final=2025-05-30
&{PRIORITIES: int=str} 3278=Critical 4173=High 5334=High
```
An alternative way to create lists and dictionaries is creating `${scalar}` variables, using `list` and `dict` types, possibly parameterizing them, and giving values as Python list and dictionary literals:
```
*** Variables ***
${NUMBERS: list[int]} [1, 2, 3, 4, 5]
${DATES: list[date]} {'rc1': '2025-05-08', 'final': '2025-05-30'}
${PRIORITIES: dict[int, str]} {3278: 'Critical', 4173: 'High', 5334: 'High'}
```
Using Python list and dictionary literals can be somewhat complicated especially for non-programmers. The main benefit of this approach is that it supports also nested structures without needing to use temporary values. The following examples create the same `${PAYLOAD}` variable using different approaches:
```
*** Variables ***
@{CHILDREN: int} 2 13 15
&{PAYLOAD: dict} id=${1} name=Robot children=${CHILDREN}
```
```
*** Variables ***
${PAYLOAD: dict} {'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}
```
##### Variable conversion on command line
Variable conversion works also with the [command line variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) that are created using the `--variable` option. The syntax is `name: type:value` and, due to the space being mandatory, the whole option value typically needs to be quoted. Following examples demonstrate some possible usages for this functionality:
```
--variable "ITERATIONS: int:99"
--variable "PAYLOAD: dict:{'id': 1, 'name': 'Robot', 'children': [2, 13, 15]}"
--variable "START_TIME: datetime:now"
```
##### Failing conversion
If type conversion fails, there is an error and the variable is not created. Conversion fails if the value cannot be converted to the specified type or if the type itself is not supported:
```
*** Test Cases ***
Invalid value
VAR ${example: int} invalid
Invalid type
VAR ${example: invalid} 123
```
#### [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-341)
An important usage for [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) is creating so called *secret variables*. These variables encapsulate their values so that the real values are [not logged even on the trace level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) when variables are passed between keywords as arguments and return values.
The actual value is available via the `value` attribute of a secret variable. It is mainly meant to be used by [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) that accept [secret values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-type), but it can be accessed also in the data using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${secret.value}`. Accessing the value in the data makes it visible in the log file similarly as if it was a normal variable, so that should only be done for debugging or testing purposes.
Warning
Secret variables do not hide or encrypt their values. The real values are thus available for all code that can access these variables directly or indirectly via Robot Framework APIs.
Note
Secret variables are new in Robot Framework 7.4.
##### Creating secrets in data
In the data secret variables can be created in the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) and by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax). To avoid secret values being visible to everyone who has access to the data, it is not possible to create secret variables using literal values. Instead the value must be created using an existing secret variable or an [environment variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variable) like `%{NAME}`. In both cases joining a secret value with a literal value like `%{SECRET}123` is allowed as well.
If showing the secret variable in the data is not an issue, it is possible to use environment variable default values like `%{NAME=default}`. The name can even be left empty like `%{=secret}` to always use the default value.
```
*** Variables ***
${NORMAL: Secret} ${XXX} # ${XXX} must itself be a secret variable.
${ENVIRON: Secret} %{EXAMPLE} # Environment variables are supported directly.
${DEFAULT: Secret} %{=robot123} # Environment variable defaults work as well.
${JOIN: Secret} ${XXX}-123 # Joining secrets with literals is ok.
${LITERAL: Secret} robot123 # This fails.
```
Also list and dictionary variables support secret values:
```
*** Variables ***
@{LIST: Secret} ${XXX} %{EXAMPLE} %{=robot123} ${XXX}-123
&{DICT: Secret} normal=${XXX} env=%{EXAMPLE} env_default=%{=robot123} join=${XXX}-123
```
Note
The above examples utilize the Variable section, but the syntax to create secret variables is exactly the same when using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax).
##### Creating secrets on command line
[Command line variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-conversion-on-command-line) supports secret values directly:
```
--variable "PASSWORD: Secret:robot123"
```
Having the secret value directly visible on the command line history or in continuous integration system logs can be a security risk. One way to mitigate that is using environment variables:
```
--variable "PASSWORD: Secret:$PASSWORD"
```
Many systems running tests or tasks also support hiding secret values used on the command line.
##### Creating secrets programmatically
Secrets can be created programmatically by using the [robot.api.types.Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) class. This is most commonly done by [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) and [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files), but also [pre-run modifiers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data) and [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) can utilize secrets if needed.
The simplest possible example of the programmatic usage is a variable file:
```
from robot.api.types import Secret
USERNAME = "robot"
PASSWORD = Secret("robot123")
```
Creating a keyword returning a secret is not much more complicated either:
```
from robot.api.types import Secret
def get_token():
return Secret("e5805f56-92e1-11f0-a798-8782a78eb4b5")
```
Note
Both examples above have the actual secret value visible in the code. When working with real secret values, it is typically better to read secrets from environment variables, get them from external systems or generate them randomly.
### [2\.6.4 Built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-342)
Robot Framework provides some built-in variables that are available automatically.
#### [Operating-system variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-343)
Built-in variables related to the operating system ease making the test data operating-system-agnostic.
| 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. |
| \${/} | The system directory path separator. `/` in UNIX-like systems and \\ in Windows. |
| \${:} | The system path element separator. `:` in UNIX-like systems and `;` in Windows. |
| \${\\n} | The system line separator. \\n in UNIX-like systems and \\r\\n in Windows. |
```
*** Test Cases ***
Example
Create Binary File ${CURDIR}${/}input.data Some text here${\n}on two lines
Set Environment Variable CLASSPATH ${TEMPDIR}${:}${CURDIR}${/}foo.jar
```
#### [Number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-344)
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.
```
*** Test Cases ***
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
```
It is possible to create integers also from binary, octal, and hexadecimal values using `0b`, `0o` and `0x` prefixes, respectively. The syntax is case insensitive.
```
*** Test Cases ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-345)
Also Boolean values and Python `None` can be created using the variable syntax similarly as numbers.
```
*** Test Cases ***
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
```
These variables are case-insensitive, so for example `${True}` and `${true}` are equivalent. Keywords accepting Boolean values typically do automatic argument conversion and handle string values like `True` and `false` as expected. In such cases using the variable syntax is not required.
#### [Space and empty variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-346)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with a backslash. If more than one space is needed, it is possible to use the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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} \
```
There is also an empty [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) `@{EMPTY}` and an empty [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) `&{EMPTY}`. Because they have no content, they basically vanish when used somewhere in the test data. They are useful, for example, with [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) when the [template keyword is used without arguments](https://groups.google.com/group/robotframework-users/browse_thread/thread/ccc9e1cd77870437/4577836fe946e7d5?lnk=gst&q=templates#4577836fe946e7d5) or when overriding list or dictionary variables in different scopes. Modifying the value of `@{EMPTY}` or `&{EMPTY}` is not possible.
```
*** Test Cases ***
Template
[Template] Some keyword
@{EMPTY}
Override
Set Global Variable @{LIST} @{EMPTY}
Set Suite Variable &{DICT} &{EMPTY}
```
Note
`${SPACE}` represents the ASCII space (`\x20`) and [other spaces](http://jkorpela.fi/chars/spaces.html) should be specified using the [escape sequences](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) like `\xA0` (NO-BREAK SPACE) and `\u3000` (IDEOGRAPHIC SPACE).
#### [Automatic variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-347)
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. Altering the value of these variables does not affect the original values, but some values can be changed dynamically using keywords from the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library.
| 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. Can be modified dynamically using Set Tags and Remove Tags keywords. | Test case |
| \${TEST DOCUMENTATION} | The documentation of the current test case. Can be set dynamically using using Set Test Documentation keyword. | Test case |
| \${TEST STATUS} | The status of the current test case, either PASS or FAIL. | [Test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) |
| \${TEST MESSAGE} | The message of the current test case. | [Test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-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. | Everywhere |
| \${SUITE DOCUMENTATION} | The documentation of the current test suite. Can be set dynamically using using Set Suite Documentation keyword. | Everywhere |
| &{SUITE METADATA} | The free metadata of the current test suite. Can be set using Set Suite Metadata keyword. | Everywhere |
| \${SUITE STATUS} | The status of the current test suite, either PASS or FAIL. | [Suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) |
| \${SUITE MESSAGE} | The full message of the current test suite, including statistics. | [Suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) |
| \${KEYWORD STATUS} | The status of the current keyword, either PASS or FAIL. | [User keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) |
| \${KEYWORD MESSAGE} | The possible error message of the current keyword. | [User keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) |
| \${LOG LEVEL} | Current [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). | Everywhere |
| \${OUTPUT DIR} | An absolute path to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) as a string. | Everywhere |
| \${OUTPUT FILE} | An absolute path to the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) as a string or a string `NONE` if the output file is not created. | Everywhere |
| \${LOG FILE} | An absolute path to the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as a string or a string `NONE` if the log file is not created. | Everywhere |
| \${REPORT FILE} | An absolute path to the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) as a string or a string `NONE` if the report file is not created. | Everywhere |
| \${DEBUG FILE} | An absolute path to the [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) as a string or a string `NONE` if the debug file is not created. | Everywhere |
| &{OPTIONS} | A dictionary exposing command line options. The dictionary keys match the command line options and can be accessed both like `${OPTIONS}[key]` and `${OPTIONS.key}`. Available options: `${OPTIONS.exclude}` (\--exclude) `${OPTIONS.include}` (\--include) `${OPTIONS.skip}` (\--skip) `${OPTIONS.skip_on_failure}` (\--skip-on-failure) `${OPTIONS.console_width}` (integer, \--console-width) `${OPTIONS.rpa}` (boolean, \--rpa) `${OPTIONS}` itself was added in RF 5.0, `${OPTIONS.console_width}` in RF 7.1 and `${OPTIONS.rpa}` in RF 7.3. More options can be exposed later. | Everywhere |
Suite related variables `${SUITE SOURCE}`, `${SUITE NAME}`, `${SUITE DOCUMENTATION}` and `&{SUITE METADATA}` as well as options related to command line options like `${LOG FILE}` and `&{OPTIONS}` are available already when libraries and variable files are imported. Possible variables in these automatic variables are not yet resolved at the import time, though.
### [2\.6.5 Variable priorities and scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-348)
Variables coming from different sources have different priorities and are available in different scopes.
#### [Variable priorities](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-349)
*Variables from the command line*
> Variables [set on the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) have the highest priority of all variables that can be set before the actual test execution starts. They override possible variables created in Variable sections 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section in a test case file*
> Variables created using the [Variable section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-section) 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 sections are available in all other sections in the file where they are created. This means that they can be used also in the Setting section, for example, for importing more variables from resource and variable files.
*Imported resource and variable files*
> Variables imported from the [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section 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 section of the file that imports them. This is due to the Variable section being processed before the Setting section where the resource files and variable files are imported.
*Variables set during test execution*
> Variables set during the test execution using [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords), [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or [Set Test/Suite/Global Variable keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#set-test-suite-global-variable-keywords) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#built-in-variables) like `${TEMPDIR}` and `${TEST_NAME}` have the highest priority of all variables. They cannot be overridden using Variable section or from command line, but even they can be reset during the test execution. An exception to this rule are [number variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-350)
Depending on where and how they are created, variables can have a global, test suite, test case or local scope.
##### Global scope
Global variables are available everywhere in the test data. These variables are normally [set from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) with the \--variable and \--variablefile options, but it is also possible to create new global variables or change the existing ones by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Global Variable keyword anywhere in the test data. Additionally also [built-in variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 sections, imported from [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files), or set during the test execution using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Suite Variable keyword.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 with the test case scope are visible in a test case and in all user keywords the test uses. Initially there are no variables in this scope, but it is possible to create them by using the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax) or the Set Test Variable keyword anywhere in a test case.
If a variable with the test scope is created in suite setup, the variable is available everywhere within that suite setup as well as in the corresponding suite teardown, but it is not seen by tests or possible child suites. If such a variable is created in a suite teardown, the variable is available only in that teardown.
Also variables in the test case scope are to some extend global. It is thus generally recommended to use capital letters with them too.
Note
Creating variables with the test scope in a suite setup or teardown caused an error prior to Robot Framework 7.2.
##### Local scope
Test cases and user keywords have a local variable scope that is not seen by other tests or keywords. Local variables can be created using [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) from executed keywords and with the [VAR syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#var-syntax), and user keywords also get them as [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments).
It is recommended to use lower-case letters with local variables.
### [2\.6.6 Advanced variable features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-351)
#### [Extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-352)
Extended variable syntax allows accessing attributes of an object assigned to a variable (for example, `${object.attribute}`) and even calling its methods (for example, `${obj.get_name()}`).
Extended variable syntax is a powerful feature, but it should be used with care. Accessing attributes is normally not a problem, on the contrary, because one variable containing an object with 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 pretty complicated to understand. If that happens, it is recommended to move the code into a library.
The most common usages of extended variable syntax are illustrated in the example below. First assume that we have the following [variable file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files) and test case:
```
class MyObject:
def __init__(self, name):
self.name = name
def eat(self, what):
return f'{self.name} eats {what}'
def __str__(self):
return self.name
OBJECT = MyObject('Robot')
DICTIONARY = {1: 'one', 2: 'two', 3: 'three'}
```
```
*** Test Cases ***
Example
KW 1 ${OBJECT.name}
KW 2 ${OBJECT.eat('Cucumber')}
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 eats Cucumber`
- 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 name of the base variable is created. The body of the name consists of all the characters after the opening `{` until the first occurrence of a character that is not an alphanumeric character, an underscore or a space. For example, base variables of `${OBJECT.name}` and `${DICTIONARY[2]}`) are `OBJECT` and `DICTIONARY`, respectively.
3. A variable matching the base name 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.
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.
```
*** Test Cases ***
String
VAR ${string} abc
Log ${string.upper()} # Logs 'ABC'
Log ${string * 2} # Logs 'abcabc'
Number
VAR ${number} ${-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.
Extended variable syntax works also in [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) and [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) contexts. If, for example, an object assigned to a variable `${EXTENDED}` has an attribute `attribute` that contains a list as a value, it can be used as a list variable `@{EXTENDED.attribute}`.
#### [Extended variable assignment](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-353)
It is possible to set attributes of objects stored to scalar variables using [keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) and a variation of the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax). Assuming we have variable `${OBJECT}` from the previous examples, attributes could be set to it like in the example below.
```
*** Test Cases ***
Example
${OBJECT.name} = Set Variable New name
${OBJECT.new_attr} = Set Variable New attribute
```
The extended variable assignment syntax is evaluated using the following rules:
1. The assigned variable must be a scalar variable and have at least one dot. Otherwise the extended assignment syntax is not used and the variable is assigned normally.
2. If there exists a variable with the full name (e.g. `${OBJECT.name}` in the example above) that variable will be assigned a new value and the extended syntax is not used.
3. The name of the base variable is created. The body of the name consists of all the characters between the opening `${` and the last dot, for example, `OBJECT` in `${OBJECT.name}` and `foo.bar` in `${foo.bar.zap}`. As the second example illustrates, the base name may contain normal extended variable syntax.
4. The name of the attribute to set is created by taking all the characters between the last dot and the closing `}`, for example, `name` in `${OBJECT.name}`. If the name does not start with a letter or underscore and contain only these characters and numbers, the attribute is considered invalid and the extended syntax is not used. A new variable with the full name is created instead.
5. A variable matching the base name is searched. If no variable is found, the extended syntax is not used and, instead, a new variable is created using the full variable name.
6. If the found variable is a string or a number, the extended syntax is ignored and a new variable created using the full name. This is done because you cannot add new attributes to Python strings or numbers, and this way the syntax is also less backwards-incompatible.
7. If all the previous rules match, the attribute is set to the base variable. If setting fails for any reason, an exception is raised and the test fails.
Note
Unlike when assigning variables normally using [return values from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords), changes to variables done using the extended assign syntax are not limited to the current scope. Because no new variable is created but instead the state of an existing variable is changed, all tests and keywords that see that variable will also see the changes.
#### [Variables inside variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-354)
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.
```
*** Variables ***
${JOHN HOME} /home/john
${JANE HOME} /home/jane
*** Test Cases ***
Example
${name} = Get Name
Do X ${${name} HOME}
```
#### [Inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-355)
Variable syntax can also be used for evaluating Python expressions. The basic syntax is `${{expression}}` i.e. there are double curly braces around the expression. The `expression` can be any valid Python expression such as `${{1 + 2}}` or `${{['a', 'list']}}`. Spaces around the expression are allowed, so also `${{ 1 + 2 }}` and `${{ ['a', 'list'] }}` are valid. In addition to using normal [scalar variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), also [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) and [dictionary variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variables) support `@{{expression}}` and `&{{expression}}` syntax, respectively.
Main usages for this pretty advanced functionality are:
- Evaluating Python expressions involving Robot Framework's variables (`${{len('${var}') > 3}}`, `${{$var[0] if $var is not None else None}}`).
- Creating values that are not Python base types (`${{decimal.Decimal('0.11')}}`, `${{datetime.date(2019, 11, 5)}}`).
- Creating values dynamically (`${{random.randint(0, 100)}}`, `${{datetime.date.today()}}`).
- Constructing collections, especially nested collections (`${{[1, 2, 3, 4]}}`, `${{ {'id': 1, 'name': 'Example', 'children': [7, 9]} }}`).
- Accessing constants and other useful attributes in Python modules (`${{math.pi}}`, `${{platform.system()}}`).
This is somewhat similar functionality than the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) discussed earlier. As the examples above illustrate, this syntax is even more powerful as it provides access to Python built-ins like `len()` and modules like `math`. In addition to being able to use variables like `${var}` in the expressions (they are replaced before evaluation), variables are also available using the special `$var` syntax during evaluation. The whole expression syntax is explained in the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix.
Tip
Instead of creating complicated expressions, it is often better to move the logic into a [custom library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries). That eases maintenance, makes test data easier to understand and can also enhance execution speed.
Note
The inline Python evaluation syntax is new in Robot Framework 3.2.
## [2\.7 Creating user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-255)
Keyword sections 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\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-syntax)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax-2)
- [Settings in the Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-keyword-section)
- [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation)
- [2\.7.3 User keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags)
- [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments)
- [Positional arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords)
- [Default values with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values-with-user-keywords)
- [Variable number of arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords)
- [Free named arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords)
- [Named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords)
- [Argument conversion with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-user-keywords)
- [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name)
- [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-syntax-3)
- [Embedded arguments matching wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-arguments-matching-wrong-values)
- [Resolving conflicts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resolving-conflicts)
- [Using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions)
- [Argument conversion with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-embedded-arguments)
- [Behavior-driven development example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-development-example)
- [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values)
- [Using `RETURN` statement](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-return-statement)
- [Using \[Return\] setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-return-setting)
- [Using special keywords to return](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-special-keywords-to-return)
- [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown)
- [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#private-user-keywords)
- [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#recursion)
### [2\.7.1 User keyword syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-356)
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-357)
In many ways, the overall user keyword syntax is identical to the [test case syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-syntax). User keywords are created in Keyword sections which differ from Test Case sections 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.
```
*** Keywords ***
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments), similarly as [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values).
User keywords can be created in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files), and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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 section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-358)
User keywords can have similar settings as [test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#settings-in-the-test-case-section), 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation).
\[Tags\]
Sets [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) for the keyword.
\[Arguments\]
Specifies [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments).
\[Setup\], \[Teardown\]
Specify [user keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown). \[Setup\] is new in Robot Framework 7.0.
\[Timeout\]
Sets the possible [user keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout). [Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) are discussed in a section of their own.
\[Return\]
Specifies [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values). Deprecated in Robot Framework 7.0, the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement should be used instead.
Note
The format used above is recommended, but setting names are case-insensitive and spaces are allowed between brackets and the name. For example, `[ TAGS ]`:setting is valid.
### [2\.7.2 User keyword name and documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-359)
The user keyword name is defined in the first column of the Keyword section. 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. It supports same formatting, splitting to multiple lines, and other features as [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). This setting documents the user keyword in the test data. It is also shown in a more formal keyword documentation, which the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool can create from [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files). Finally, the first logical row of the documentation, until the first empty row, is shown as a keyword documentation in [test logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).
```
*** Keywords ***
One line documentation
[Documentation] One line documentation.
No Operation
Multiline documentation
[Documentation] The first line creates the short doc.
...
... This is the body of the documentation.
... It is not shown in Libdoc outputs but only
... the short doc is shown in logs.
No Operation
Short documentation in multiple lines
[Documentation] If the short doc gets longer, it can span
... multiple physical lines.
...
... The body is separated from the short doc with
... an empty line.
No Operation
```
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 keyword is used. For more information, see the [Deprecating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecating-keywords) section.
Note
Prior to Robot Framework 3.1, the short documentation contained only the first physical line of the keyword documentation.
### [2\.7.4 User keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-361)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), for example `${arg}`.
#### [Positional arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-362)
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 be as descriptive as possible. It is recommended to use lower-case letters in variable names, either as `${my_arg}`, `${my arg}` or `${myArg}`.
```
*** Keywords ***
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 with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-363)
When creating user keywords, positional arguments are sufficient in most situations. It is, however, sometimes useful that keywords have [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) for some or all of their arguments. Also user keywords support default values, 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. The default value can contain a [variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) created on [test, suite or global scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-priorities-and-scopes), but local variables of the keyword executor cannot be used. Default value can also be defined based on earlier arguments accepted by the keyword.
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.
```
*** Keywords ***
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}=${VARIABLE}
[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}
Default Based On Earlier Argument
[Arguments] ${a} ${b}=${a} ${c}=${a} and ${b}
Should Be Equal ${a} ${b}
Should Be Equal ${c} ${a} and ${b}
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
```
*** Test Cases ***
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 with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-364)
Sometimes even default values are not enough and there is a need for a keyword accepting [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments). User keywords support also this feature. All that is needed is having [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) such as `@{varargs}` after possible positional arguments in the keyword signature. This syntax can be combined with the previously described 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.
```
*** Keywords ***
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}
END
```
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). This combination of two rather advanced functions can sometimes be very useful.
The keywords in the examples above could be used, for example, like this:
```
*** Test Cases ***
Varargs with user keywords
Any Number Of Arguments
Any Number Of Arguments arg
Any Number Of Arguments arg1 arg2 arg3 arg4
One Or More Arguments required
One Or More Arguments arg1 arg2 arg3 arg4
Required, Default, Varargs required
Required, Default, Varargs required optional
Required, Default, Varargs arg1 arg2 arg3 arg4 arg5
```
Again, Pythonistas probably notice that the variable number of arguments syntax is very close to the one in Python.
#### [Free named arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-365)
User keywords can also accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) by having a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) like `&{named}` as the absolutely last argument. When the keyword is called, this variable will get all [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments) that do not match any [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords) or [named-only argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords) in the keyword signature.
```
*** Keywords ***
Free Named Only
[Arguments] &{named}
Log Many &{named}
Positional And Free Named
[Arguments] ${required} &{extra}
Log Many ${required} &{extra}
Run Program
[Arguments] @{args} &{config}
Run Process program.py @{args} &{config}
```
The last example above shows how to create a wrapper keyword that accepts any positional or named argument and passes them forward. See [free named argument examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-argument-examples) for a full example with same keyword.
Free named arguments support with user keywords works similarly as kwargs work in Python. In the signature and also when passing arguments forward, `&{kwargs}` is pretty much the same as Python's `**kwargs`.
#### [Named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-366)
User keywords support [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) that are inspired by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102). This syntax is typically used by having normal arguments *after* [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords) (`@{varargs}`). If the keywords does not use varargs, it is possible to use just `@{}` to denote that the subsequent arguments are named-only:
```
*** Keywords ***
With Varargs
[Arguments] @{varargs} ${named}
Log Many @{varargs} ${named}
Without Varargs
[Arguments] @{} ${first} ${second}
Log Many ${first} ${second}
```
Named-only arguments can be used together with [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments-with-user-keywords) as well as with [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords). When using free named arguments, they must be last:
```
*** Keywords ***
With Positional
[Arguments] ${positional} @{} ${named}
Log Many ${positional} ${named}
With Free Named
[Arguments] @{varargs} ${named only} &{free named}
Log Many @{varargs} ${named only} &{free named}
```
When passing named-only arguments to keywords, their order does not matter other than they must follow possible positional arguments. The keywords above could be used, for example, like this:
```
*** Test Cases ***
Example
With Varargs named=value
With Varargs positional second positional named=foobar
Without Varargs first=1 second=2
Without Varargs second=toka first=eka
With Positional foo named=bar
With Positional named=2 positional=1
With Free Named positional named only=value x=1 y=2
With Free Named foo=a bar=b named only=c quux=d
```
Named-only arguments can have default values similarly as [normal user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values-with-user-keywords). A minor difference is that the order of arguments with and without default values is not important.
```
*** Keywords ***
With Default
[Arguments] @{} ${named}=default
Log Many ${named}
With And Without Defaults
[Arguments] @{} ${optional}=default ${mandatory} ${mandatory 2} ${optional 2}=default 2 ${mandatory 3}
Log Many ${optional} ${mandatory} ${mandatory 2} ${optional 2} ${mandatory 3}
```
#### [Argument conversion with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-367)
User keywords support automatic argument conversion based on explicitly specified types. The type syntax `${name: type}` is the same, and the supported conversions are the same, as when [creating variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-syntax).
The basic usage with normal arguments is very simple. You only need to specify the type like `${count: int}` and the used value is converted automatically. If an argument has a default value like `${count: int}=1`, also the default value will be converted. If conversion fails, calling the keyword fails with an informative error message.
```
*** Test Cases ***
Move around
Move 3
Turn LEFT
Move 2.3 log=True
Turn right
Failing move
Move bad
Failing turn
Turn oops
*** Keywords ***
Move
[Arguments] ${distance: float} ${log: bool}=False
IF ${log}
Log Moving ${distance} meters.
END
Turn
[Arguments] ${direction: Literal["LEFT", "RIGHT"]}
Log Turning ${direction}.
```
Tip
Using `Literal`, like in the above example, is a convenient way to limit what values are accepted.
When using [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments-with-user-keywords), the type is specified like `@{numbers: int}` and is applied to all arguments. If arguments may have different types, it is possible to use an union like `@{numbers: float | int}`. With [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-user-keywords) the type is specified like `&{named: int}` and it is applied to all argument values. Converting argument names is not supported.
```
*** Test Cases ***
Varargs
Send bytes Hello! Hyvä! \x00\x00\x07
Free named
Log releases rc 1=2025-05-08 rc 2=2025-05-19 rc 3=2025-05-21 final=2025-05-30
*** Keywords ***
Send bytes
[Arguments] @{data: bytes}
FOR ${value} IN @{data}
Log ${value} formatter=repr
END
Log releases
[Arguments] &{releases: date}
FOR ${version} ${date} IN &{releases}
Log RF 7.3 ${version} was released on ${date.day}.${date.month}.${date.year}.
END
```
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
### [2\.7.5 Embedding arguments into keyword name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-368)
The previous section explained how to pass arguments to keywords so that they are listed separately after the keyword name. Robot Framework has also another approach to pass arguments, embedding them directly to the keyword name, used by the second test below:
```
*** Test Cases ***
Normal arguments
Select from list cat
Embedded arguments
Select cat from list
```
As the example illustrates, embedding arguments to keyword names can make the data easier to read and understand even for people without any Robot Framework experience.
#### [Basic syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-369)
The previous example showed how using a keyword Select cat from list is more fluent than using Select from list so that `cat` is passed to it as an argument. We obviously could implement Select cat from list as a normal keyword accepting no arguments, but then we needed to implement various other keywords like Select dog from list for other animals. Embedded arguments simplify this and we can instead implement just one keyword with name Select \${animal} from list and use it with any animal:
```
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
*** Keywords ***
Select ${animal} from list
Open Page Pet Selection
Select Item From List animal_list ${animal}
```
As the above example shows, embedded arguments are specified simply by using variables in keyword names. The arguments used in the name are naturally available inside the keyword and they have different values depending on how the keyword is called. In the above example, `${animal}` has value `cat` when the keyword is used for the first time and `dog` when it is used for the second time.
Starting from Robot Framework 6.1, it is possible to create user keywords that accept both embedded and "normal" arguments:
```
*** Test Cases ***
Embedded and normal arguments
Number of cats should be 2
Number of dogs should be count=3
*** Keywords ***
Number of ${animals} should be
[Arguments] ${count}
Open Page Pet Selection
Select Items From List animal_list ${animals}
Number of Selected List Items Should Be ${count}
```
Other than the special name, keywords with embedded arguments are created just like other user keywords. They are also used the same way as other keywords except that spaces and underscores are not ignored in their names when keywords are matched. They are, however, case-insensitive like other keywords. For example, the Select \${animal} from list keyword could be used like select cow from list, but not like Select cow fromlist.
Embedded arguments do not support default values or variable number of arguments like normal arguments do. If such functionality is needed, normal arguments should be used instead. Passing embedded arguments as variables is possible, but that can reduce readability:
```
*** Variables ***
${SELECT} cat
*** Test Cases ***
Embedded arguments with variable
Select ${SELECT} from list
*** Keywords ***
Select ${animal} from list
Open Page Pet Selection
Select Item From List animal_list ${animal}
```
#### [Embedded arguments matching wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-370)
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, Select Los Angeles Lakers in the following example matches Select \${city} \${team} so that `${city}` contains `Los` and `${team}` contains `Angeles Lakers`:
```
*** Test Cases ***
Example
Select Chicago Bulls
Select Los Angeles Lakers
*** Keywords ***
Select ${city} ${team}
Log Selected ${team} from ${city}.
```
An easy solution to this problem is surrounding arguments with double quotes or other characters not used in the actual values. This fixed example works so that cities and teams match correctly:
```
*** Test Cases ***
Example
Select "Chicago" "Bulls"
Select "Los Angeles" "Lakers"
*** Keywords ***
Select "${city}" "${team}"
Log Selected ${team} from ${city}.
```
This approach is not enough to resolve all conflicts, but it helps in common cases and is generally recommended. Another benefit is that it makes arguments stand out from rest of the keyword.
Prior to Robot Framework 7.1, embedded arguments starting the keyword name also matched possible [given/when/then/and/but prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignoring-given-when-then-and-but-prefixes) typically used in Behavior Driven Development (BDD). For example, \${name} goes home matched Given Janne goes home so that `${name}` got value `Given Janne`. Nowadays the prefix is ignored and `${name}` will be `Janne` as expected. If older Robot Framework versions need to be supported, it is easiest to quote the argument like in "\${name}" goes home to get consistent behavior.
An alternative solution for limiting what values arguments match is [using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions).
#### [Resolving conflicts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-371)
When using embedded arguments, it is pretty common that there are multiple keyword implementations that match the keyword that is used. For example, Execute "ls" with "lf" in the example below matches both of the keywords. It matching Execute "\${cmd}" with "\${opts}" is pretty obvious and what we want, but it also matches Execute "\${cmd}" so that `${cmd}` matches `ls" with "-lh`.
```
*** Settings ***
Library Process
*** Test Cases ***
Automatic conflict resolution
Execute "ls"
Execute "ls" with "-lh"
*** Keywords ***
Execute "${cmd}"
Run Process ${cmd} shell=True
Execute "${cmd}" with "${opts}"
Run Process ${cmd} ${opts} shell=True
```
When this kind of conflicts occur, Robot Framework tries to automatically select the best match and use that. In the above example, Execute "\${cmd}" with "\${opts}" is considered a better match than the more generic Execute "\${cmd}" and running the example thus succeeds without conflicts.
It is not always possible to find a single match that is better than others. For example, the second test below fails because Robot Framework matches both of the keywords equally well. This kind of conflicts need to be resolved manually either by renaming keywords or by [using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions).
```
*** Test Cases ***
No conflict
Automation framework
Robot uprising
Unresolvable conflict
Robot Framework
*** Keywords ***
${type} Framework
Should Be Equal ${type} Automation
Robot ${action}
Should Be Equal ${action} uprising
```
Keywords that accept only "normal" arguments or no arguments at all are considered to match better than keywords accepting embedded arguments. For example, if the following keyword is added to the above example, Robot Framework used by the latter test matches it and the test succeeds:
```
*** Keywords ***
Robot Framework
No Operation
```
Before looking which match is best, Robot Framework checks are some of the matching keywords implemented in the same file as the caller keyword. If there are such keywords, they are given precedence over other keywords. Alternatively, [library search order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-search-order) can be used to control the order in which Robot Framework looks for keywords in resources and libraries.
Note
Automatically resolving conflicts if multiple keywords with embedded arguments match is a new feature in Robot Framework 6.0. With older versions custom regular expressions explained below can be used instead.
#### [Using custom regular expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-372)
When keywords with embedded arguments are called, the values are matched internally using [regular expressions](http://en.wikipedia.org/wiki/Regular_expression) (regexps for short). The default logic goes so that every argument in the name is replaced with a pattern `.*?` that matches any string and tries to match as little as possible. This logic works fairly well normally, but as discussed above, sometimes keywords [match wrong values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedded-arguments-matching-wrong-values) and sometimes there are [conflicts that cannot be resolved](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resolving-conflicts) . A solution in these cases is specifying 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+}`. If needed, custom patterns can be prefixed with [inline flags](https://docs.python.org/3/library/re.html#regular-expression-syntax) such as `(?i)` for case-insensitivity.
Using custom regular expressions is illustrated by the following examples. The first one shows how the earlier problem with Select \${city} \${team} not matching Select Los Angeles Lakers properly can be resolved without quoting by implementing the keyword so that `${team}` can only contain non-whitespace characters.
```
*** Test Cases ***
Do not match whitespace characters
Select Chicago Bulls
Select Los Angeles Lakers
Match numbers and characters from set
1 + 2 = 3
53 - 11 = 42
Match either date or literal 'today'
Deadline is 2022-09-21
Deadline is today
Case-insensitive match
Select dog
Select CAT
*** Keywords ***
Select ${city} ${team:\S+}
Log Selected ${team} from ${city}.
${number1:\d+} ${operator:[+-]} ${number2:\d+} = ${expected:\d+}
${result} = Evaluate ${number1} ${operator} ${number2}
Should Be Equal As Integers ${result} ${expected}
Deadline is ${deadline: date:\d{4}-\d{2}-\d{2}|today}
# The ': date' part of the above argument specifies the argument type.
# See the separate section about argument conversion for more information.
Log Deadline is ${deadline.day}.${deadline.month}.${deadline.year}.
Select ${animal:(?i)cat|dog}
[Documentation] Inline flag `(?i)` makes the pattern case-insensitive.
Log Selected ${animal}!
```
Note
Support for inline flags is new in Robot Framework 7.2.
##### Supported regular expression syntax
Being implemented with Python, Robot Framework naturally uses Python's [re module](http://docs.python.org/library/re.html) that has pretty standard regular expressions syntax. This syntax is otherwise fully supported with embedded arguments, but regexp extensions in format `(?...)` cannot be used. If the regular expression syntax is invalid, creating the keyword fails with an error visible in [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution).
##### Escaping special characters
Regular expressions use the backslash character (\\) heavily both to form special sequences (e.g. `\d`) and to escape characters that have a special meaning in regexps (e.g. `\$`). Typically in Robot Framework data backslash characters [need to be escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) with another backslash, but that is not required in this context. If there is a need to have a literal backslash in the pattern, then the backslash must be escaped like `${path:c:\\temp\\.*}`.
Possible lone opening and closing curly braces in the pattern must be escaped like `${open:\{}` and `${close:\}}` or otherwise Robot Framework is not able to parse the variable syntax correctly. If there are matching braces like in `${digits:\d{2}}`, escaping is not needed.
Note
Prior to Robot Framework 3.2, it was mandatory to escape all closing curly braces in the pattern like `${digits:\d{2\}}`. This syntax is unfortunately not supported by Robot Framework 3.2 or newer and keywords using it must be updated when upgrading.
Note
Prior to Robot Framework 6.0, using literal backslashes in the pattern required double escaping them like `${path:c:\\\\temp\\\\.*}`. Patterns using literal backslashes need to be updated when upgrading.
##### Using variables with custom embedded argument regular expressions
When using embedded arguments with custom regular expressions, specifying values using variables works only if variables match the whole embedded argument, not if there is any additional content with the variable. For example, the first test below succeeds because the variable `${DATE}` is used on its own, but the last test fails because `${YEAR}-${MONTH}-${DAY}` is not a single variable.
```
*** Variables ***
${DATE} 2011-06-27
${YEAR} 2011
${MONTH} 06
${DAY} 27
*** Test Cases ***
Succeeds
Deadline is ${DATE}
Succeeds without variables
Deadline is 2011-06-27
Fails
Deadline is ${YEAR}-${MONTH}-${DAY}
*** Keywords ***
Deadline is ${deadline:\d{4}-\d{2}-\d{2}}
Should Be Equal ${deadline} 2011-06-27
```
Another limitation of using variables is that their actual values are not matched against custom regular expressions. As the result keywords may be called with values that their custom regexps would not allow. This behavior is deprecated starting from Robot Framework 6.0 and values will be validated in the future. For more information see issue [\#4462](https://github.com/robotframework/robotframework/issues/4462).
#### [Argument conversion with embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-373)
User keywords accepting embedded arguments support argument conversion with type syntax `${name: type}` similarly as [normal user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-user-keywords). If a [custom pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-regular-expressions) is needed, it can be separated with an additional colon like `${name: type:pattern}`.
```
*** Test Cases ***
Example
Buy 3 books
Deadline is 2025-05-30
*** Keywords ***
Buy ${quantity: int} books
Should Be Equal ${quantity} ${3}
Deadline is ${deadline: date:\d{4}-\d{2}-\d{2}}
Should Be Equal ${deadline.year} ${2025}
Should Be Equal ${deadline.month} ${5}
Should Be Equal ${deadline.day} ${30}
```
Because the type separator is a colon followed by a space (e.g. `${arg: int}`) and the pattern separator is just a colon (e.g. `${arg:\d+}`), there typically are no conflicts when using only a type or only a pattern. The only exception is using a pattern starting with a space, but in that case the space can be escaped like `${arg:\ abc}` or a type added like `${arg: str: abc}`.
Note
Argument conversion with user keywords is new in Robot Framework 7.3.
#### [Behavior-driven development example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-374)
A big benefit of having arguments as part of the keyword name is that it makes it easier to use higher-level sentence-like keywords when using the [behavior-driven style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) to write tests. As the example below shows, this support is typically used in combination with the possibility to [omit Given, When and Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ignoring-given-when-then-and-but-prefixes) in keyword definitions:
```
*** Test Cases ***
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
*** Keywords ***
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 the popular BDD tool [Cucumber](https://cucumber.io/).
### [2\.7.6 User keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-375)
Similarly as library keywords, also user keywords can return values. When using Robot Framework 5.0 or newer, the recommended approach is using the native [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement. The old \[Return\] setting was deprecated in Robot Framework 7.0 and also [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Return From Keyword and Return From Keyword If are considered deprecated.
Regardless how values are returned, they can be [assigned to variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) in test cases and in other user keywords.
#### [Using `RETURN` statement](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-376)
The recommended approach to return values is using the `RETURN` statement. It accepts optional return values and can be used with [IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if) and [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) structures. Its usage is easiest explained with examples:
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
[Documentation] Return a value unconditionally.
... Notice that keywords after RETURN are not executed.
${value} = Convert To Upper Case ${arg}
RETURN ${value}
Fail Not executed
Return Three Values
[Documentation] Return multiple values.
RETURN a b c
Conditional Return
[Arguments] ${arg}
[Documentation] Return conditionally.
Log Before
IF ${arg} == 1
Log Returning!
RETURN
END
Log After
Find Index
[Arguments] ${test} ${items}
[Documentation] Advanced example involving FOR loop, inline IF and @{list} variable syntax.
FOR ${index} ${item} IN ENUMERATE @{items}
IF $item == $test RETURN ${index}
END
RETURN ${-1}
```
If you want to test the above examples yourself, you can use them with these test cases:
```
*** Settings ***
Library String
*** Test Cases ***
One return value
${ret} = Return One Value argument
Should Be Equal ${ret} ARGUMENT
Multiple return values
${a} ${b} ${c} = Return Three Values
Should Be Equal ${a}, ${b}, ${c} a, b, c
Conditional return
Conditional Return 1
Conditional Return 2
Advanced
@{list} = Create List foo bar baz
${index} = Find Index bar ${list}
Should Be Equal ${index} ${1}
${index} = Find Index non existing ${list}
Should Be Equal ${index} ${-1}
```
Note
`RETURN` syntax is case-sensitive similarly as [IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if) and [FOR](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for).
Note
`RETURN` is new in Robot Framework 5.0. Use approaches explained below if you need to support older versions.
#### [Using \[Return\] setting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-377)
The \[Return\] setting defines what the keyword should return after it has been executed. Although it is recommended to have it at the end of keyword where it logically belongs, its position does not affect how it is used.
An inherent limitation of the \[Return\] setting is that cannot be used conditionally. Thus only the first two earlier `RETURN` statement examples can be created using it.
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
${value} = Convert To Upper Case ${arg}
[Return] ${value}
Return Three Values
[Return] a b c
```
Note
The \[Return\] setting was deprecated in Robot Framework 7.0 and the `RETURN` statement should be used instead. If there is a need to support older Robot Framework versions that do not support `RETURN`, it is possible to use the special keywords discussed in the next section.
#### [Using special keywords to return](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-378)
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Return From Keyword and Return From Keyword If allow returning from a user keyword conditionally in the middle of the keyword. Both of them also accept optional return values that are handled exactly like with the `RETURN` statement and the \[Return\] setting discussed above.
The introduction of the `RETURN` statement makes these keywords redundant. Examples below contain same keywords as earlier `RETURN` examples but these ones are more verbose:
```
*** Keywords ***
Return One Value
[Arguments] ${arg}
${value} = Convert To Upper Case ${arg}
Return From Keyword ${value}
Fail Not executed
Return Three Values
Return From Keyword a b c
Conditional Return
[Arguments] ${arg}
Log Before
IF ${arg} == 1
Log Returning!
Return From Keyword
END
Log After
Find Index
[Arguments] ${test} ${items}
FOR ${index} ${item} IN ENUMERATE @{items}
Return From Keyword If $item == $test ${index}
END
Return From Keyword ${-1}
```
Note
These keywords are effectively deprecated and the `RETURN` statement should be used unless there is a need to support also older versions than Robot Framework 5.0. There is no visible deprecation warning when using these keywords yet, but they will be loudly deprecated and eventually removed in the future.
### [2\.7.7 User keyword setup and teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-379)
A user keyword can have a setup and a teardown similarly as [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). They are specified using \[Setup\] and \[Teardown\] settings, respectively, directly to the keyword having them. Unlike with tests, it is not possible to specify a common setup or teardown to all keywords in a certain file.
A setup and a teardown are always a single keyword, but they can themselves be user keywords executing multiple keywords internally. It is possible to specify them as variables, and using a special `NONE` value (case-insensitive) is the same as not having a setup or a teardown at all.
User keyword setup is not much different to the first keyword inside the created user keyword. The only functional difference is that a setup can be specified as a variable, but it can also be useful to be able to explicitly mark a keyword to be a setup.
User keyword teardowns are, exactly as test teardowns, executed also if the user keyword fails. They are thus very useful when needing to do something at the end of the keyword regardless of its status. To ensure that all cleanup activities are done, the [continue on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) mode is enabled by default with user keyword teardowns the same way as with test teardowns.
```
*** Keywords ***
Setup and teardown
[Setup] Log New in RF 7!
Do Something
[Teardown] Log Old feature.
Using variables
[Setup] ${SETUP}
Do Something
[Teardown] ${TEARDOWN}
```
Note
User keyword setups are new in Robot Framework 7.0.
### [2\.7.8 Private user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-380)
User keywords can be [tagged](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) with a special `robot:private` tag to indicate that they should only be used in the file where they are created:
```
*** Keywords ***
Public Keyword
Private Keyword
Private Keyword
[Tags] robot:private
No Operation
```
Using the `robot:private` tag does not outright prevent using the keyword outside the file where it is created, but such usages will cause a warning. If there is both a public and a private keyword with the same name, the public one will be used but also this situation causes a warning.
Private keywords are included in spec files created by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) but not in its HTML output files.
Note
Private user keywords are new in Robot Framework 6.0.
### [2\.7.9 Recursion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-381)
User keywords can call themselves either directly or indirectly. This kind of recursive usage is fine as long as the recursion ends, typically based on some condition, before the recursion limit is exceeded. The limit exists because otherwise infinite recursion would crash the execution.
Robot Framework's recursion detection works so, that it checks is the current recursion level close to the recursion limit of the underlying Python process. If it is close enough, no more new started keywords or control structures are allowed and execution fails.
Python's default recursion limit is 1000 stack frames, which in practice means that it is possible to start approximately 140 keywords or control structures. If that is not enough, Python's recursion limit can be raised using the [sys.setrecursionlimit()](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit) function. As the documentation of the function explains, this should be done with care, because a too-high level can lead to a crash.
Note
Prior to Robot Framework 7.2, the recursion limit was hard-coded to 100 started keywords or control structures.
## [2\.8 Resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-256)
User keywords and variables in [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) can only be used in files where they are created, but *resource files* provide a mechanism for sharing them. The high level syntax for creating resource files is exactly the same as when creating suite files and [supported file formats](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats) are the same as well. The main difference is that resource files cannot have tests.
*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 or YAML, which also makes them somewhat more complicated than [Variable sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-sections).
- [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files)
- [Taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use)
- [Resource file structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-structure)
- [Documenting resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-resource-files)
- [Example resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-resource-file)
- [Resource files using reStructured text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format)
- [Resource files using JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format)
- [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files)
- [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use)
- [Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module)
- [Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function)
- [Implementing variable file as a class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implementing-variable-file-as-a-class)
- [Variable file as YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-yaml)
- [Variable file as JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-json)
### [2\.8.1 Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-382)
Resource files are typically created using the plain text format, but also [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format) and [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format) are supported.
#### [Taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-383)
Resource files are imported using the Resource setting in the Settings section so that the path to the resource file is given as an argument to the setting. The recommended extension for resource files is .resource. For backwards compatibility reasons also .robot, .txt and .tsv work, but using .resource may be mandated in the future.
If the resource file path is absolute, it is used directly. Otherwise, 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 Python's [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). Searching resource files from the module search path makes it possible to bundle them into Python packages as [package data](https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/#package-data) and importing them like package/example.resource.
The resource file path can contain variables, and it is recommended to use them to make paths system-independent (for example, \${RESOURCES}/login.resource or just \${RESOURCE\_PATH}). Additionally, forward slashes (`/`) in the path are automatically changed to backslashes (\\) on Windows.
```
*** Settings ***
Resource example.resource
Resource ../resources/login.resource
Resource package/example.resource
Resource ${RESOURCES}/common.resource
```
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.
Note
The .resource extension is new in Robot Framework 3.1.
#### [Resource file structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-384)
The higher-level structure of resource files is the same as that of suite files otherwise, but they cannot contain tests or tasks. Additionally, the Setting section in resource files can contain only imports (Library, Resource, Variables), Documentation and Keyword Tags. The Variable section and Keyword section are used exactly the same way as in suite 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-385)
Keywords created in a resource file can be [documented](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation) using \[Documentation\] setting. The resource file itself can have Documentation in the Setting section similarly as [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name).
[Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) and various editors use these documentations, and they are naturally available for anyone opening resource files. The first logical line of the documentation of a keyword, until the first empty line, is logged when the keyword is run, but otherwise resource file documentation is ignored during the test execution.
#### [Example resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-386)
```
*** Settings ***
Documentation An example resource file
Library SeleniumLibrary
Resource ${RESOURCES}/common.resource
*** Variables ***
${HOST} localhost:7272
${LOGIN URL} http://${HOST}/
${WELCOME URL} http://${HOST}/welcome.html
${BROWSER} Firefox
*** Keywords ***
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}
```
#### [Resource files using reStructured text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-387)
The [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format) that can be used with [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) works also with resource files. Such resource files can use either .rst or .rest extension and they are otherwise imported exactly as normal resource files:
```
*** Settings ***
Resource example.rst
```
When parsing resource files using the reStructuredText format, Robot Framework ignores all data outside code blocks containing Robot Framework data exactly the same way as when parsing [reStructuredText suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format). For example, the following resource file imports OperatingSystem library, defines `${MESSAGE}` variable and creates My Keyword keyword:
```
Resource file using reStructuredText
------------------------------------
This text is outside code blocks and thus ignored.
.. code:: robotframework
*** Settings ***
Library OperatingSystem
*** Variables ***
${MESSAGE} Hello, world!
Also this text is outside code blocks and ignored. Code blocks not
containing Robot Framework data are ignored as well.
.. code:: robotframework
# Both space and pipe separated formats are supported.
| *** Keywords *** | | |
| My Keyword | [Arguments] | ${path} |
| | Directory Should Exist | ${path} |
```
#### [Resource files using JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-388)
Resource files can be created using [JSON](https://json.org/) the [same way as suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format). Such JSON resource files must use either the standard .json extension or the custom .rsrc extension. They are otherwise imported exactly as normal resource files:
```
*** Settings ***
Resource example.rsrc
```
Resource files can be converted to JSON using [ResourceFile.to\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.ResourceFile.to_json) and recreated using [ResourceFile.from\_json](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.ResourceFile.from_json):
```
from robot.running import ResourceFile
# Create resource file based on data on the file system.
resource = ResourceFile.from_file_system('example.resource')
# Save JSON data to a file.
resource.to_json('example.rsrc')
# Recreate resource from JSON data.
resource = ResourceFile.from_json('example.rsrc')
```
### [2\.8.2 Variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-389)
Variable files contain [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) that can be used in the test data. Variables can also be created using [Variable sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-sections) or [set from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables), but variable files allow creating them dynamically and also make it easy to create other variable values than strings.
Variable files are typically implemented as modules and there are two different approaches for creating variables:
[Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module)
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 its value. One limitation of this approach is that it does not allow using arguments.
[Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function)
Variable files can have a special `get_variables` (or `getVariables`) method that returns variables as a mapping. Because the method can take arguments this approach is very flexible.
Alternatively variable files can be implemented as [classes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implementing-variable-file-as-a-class) that the framework will instantiate. Also in this case it is possible to create variables as attributes or get them dynamically from the `get_variables` method. Variable files can also be created as [YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-yaml) and [JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-file-as-json).
#### [Taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-390)
##### Setting section
All test data files can import variable files using the Variables setting in the Setting section. Variable files are typically imported using a path to the file same way as [resource files are imported](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use) 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 directories in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). The path can also contain variables, and slashes are converted to backslashes on Windows.
Examples:
```
*** Settings ***
Variables myvariables.py
Variables ../data/variables.py
Variables ${RESOURCES}/common.yaml
```
Starting from Robot Framework 5.0, variable files implemented using Python can also be imported using the module name [similarly as libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import). When using this approach, the module needs to be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
Examples:
```
*** Settings ***
Variables myvariables
Variables rootmodule.Variables
```
If a [variable file accepts arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-from-a-special-function), they are specified after the path or name of the variable file to import:
```
*** Settings ***
Variables arguments.py arg1 ${ARG2}
Variables arguments argument
```
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 sections 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 or module name similarly as when importing them using the Variables setting. Possible arguments are joined to the path with a colon (`:`):
```
--variablefile myvariables.py
--variablefile path/variables.py
--variablefile /absolute/path/common.py
--variablefile variablemodule
--variablefile arguments.py:arg1:arg2
--variablefile rootmodule.Variables:arg1:arg2
```
Variable files taken into use from the command line are also searched from the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) similarly as variable files imported in the Setting section. Relative paths are considered relative to the directory where execution is started from.
If a variable file is given as an absolute Windows path, the colon after the drive letter is not considered a separator:
```
--variablefile C:\path\variables.py
```
It is also possible to use a semicolon (`;`) as an argument separator. This is useful if variable file arguments themselves contain colons, but requires surrounding the whole value with quotes on UNIX-like operating systems:
```
--variablefile C:\path\variables.py;D:\data.xls
--variablefile "myvariables.py;argument:with:colons"
```
Variables in variable files taken use on the command line are globally available in all test data files, similarly as [individual variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-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.
#### [Getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-391)
##### Basic syntax
When variable files are taken into use, they are imported as Python modules and all their module level attributes that do not start with an underscore (`_`) are, by default, 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]
MAPPING = {"one": 1, "two": 2, "three": 3}
```
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, then there are two lists, and the final value is a dictionary. All these variables can be used as a [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variable), lists and the dictionary also a [list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variable) like `@{STRINGS}` (in the dictionary's case that variable would only contain keys), and the dictionary also as a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable) like `&{MAPPING}`.
To make creating a list variable or a dictionary variable more explicit, it is possible to prefix the variable name with `LIST__` or `DICT__`, respectively:
```
from collections import OrderedDict
LIST__ANIMALS = ["cat", "dog"]
DICT__FINNISH = OrderedDict([("cat", "kissa"), ("dog", "koira")])
```
These prefixes will not be part of the final variable name, but they cause Robot Framework to validate that the value actually is list-like or dictionary-like. With dictionaries the actual stored value is also turned into a special dictionary that is used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Values of these dictionaries are accessible as attributes like `${FINNISH.cat}`. These dictionaries are also ordered, but preserving the source order requires also the original dictionary to be ordered.
The variables in both the examples above could be created also using the Variable section below.
```
*** Variables ***
${VARIABLE} An example string
${ANOTHER VARIABLE} This is pretty easy!
${INTEGER} ${42}
@{STRINGS} one two kolme four
@{NUMBERS} ${1} ${INTEGER} ${3.14}
&{MAPPING} one=${1} two=${2} three=${3}
@{ANIMALS} cat dog
&{FINNISH} cat=kissa dog=koira
```
Note
Variables are not replaced in strings got from variable files. For example, `VAR = "an ${example}"` would create variable `${VAR}` with a literal string value `an ${example}` regardless would variable `${example}` exist or not.
##### Using objects as values
Variables in variable files are not limited to having only strings or other base types as values like Variable sections. Instead, their variables can contain any objects. In the example below, the variable `${MAPPING}` contains 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 *`.
The third option to select what variables are actually created is using a special `get_variables` function discussed below.
#### [Getting variables from a special function](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-392)
An alternative approach for getting variables is having a special `get_variables` function (also camelCase syntax `getVariables` is possible) in a variable file. If such a function exists, Robot Framework calls it and expects to receive variables as a Python dictionary with variable names as keys and variable values as values. Created variables can be used as scalars, lists, and dictionaries exactly like when [getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module), and it is possible to use `LIST__` and `DICT__` prefixes to make creating list and dictionary variables more explicit. The example below is functionally identical to the first example related to [getting variables directly from a module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-variables-directly-from-a-module).
```
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],
"MAPPING": {"one": 1, "two": 2, "three": 3}}
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use), arguments are specified after the path to the variable file, and in the command line they are separated from the path with a colon or a semicolon.
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
```
Starting from Robot Framework 7.0, arguments to variable files support automatic argument conversion as well as named argument syntax. For example, a variable file with `get_variables(first: int = 0, second: str = '')` could be imported like this:
```
*** Settings ***
Variables example.py 42 # Converted to integer.
Variables example.py second=value # Named argument syntax.
```
#### [Implementing variable file as a class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-393)
It is possible to implement variables files also as a class.
##### Implementation
Because variable files are always imported using a file system path, the class must have the same name as the module it is located in.
The framework will create an instance of the class using no arguments and variables will be gotten from the instance. Similarly as with modules, variables can be defined as attributes directly in the instance or gotten from a special `get_variables` method.
When variables are defined directly in an instance, all attributes containing callable values are ignored to avoid creating variables from possible methods the instance has. If you would actually need callable variables, you need to use other approaches to create variable files.
##### Examples
The first examples create variables from attributes. It creates variables `${VARIABLE}` and `@{LIST}` from class attributes and `${ANOTHER VARIABLE}` from an instance attribute.
```
class StaticExample:
variable = 'value'
LIST__list = [1, 2, 3]
_not_variable = 'starts with an underscore'
def __init__(self):
self.another_variable = 'another value'
```
The second examples utilizes dynamic approach for getting variables. It creates only one variable `${DYNAMIC VARIABLE}`.
```
class DynamicExample:
def get_variables(self, *args):
return {'dynamic variable': ' '.join(args)}
```
#### [Variable file as YAML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-394)
Variable files can also be implemented as [YAML](https://yaml.org/) files. YAML is a data serialization language with a simple and human-friendly syntax that is nevertheless easy for machines to parse. The following example demonstrates a simple YAML file:
```
string: Hello, world!
integer: 42
list:
- one
- two
dict:
one: yksi
two: kaksi
with spaces: kolme
```
YAML variable files can be used exactly like normal variable files from the command line using \--variablefile option, in the Settings section using Variables setting, and dynamically using the Import Variables keyword. They are automatically recognized by their extension that must be either .yaml or .yml. If the above YAML file is imported, it will create exactly the same variables as this Variable section:
```
*** Variables ***
${STRING} Hello, world!
${INTEGER} ${42}
@{LIST} one two
&{DICT} one=yksi two=kaksi with spaces=kolme
```
YAML files used as variable files must always be mappings on the top level. As the above example demonstrates, keys and values in the mapping become variable names and values, respectively. Variable values can be any data types supported by YAML syntax. If names or values contain non-ASCII characters, YAML variables files must be UTF-8 encoded.
Mappings used as values are automatically converted to special dictionaries that are used also when [creating dictionaries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-dictionaries) in the Variable section. Most importantly, values of these dictionaries are accessible as attributes like `${DICT.one}`, assuming their names are valid as Python attribute names. If the name contains spaces or is otherwise not a valid attribute name, it is always possible to access dictionary values using syntax like `${DICT}[with spaces]` syntax.
Note
Using YAML files with Robot Framework requires [PyYAML](http://pyyaml.org/) module to be installed. You can typically install it with [pip](https://pip.pypa.io/) like `pip install pyyaml`.
#### [Variable file as JSON](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-395)
Variable files can also be implemented as [JSON](https://json.org/) files. Similarly as YAML discussed in the previous section, JSON is a data serialization format targeted both for humans and machines. It is based on JavaScript syntax and it is not as human-friendly as YAML, but it still relatively easy to understand and modify. The following example contains exactly the same data as the earlier YAML example:
```
{
"string": "Hello, world!",
"integer": 42,
"list": [
"one",
"two"
],
"dict": {
"one": "yksi",
"two": "kaksi",
"with spaces": "kolme"
}
}
```
JSON variable files are automatically recognized by their .json extension and they can be used exactly like YAML variable files. They also have exactly same requirements for structure, encoding, and so on. Unlike YAML, Python supports JSON out-of-the-box so no extra modules need to be installed.
Note
Support for JSON variable files is new in Robot Framework 6.1.
## [2\.9 Control structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-257)
This section describes various structures that can be used to control the test execution flow. These structures are familiar from most programming languages and they allow conditional execution, repeatedly executing a block of keywords and fine-grained error handling. For readability reasons these structures should be used judiciously, and more complex use cases should be preferably implemented in [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries).
- [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops)
- [Simple `FOR` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-for-loop)
- [Old `FOR` loop syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#old-for-loop-syntax)
- [Nesting `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nesting-for-loops)
- [Using several loop variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-several-loop-variables)
- [`FOR-IN-RANGE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-range-loop)
- [`FOR-IN-ENUMERATE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-enumerate-loop)
- [`FOR-IN-ZIP` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-zip-loop)
- [Dictionary iteration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-iteration)
- [Loop variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-variable-conversion)
- [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-unnecessary-keywords-from-outputs)
- [Repeating single keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#repeating-single-keyword)
- [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops)
- [Basic `WHILE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-while-syntax)
- [Limiting `WHILE` loop iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-while-loop-iterations)
- [Nesting `WHILE` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nesting-while-loops)
- [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-unnecessary-keywords-from-outputs-1)
- [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#loop-control-using-break-and-continue)
- [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-syntax)
- [Basic `IF` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-if-syntax)
- [`ELSE` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#else-branches)
- [`ELSE IF` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#else-if-branches)
- [Inline `IF`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if-1)
- [Nested `IF` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#nested-if-structures)
- [Other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-execute-keywords-conditionally)
- [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax)
- [Catching exceptions with `EXCEPT`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#catching-exceptions-with-except)
- [Matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#matching-errors-using-patterns)
- [Capturing error message](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#capturing-error-message)
- [Using `ELSE` to execute keywords when there are no errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-else-to-execute-keywords-when-there-are-no-errors)
- [Using `FINALLY` to execute keywords regardless are there errors or not](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-finally-to-execute-keywords-regardless-are-there-errors-or-not)
- [Other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-handle-errors)
- [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-syntax)
- [`GROUP` with templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#group-with-templates)
- [Programmatic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-usage)
### [2\.9.1 `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-396)
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 supported also by various other programming languages.
#### [Simple `FOR` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-397)
In a normal `FOR` loop, one variable is assigned based on a list of values, one value per iteration. The syntax starts with `FOR` (case-sensitive) as a marker, then the loop variable, then a mandatory `IN` (case-sensitive) as a separator, and finally the values to iterate. These values can contain [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables), including [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables).
The keywords used in the `FOR` loop are on the following rows and the loop ends with `END` (case-sensitive) on its own row. Keywords inside the loop do not need to be indented, but that is highly recommended to make the syntax easier to read.
```
*** Test Cases ***
Example
FOR ${animal} IN cat dog
Log ${animal}
Log 2nd keyword
END
Log Outside loop
Second Example
FOR ${var} IN one two ${3} four ${five}
... kuusi 7 eight nine ${last}
Log ${var}
END
```
The `FOR` loop in Example 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 two rows](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) and the loop is run altogether ten times.
It is often convenient to use `FOR` loops with [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables). This is illustrated by the example below, where `@{ELEMENTS}` contains an arbitrarily long list of elements and keyword Start Element is used with all of them one by one.
```
*** Test Cases ***
Example
FOR ${element} IN @{ELEMENTS}
Start Element ${element}
END
```
#### [Old `FOR` loop syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-398)
Prior to Robot Framework 3.1, the `FOR` loop syntax was different than nowadays. The marker to start the loop was `:FOR` instead of `FOR` and loop contents needed to be explicitly marked with a backslash instead of using the `END` marker to end the loop. The first example above would look like this using the old syntax:
```
*** Test Cases ***
Example
:FOR ${animal} IN cat dog
\ Log ${animal}
\ Log 2nd keyword
Log Outside loop
```
The old syntax was deprecated in Robot Framework 3.2 and the support for it was removed altogether in Robot Framework 4.0.
#### [Nesting `FOR` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-399)
Starting from Robot Framework 4.0, it is possible to use nested `FOR` loops simply by adding a loop inside another loop:
```
*** Keywords ***
Handle Table
[Arguments] @{table}
FOR ${row} IN @{table}
FOR ${cell} IN @{row}
Handle Cell ${cell}
END
END
```
There can be multiple nesting levels and loops can also be combined with other control structures:
```
*** Test Cases ***
Multiple nesting levels
FOR ${root} IN r1 r2
FOR ${child} IN c1 c2 c3
FOR ${grandchild} IN g1 g2
Log Many ${root} ${child} ${grandchild}
END
END
FOR ${sibling} IN s1 s2 s3
IF '${sibling}' != 's2'
Log Many ${root} ${sibling}
END
END
END
```
#### [Using several loop variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-400)
It is possible to iterate over multiple values in one iteration by using multiple loop variables between the `FOR` and `IN` markers. There can be any number of loop variables, but the number of values must be evenly dividable by the number of variables. Each iteration consumes as many values as there are variables.
If there are lot of values to iterate, it is often convenient to organize them below the loop variables, as in the first loop of the example below:
```
*** Test Cases ***
Multiple loop variables
FOR ${index} ${english} ${finnish} IN
... 1 cat kissa
... 2 dog koira
... 3 horse hevonen
Add Translation ${english} ${finnish} ${index}
END
FOR ${name} ${id} IN @{EMPLOYERS}
Create ${name} ${id}
END
```
#### [`FOR-IN-RANGE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-401)
All `FOR` loops in the previous section iterated over a sequence. That is the most common use case, but sometimes it is convenient to have a loop that is executed a certain number of times. For this purpose Robot Framework has a special `FOR index IN RANGE limit` loop syntax that is derived from the similar Python idiom using the [built-in range() function](http://docs.python.org/library/functions.html#func-range).
Similarly as other `FOR` loops, the `FOR-IN-RANGE` loop starts with `FOR` that is followed by a loop variable. In this format there can be only one loop variable and it contains the current loop index. After the variable there must be `IN RANGE` marker (case-sensitive) that is followed by loop limits.
In the simplest case, only the upper limit of the loop is specified. In this case, loop indices 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 indices 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.
It is possible to use simple arithmetic such as addition and subtraction with the range limits. This is especially useful when the limits are specified with variables. Start, end and step are typically given as integers, but using float values is possible as well.
```
*** Test Cases ***
Only upper limit
[Documentation] Loops over values from 0 to 9.
FOR ${index} IN RANGE 10
Log ${index}
END
Start and end
[Documentation] Loops over values from 1 to 10.
FOR ${index} IN RANGE 1 11
Log ${index}
END
Also step given
[Documentation] Loops over values 5, 15, and 25.
FOR ${index} IN RANGE 5 26 10
Log ${index}
END
Negative step
[Documentation] Loops over values 13, 3, and -7.
FOR ${index} IN RANGE 13 -13 -10
Log ${index}
END
Arithmetic
[Documentation] Arithmetic with variable.
FOR ${index} IN RANGE ${var} + 1
Log ${index}
END
Float parameters
[Documentation] Loops over values 3.14, 4.34, and 5.54.
FOR ${index} IN RANGE 3.14 6.09 1.2
Log ${index}
END
```
#### [`FOR-IN-ENUMERATE` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-402)
Sometimes it is useful to loop over a list and also keep track of your location inside the list. Robot Framework has a special `FOR index ... IN ENUMERATE ...` syntax for this situation. This syntax is derived from the [Python built-in enumerate() function](http://docs.python.org/library/functions.html#enumerate).
`FOR-IN-ENUMERATE` loops syntax is just like the regular `FOR` loop syntax, except that the separator between variables and values is `IN ENUMERATE` (case-sensitive). Typically they are used so that there is an additional index variable before any other loop-variables. By default the index has a value `0` on the first iteration, `1` on the second, and so on.
For example, the following two test cases do the same thing:
```
*** Variables ***
@{LIST} a b c
*** Test Cases ***
Manage index manually
${index} = Set Variable -1
FOR ${item} IN @{LIST}
${index} = Evaluate ${index} + 1
My Keyword ${index} ${item}
END
FOR-IN-ENUMERATE
FOR ${index} ${item} IN ENUMERATE @{LIST}
My Keyword ${index} ${item}
END
```
Starting from Robot Framework 4.0, it is possible to specify a custom start index by using `start=<index>` syntax as the last item of the `FOR ... IN ENUMERATE ...` header:
```
*** Variables ***
@{LIST} a b c
${START} 10
*** Test Cases ***
FOR-IN-ENUMERATE with start
FOR ${index} ${item} IN ENUMERATE @{LIST} start=1
My Keyword ${index} ${item}
END
Start as variable
FOR ${index} ${item} IN ENUMERATE @{LIST} start=${start}
My Keyword ${index} ${item}
END
```
The `start=<index>` syntax must be explicitly used in the `FOR` header and it cannot itself come from a variable. If the last actual item to enumerate would start with `start=`, it needs to be escaped like `start\=`.
Just like with regular `FOR` loops, you can loop over multiple values per loop iteration as long as the number of values in your list is evenly divisible by the number of loop-variables (excluding the index variable):
```
*** Test Cases ***
FOR-IN-ENUMERATE with two values per iteration
FOR ${index} ${en} ${fi} IN ENUMERATE
... cat kissa
... dog koira
... horse hevonen
Log "${en}" in English is "${fi}" in Finnish (index: ${index})
END
```
If you only use one loop variable with `FOR-IN-ENUMERATE` loops, that variable will become a Python tuple containing the index and the iterated value:
```
*** Test Cases ***
FOR-IN-ENUMERATE with one loop variable
FOR ${x} IN ENUMERATE @{LIST}
Length Should Be ${x} 2
Log Index is ${x}[0] and item is ${x}[1].
END
```
Note
`FOR-IN-ENUMERATE` loops with only one loop variable is a new feature in Robot Framework 3.2.
#### [`FOR-IN-ZIP` loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-403)
Some tests build up several related lists, then loop over them together. Robot Framework has a shortcut for this case: `FOR ... IN ZIP ...`, which is derived from the [Python built-in zip() function](http://docs.python.org/library/functions.html#zip).
This may be easiest to show with an example:
```
*** Variables ***
@{NUMBERS} ${1} ${2} ${5}
@{NAMES} one two five
*** Test Cases ***
Iterate over two lists manually
${length}= Get Length ${NUMBERS}
FOR ${index} IN RANGE ${length}
Log Many ${NUMBERS}[${index}] ${NAMES}[${index}]
END
FOR-IN-ZIP
FOR ${number} ${name} IN ZIP ${NUMBERS} ${NAMES}
Log Many ${number} ${name}
END
```
As the example above illustrates, `FOR-IN-ZIP` loops require their own custom separator `IN ZIP` (case-sensitive) between loop variables and values. Values used with `FOR-IN-ZIP` loops must be lists or list-like objects.
Items to iterate over must always be given either as [scalar variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables) like `${items}` or as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables) like `@{lists}` that yield the actual iterated lists. The former approach is more common and it was already demonstrated above. The latter approach works like this:
```
*** Variables ***
@{NUMBERS} ${1} ${2} ${5}
@{NAMES} one two five
@{LISTS} ${NUMBERS} ${NAMES}
*** Test Cases ***
FOR-IN-ZIP with lists from variable
FOR ${number} ${name} IN ZIP @{LISTS}
Log Many ${number} ${name}
END
```
The number of lists to iterate over is not limited, but it must match the number of loop variables. Alternatively, there can be just one loop variable that then becomes a Python tuple getting items from all lists.
```
*** Variables ***
@{ABC} a b c
@{XYZ} x y z
@{NUM} 1 2 3
*** Test Cases ***
FOR-IN-ZIP with multiple lists
FOR ${a} ${x} ${n} IN ZIP ${ABC} ${XYZ} ${NUM}
Log Many ${a} ${x} ${n}
END
FOR-IN-ZIP with one variable
FOR ${items} IN ZIP ${ABC} ${XYZ} ${NUM}
Length Should Be ${items} 3
Log Many ${items}[0] ${items}[1] ${items}[2]
END
```
Starting from Robot Framework 6.1, it is possible to configure what to do if lengths of the iterated items differ. By default, the shortest item defines how many iterations there are and values at the end of longer ones are ignored. This can be changed by using the `mode` option that has three possible values:
- `STRICT`: Items must have equal lengths. If not, execution fails. This is the same as using `strict=True` with Python's [zip](https://docs.python.org/library/functions.html#zip) function.
- `SHORTEST`: Items in longer items are ignored. Infinite iterators are supported in this mode as long as one of the items is exhausted. This is the default behavior.
- `LONGEST`: The longest item defines how many iterations there are. Missing values in shorter items are filled-in with value specified using the `fill` option or `None` if it is not used. This is the same as using Python's [zip\_longest](https://docs.python.org/library/itertools.html#itertools.zip_longest) function except that it has `fillvalue` argument instead of `fill`.
All these modes are illustrated by the following examples:
```
*** Variables ***
@{CHARACTERS} a b c d f
@{NUMBERS} 1 2 3
*** Test Cases ***
STRICT mode
[Documentation] This loop fails due to lists lengths being different.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=STRICT
Log ${c}: ${n}
END
SHORTEST mode
[Documentation] This loop executes three times.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=SHORTEST
Log ${c}: ${n}
END
LONGEST mode
[Documentation] This loop executes five times.
... On last two rounds `${n}` has value `None`.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=LONGEST
Log ${c}: ${n}
END
LONGEST mode with custom fill value
[Documentation] This loop executes five times.
... On last two rounds `${n}` has value `0`.
FOR ${c} ${n} IN ZIP ${CHARACTERS} ${NUMBERS} mode=LONGEST fill=0
Log ${c}: ${n}
END
```
Note
The behavior if list lengths differ will change in the future so that the `STRICT` mode will be the default. If that is not desired, the `SHORTEST` mode needs to be used explicitly.
#### [Dictionary iteration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-404)
Normal `FOR` loops and `FOR-IN-ENUMERATE` loops support iterating over keys and values in dictionaries. This syntax requires at least one of the loop values to be a [dictionary variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dictionary-variable). It is possible to use multiple dictionary variables and to give additional items in `key=value` syntax. Items are iterated in the order they are defined and if same key gets multiple values the last value will be used.
```
*** Variables ***
&{DICT} a=1 b=2 c=3
*** Test Cases ***
Dictionary iteration with FOR loop
FOR ${key} ${value} IN &{DICT}
Log Key is '${key}' and value is '${value}'.
END
Dictionary iteration with FOR-IN-ENUMERATE loop
FOR ${index} ${key} ${value} IN ENUMERATE &{DICT}
Log On round ${index} key is '${key}' and value is '${value}'.
END
Multiple dictionaries and extra items in 'key=value' syntax
&{more} = Create Dictionary e=5 f=6
FOR ${key} ${value} IN &{DICT} d=4 &{more} g=7
Log Key is '${key}' and value is '${value}'.
END
```
Typically it is easiest to use the dictionary iteration syntax so that keys and values get separate variables like in the above examples. With normal `FOR` loops it is also possible to use just a single variable that will become a tuple containing the key and the value. If only one variable is used with `FOR-IN-ENUMERATE` loops, it becomes a tuple containing the index, the key and the value. Two variables with `FOR-IN-ENUMERATE` loops means assigning the index to the first variable and making the second variable a tuple containing the key and the value.
```
*** Test Cases ***
One loop variable
FOR ${item} IN &{DICT}
Log Key is '${item}[0]' and value is '${item}[1]'.
END
One loop variable with FOR-IN-ENUMERATE
FOR ${item} IN ENUMERATE &{DICT}
Log On round ${item}[0] key is '${item}[1]' and value is '${item}[2]'.
END
Two loop variables with FOR-IN-ENUMERATE
FOR ${index} ${item} IN ENUMERATE &{DICT}
Log On round ${index} key is '${item}[0]' and value is '${item}[1]'.
END
```
In addition to iterating over names and values in dictionaries, it is possible to iterate over keys and then possibly fetch the value based on it. This syntax requires using dictionaries as [list variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables):
```
*** Test Cases ***
Iterate over keys
FOR ${key} IN @{DICT}
Log Key is '${key}' and value is '${DICT}[${key}]'.
END
```
Note
Iterating over keys and values in dictionaries is a new feature in Robot Framework 3.2. With earlier version it is possible to iterate over dictionary keys like the last example above demonstrates.
#### [Loop variable conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-405)
[Variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) works also with FOR loop variables. The desired type can be added to any loop variable by using the familiar `${name: type}` syntax.
```
*** Test Cases ***
Variable conversion
FOR ${value: bytes} IN Hello! Hyvä! \x00\x00\x07
Log ${value} formatter=repr
END
FOR ${index} ${date: date} IN ENUMERATE 2023-06-15 2025-05-30 today
Log ${date} formatter=repr
END
FOR ${item: tuple[str, date]} IN ENUMERATE 2023-06-15 2025-05-30 today
Log ${item} formatter=repr
END
```
Note
Variable type conversion is new in Robot Framework 7.3.
#### [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-406)
`FOR` loops with multiple iterations often create lots of output and considerably increase the size of the generated [output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) files. It is possible to [remove or flatten unnecessary keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) using \--removekeywords and \--flattenkeywords command line options.
#### [Repeating single keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-407)
`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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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.
```
*** Test Cases ***
Example
Repeat Keyword 5 Some Keyword arg1 arg2
Repeat Keyword 42 times My Keyword
Repeat Keyword ${var} Another Keyword argument
```
### [2\.9.2 `WHILE loops`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-408)
`WHILE` loops combine features of [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) and [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures). They specify a condition and repeat the loop body as long as the condition remains true. This can be utilised, for example, to repeat a nondeterministic sequence until the desired outcome happens, or in some cases they can be used as an alternative to [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops).
Note
`WHILE` loops are new in Robot Framework 5.0.
#### [Basic `WHILE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-409)
```
*** Test Cases ***
Example
VAR ${rc} 1
WHILE ${rc} != 0
${rc} = Keyword that returns zero on success
END
```
The `WHILE` loop condition is evaluated in Python so that Python builtins like `len()` are available and modules are imported automatically to support usages like `math.pi * math.pow(${radius}, 2) < 10`. Normal variables like `${rc}` in the above example are replaced before evaluation, but variables are also available in the evaluation namespace using the special `$rc` syntax. The latter approach is handy when the string representation of the variable cannot be used in the condition directly. For example, strings require quoting and multiline strings and string themselves containing quotes cause additional problems. See the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix for more information and examples related to the evaluation syntax.
Starting from Robot Framework 6.1, the condition in a `WHILE` statement can be omitted. This is interpreted as the condition always being true, which may be useful with the `limit` option described below.
#### [Limiting `WHILE` loop iterations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-410)
With `WHILE` loops, there is always a possibility to achieve an infinite loop, either by intention or by mistake. This happens when the loop condition never becomes false. While infinite loops have some utility in application programming, in automation an infinite loop is rarely a desired outcome. If such a loop occurs with Robot Framework, the execution must be forcefully stopped and no log or report can be created. For this reason, `WHILE` loops in Robot Framework have a default limit of 10 000 iterations. If the limit is exceeded, the loop fails.
The limit can be set with the `limit` configuration parameter either as a maximum iteration count or as a maximum time for the whole loop. When the limit is an iteration count, it is possible to use just integers like `100` and to add `times` or `x` suffix after the value like `100 times`. When the limit is a timeout, it is possible to use [time strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format) like `10 s` or `1 hour 10 minutes`. The limit can also be disabled altogether by using `NONE` (case-insensitive). All these options are illustrated by the examples below.
```
*** Test Cases ***
Limit as iteration count
WHILE True limit=100
Log This is run 100 times.
END
WHILE True limit=10 times
Log This is run 10 times.
END
WHILE True limit=42x
Log This is run 42 times.
END
Limit as time
WHILE True limit=10 seconds
Log This is run 10 seconds.
END
No limit
WHILE True limit=NONE
Log This runs forever.
END
```
Note
Support for using `times` and `x` suffixes with iteration counts is new in Robot Framework 7.0.
Keywords in a loop are not forcefully stopped if the limit is exceeded. Instead the loop is exited similarly as if the loop condition would have become false. A major difference is that the loop status will be `FAIL` in this case.
Starting from Robot Framework 6.1, it is possible to use `on_limit` parameter to configure the behaviour when the limit is exceeded. It supports two values `pass` and `fail`, case insensitively. If the value is `pass`, the execution will continue normally when the limit is reached and the status of the `WHILE` loop will be `PASS`. The value `fail` works similarly as the default behaviour, e.g. the loop and the test will fail if the limit is exceeded.
```
*** Test Cases ***
Continue when iteration limit is reached
WHILE True limit=5 on_limit=pass
Log Loop will be executed five times
END
Log This will be executed normally.
Continue when time limit is reached
WHILE True limit=10s on_limit=pass
Log Loop will be executed for 10 seconds.
Sleep 0.5s
END
Log This will be executed normally.
```
By default, the error message raised when the limit is reached is . Starting from Robot Framework 6.1, the error message can be changed with the `on_limit_message` configuration parameter.
```
*** Test Cases ***
Limit as iteration count
WHILE True limit=0.5s on_limit_message=Custom While loop error message
Log This is run 0.5 seconds.
END
```
Note
`on_limit_message` configuration parameter is new in Robot Framework 6.1.
#### [Nesting `WHILE` loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-411)
`WHILE` loops can be nested and also combined with other control structures:
```
*** Test Cases ***
Nesting WHILE
VAR ${x} 10
WHILE ${x} > 0
VAR ${y} ${x}
WHILE ${y} > 0
${y} = Evaluate ${y} - 1
END
IF ${x} > 5
${x} = Evaluate ${x} - 1
ELSE
${x} = Evaluate ${x} - 2
END
END
```
#### [Removing unnecessary keywords from outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-412)
`WHILE` loops with multiple iterations often create lots of output and considerably increase the size of the generated [output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) files. It is possible to [remove or flatten unnecessary keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) using \--removekeywords and \--flattenkeywords command line options.
### [2\.9.3 Loop control using `BREAK` and `CONTINUE`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-413)
Both [FOR](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for) and [WHILE](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while) loop execution can be controlled with `BREAK` and `CONTINUE` statements. The former exits the whole loop prematurely and the latter stops executing the current loop iteration and continues to the next one. In practice they have the same semantics as `break` and `continue` statements in Python, Java, and many other programming languages.
Both `BREAK` and `CONTINUE` are typically used conditionally with [IF/ELSE](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else) or [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except) structures, and especially the [inline IF](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-if) syntax is often convenient with them. These statements must be used in the loop body, possibly inside the aforementioned control structures, and using them in keyword called in the loop body is invalid.
```
*** Test Cases ***
BREAK with FOR
${text} = Set Variable zero
FOR ${var} IN one two three
IF '${var}' == 'two' BREAK
${text} = Set Variable ${text}-${var}
END
Should Be Equal ${text} zero-one
CONTINUE with FOR
${text} = Set Variable zero
FOR ${var} IN one two three
IF '${var}' == 'two' CONTINUE
${text} = Set Variable ${text}-${var}
END
Should Be Equal ${text} zero-one-three
CONTINUE and BREAK with WHILE
WHILE True
TRY
${value} = Do Something
EXCEPT
CONTINUE
END
Do something with value ${value}
BREAK
END
Invalid BREAK usage
[Documentation] BREAK and CONTINUE can only be used in the loop body,
... not in keywords used in the loop.
FOR ${var} IN one two three
Invalid BREAK
END
*** Keywords ***
Invalid BREAK
[Documentation] This keyword fails due to invalid syntax.
BREAK
```
Note
`BREAK` and `CONTINUE` statements are new in Robot Framework 5.0 similarly as `WHILE`. Earlier versions supported controlling `FOR` loops using [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Exit For Loop, Exit For Loop If, Continue For Loop and Continue For Loop If. These keywords still continue to work, but they will be deprecated and removed in the future.
Note
Also the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement can be used to a exit loop. It only works when loops are used inside a [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords).
### [2\.9.4 `IF/ELSE` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-414)
Sometimes there is a need to execute some keywords conditionally. Starting from Robot Framework 4.0 there is a separate `IF/ELSE` syntax, but there are also [other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-execute-keywords-conditionally). Notice that if the logic gets complicated, it is typically better to move it into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries).
#### [Basic `IF` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-415)
Robot Framework's native `IF` syntax starts with `IF` (case-sensitive) and ends with `END` (case-sensitive). The `IF` marker requires exactly one value that is the condition to evaluate. Keywords to execute if the condition is true are on their own rows between the `IF` and `END` markers. Indenting keywords in the `IF` block is highly recommended but not mandatory.
In the following example keywords Some keyword and Another keyword are executed if `${rc}` is greater than zero:
```
*** Test Cases ***
Example
IF ${rc} > 0
Some keyword
Another keyword
END
```
The condition is evaluated in Python so that Python builtins like `len()` are available and modules are imported automatically to support usages like `platform.system() == 'Linux'` and `math.ceil(${x}) == 1`. Normal variables like `${rc}` in the above example are replaced before evaluation, but variables are also available in the evaluation namespace using the special `$rc` syntax. The latter approach is handy when the string representation of the variable cannot be used in the condition directly. For example, strings require quoting and multiline strings and string themselves containing quotes cause additional problems. For more information and examples related the evaluation syntax see the [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix.
#### [`ELSE` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-416)
Like most other languages supporting conditional execution, Robot Framework `IF` syntax also supports `ELSE` branches that are executed if the `IF` condition is not true.
In this example Some keyword is executed if `${rc}` is greater than zero and Another keyword is executed otherwise:
```
*** Test Cases ***
Example
IF ${rc} > 0
Some keyword
ELSE
Another keyword
END
```
#### [`ELSE IF` branches](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-417)
Robot Framework also supports `ELSE IF` branches that have their own condition that is evaluated if the initial condition is not true. There can be any number of `ELSE IF` branches and they are gone through in the order they are specified. If one of the `ELSE IF` conditions is true, the block following it is executed and remaining `ELSE IF` branches are ignored. An optional `ELSE` branch can follow `ELSE IF` branches and it is executed if all conditions are false.
In the following example different keyword is executed depending on is `${rc}` positive, negative, zero, or something else like a string or `None`:
```
*** Test Cases ***
Example
IF $rc > 0
Positive keyword
ELSE IF $rc < 0
Negative keyword
ELSE IF $rc == 0
Zero keyword
ELSE
Fail Unexpected rc: ${rc}
END
```
Notice that this example uses the `${rc}` variable in the special `$rc` format to avoid evaluation failures if it is not a number. See the aforementioned [Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions) appendix for more information about this syntax.
#### [Inline `IF`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-418)
Normal `IF/ELSE` structure is a bit verbose if there is a need to execute only a single statement. An alternative to it is using inline `IF` syntax where the statement to execute follows the `IF` marker and condition directly and no `END` marker is needed. For example, the following two keywords are equivalent:
```
*** Keywords ***
Normal IF
IF $condition1
Keyword argument
END
IF $condition2
RETURN
END
Inline IF
IF $condition1 Keyword argument
IF $condition2 RETURN
```
The inline `IF` syntax supports also `ELSE` and `ELSE IF` branches:
```
*** Keywords ***
Inline IF/ELSE
IF $condition Keyword argument ELSE Another Keyword
Inline IF/ELSE IF/ELSE
IF $cond1 Keyword 1 ELSE IF $cond2 Keyword 2 ELSE IF $cond3 Keyword 3 ELSE Keyword 4
```
As the latter example above demonstrates, inline `IF` with several `ELSE IF` and `ELSE` branches starts to get hard to understand. Long inline `IF` structures can be [split into multiple lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows) using the common `...` continuation syntax, but using a normal `IF/ELSE` structure or moving the logic into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) is probably a better idea. Each inline `IF` branch can contain only one statement. If more statements are needed, normal `IF/ELSE` structure needs to be used instead.
If there is a need for an assignment with inline `IF`, the variable or variables to assign must be before the starting `IF`. Otherwise the logic is exactly the same as when [assigning variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) based on keyword return values. If assignment is used and no branch is run, the variable gets value `None`.
```
*** Keywords ***
Inline IF/ELSE with assignment
${var} = IF $condition Keyword argument ELSE Another Keyword
Inline IF/ELSE with assignment having multiple variables
${host} ${port} = IF $production Get Production Config ELSE Get Testing Config
```
Note
Inline `IF` syntax is new in Robot Framework 5.0.
#### [Nested `IF` structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-419)
`IF` structures can be nested with each others and with [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops). This is illustrated by the following example using advanced features such as [FOR-IN-ENUMERATE loop](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-in-enumerate-loop), [named-only arguments with user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-user-keywords) and [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) syntax (`${{len(${items})}}`):
```
*** Keywords ***
Log items
[Arguments] @{items} ${log_values}=True
IF not ${items}
Log to console No items.
ELSE IF len(${items}) == 1
IF ${log_values}
Log to console One item: ${items}[0]
ELSE
Log to console One item.
END
ELSE
Log to console ${{len(${items})}} items.
IF ${log_values}
FOR ${index} ${item} IN ENUMERATE @{items} start=1
Log to console Item ${index}: ${item}
END
END
END
*** Test Cases ***
No items
Log items
One item without logging value
Log items xxx log_values=False
Multiple items
Log items a b c
```
#### [Other ways to execute keywords conditionally](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-420)
There are also other methods to execute keywords conditionally:
- The name of the keyword used as a setup or a teardown with [suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown), [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown) can be specified using a variable. This facilitates changing them, for example, from the command line.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Run Keyword If and Run Keyword Unless execute a named keyword only if a certain expression is true or false, respectively. The new `IF/ELSE` syntax explained above is generally recommended, though.
- Another [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword, Set Variable If, can be used to set variables dynamically based on a given expression.
- There are several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords that allow executing a named keyword only if a test case or test suite has failed or passed.
### [2\.9.5 `TRY/EXCEPT` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-421)
When a keyword fails, Robot Framework's default behavior is to stop the current test and executes its possible [teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). There can, however, be needs to handle these failures during execution as well. Robot Framework 5.0 introduces native `TRY/EXCEPT` syntax for this purpose, but there also [other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#other-ways-to-handle-errors).
Robot Framework's `TRY/EXCEPT` syntax is inspired by Python's [exception handling](https://docs.python.org/tutorial/errors.html#handling-exceptions) syntax. It has same `TRY`, `EXCEPT`, `ELSE` and `FINALLY` branches as Python and they also mostly work the same way. A difference is that Python uses lower case `try`, `except`, etc. but with Robot Framework all this kind of syntax must use upper case letters. A bigger difference is that with Python exceptions are objects and with Robot Framework you are dealing with error messages as strings.
Note
It is not possible to catch errors caused by invalid syntax or errors that [stop the whole execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully).
#### [Catching exceptions with `EXCEPT`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-422)
The basic `TRY/EXCEPT` syntax can be used to handle failures based on error messages:
```
*** Test Cases ***
First example
TRY
Some Keyword
EXCEPT Error message
Error Handler Keyword
END
Keyword Outside
```
In the above example, if `Some Keyword` passes, the `EXCEPT` branch is not run and execution continues after the `TRY/EXCEPT` structure. If the keyword fails with a message `Error message` (case-sensitive), the `EXCEPT` branch is executed. If the `EXCEPT` branch succeeds, execution continues after the `TRY/EXCEPT` structure. If it fails, the test fails and remaining keywords are not executed. If `Some Keyword` fails with any other exception, that failure is not handled and the test fails without executing remaining keywords.
There can be more than one `EXCEPT` branch. In that case they are matched one by one and the first matching branch is executed. One `EXCEPT` can also have multiple messages to match, and such a branch is executed if any of its messages match. In all these cases messages can be specified using variables in addition to literal strings.
```
*** Test Cases ***
Multiple EXCEPT branches
TRY
Some Keyword
EXCEPT Error message # Try matching this first.
Error Handler 1
EXCEPT Another error # Try this if above did not match.
Error Handler 2
EXCEPT ${message} # Last match attempt, this time using a variable.
Error Handler 3
END
Multiple messages with one EXCEPT
TRY
Some Keyword
EXCEPT Error message Another error ${message} # Match any of these.
Error handler
END
```
It is also possible to have an `EXCEPT` without messages, in which case it matches any error. There can be only one such `EXCEPT` and it must follow possible other `EXCEPT` branches:
```
*** Test Cases ***
Match any error
TRY
Some Keyword
EXCEPT # Match any error.
Error Handler
END
Match any after testing more specific errors
TRY
Some Keyword
EXCEPT Error message # Try matching this first
Error Handler 1
EXCEPT # Match any that did not match the above.
Error Handler 2
END
```
#### [Matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-423)
By default matching an error using `EXCEPT` requires an exact match. That can be changed using a configuration option `type=` as an argument to the except clause. Valid values for the option are `GLOB`, `REGEXP` or `START` (case-insensitive) to make the match a [glob pattern match](https://en.wikipedia.org/wiki/Glob_\(programming\)), a [regular expression match](https://en.wikipedia.org/wiki/Regular_expression), or to match only the beginning of the error, respectively. Using value `LITERAL` has the same effect as the default behavior. If an `EXCEPT` has multiple messages, this option applies to all of them. The value of the option can be defined with a variable as well.
```
*** Variables ***
${MATCH TYPE} regexp
*** Test Cases ***
Glob pattern
TRY
Some Keyword
EXCEPT ValueError: * type=GLOB
Error Handler 1
EXCEPT [Ee]rror ?? occurred ${pattern} type=glob
Error Handler 2
END
Regular expression
TRY
Some Keyword
EXCEPT ValueError: .* type=${MATCH TYPE}
Error Handler 1
EXCEPT [Ee]rror \\d+ occurred type=Regexp # Backslash needs to be escaped.
Error Handler 2
END
Match start
TRY
Some Keyword
EXCEPT ValueError: ${beginning} type=start
Error Handler
END
Explicit exact match
TRY
Some Keyword
EXCEPT ValueError: invalid literal for int() with base 10: 'ooops' type=LITERAL
Error Handler
EXCEPT Error 13 occurred type=LITERAL
Error Handler 2
END
```
Note
Remember that the backslash character often used with regular expressions is an [escape character](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) in Robot Framework data. It thus needs to be escaped with another backslash when using it in regular expressions.
#### [Capturing error message](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-424)
When [matching errors using patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#matching-errors-using-patterns) and when using `EXCEPT` without any messages to match any error, it is often useful to know the actual error that occurred. Robot Framework supports that by making it possible to capture the error message into a variable by adding `AS ${var}` at the end of the `EXCEPT` statement:
```
*** Test Cases ***
Capture error
TRY
Some Keyword
EXCEPT ValueError: * type=GLOB AS ${error}
Error Handler 1 ${error}
EXCEPT [Ee]rror \\d+ (Invalid|Bad) usage type=REGEXP AS ${error}
Error Handler 2 ${error}
EXCEPT AS ${error}
Error Handler 3 ${error}
END
```
#### [Using `ELSE` to execute keywords when there are no errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-425)
Optional `ELSE` branches make it possible to execute keywords if there is no error. There can be only one `ELSE` branch and it is allowed only after one or more `EXCEPT` branches:
```
*** Test Cases ***
ELSE branch
TRY
Some Keyword
EXCEPT X
Log Error 'X' occurred!
EXCEPT Y
Log Error 'Y' occurred!
ELSE
Log No error occurred!
END
Keyword Outside
```
In the above example, if `Some Keyword` passes, the `ELSE` branch is executed, and if it fails with message `X` or `Y`, the appropriate `EXCEPT` branch run. In all these cases execution continues after the whole `TRY/EXCEPT/ELSE` structure. If `Some Keyword` fail any other way, `EXCEPT` and `ELSE` branches are not run and the `TRY/EXCEPT/ELSE` structure fails.
To handle both the case when there is any error and when there is no error, it is possible to use an `EXCEPT` without any message in combination with an `ELSE`:
```
*** Test Cases ***
Handle everything
TRY
Some Keyword
EXCEPT AS ${err}
Log Error occurred: ${err}
ELSE
Log No error occurred!
END
```
#### [Using `FINALLY` to execute keywords regardless are there errors or not](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-426)
Optional `FINALLY` branches make it possible to execute keywords both when there is an error and when there is not. They are thus suitable for cleaning up after a keyword execution somewhat similarly as [teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). There can be only one `FINALLY` branch and it must always be last. They can be used in combination with `EXCEPT` and `ELSE` branches and having also `TRY/FINALLY` structure is possible:
```
*** Test Cases ***
TRY/EXCEPT/ELSE/FINALLY
TRY
Some keyword
EXCEPT
Log Error occurred!
ELSE
Log No error occurred.
FINALLY
Log Always executed.
END
TRY/FINALLY
Open Connection
TRY
Use Connection
FINALLY
Close Connection
END
```
#### [Other ways to handle errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-427)
There are also other methods to execute keywords conditionally:
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Expect Error executes a named keyword and expects that it fails with a specified error message. It is basically the same as using `TRY/EXCEPT` with a specified message. The syntax to specify the error message is also identical except that this keyword uses glob pattern matching, not exact match, by default. Using the native `TRY/EXCEPT` functionality is generally recommended unless there is a need to support older Robot Framework versions that do not support it.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Ignore Error executes a named keyword and returns its status as string `PASS` or `FAIL` along with possible return value or error message. It is basically the same as using `TRY/EXCEPT/ELSE` so that `EXCEPT` catches all errors. Using the native syntax is recommended unless old Robot Framework versions need to be supported.
- The [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Run Keyword And Return Status executes a named keyword and returns its status as a Boolean true or false. It is a wrapper for the aforementioned Run Keyword And Ignore Error. The native syntax is nowadays recommended instead.
- [Test teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [keyword teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown) can be used for cleaning up activities similarly as `FINALLY` branches.
- When keywords are implemented in Python based [libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries), all Python's error handling features are readily available. This is the recommended approach especially if needed logic gets more complicated.
### [2\.9.6 `GROUP` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-428)
The `GROUP` syntax allows grouping related keywords and control structures together:
```
*** Test Cases ***
Valid login
GROUP Open browser to login page
Open Browser ${LOGIN URL}
Title Should Be Login Page
END
GROUP Submit credentials
Input Username username_field demo
Input Password password_field mode
Click Button login_button
END
GROUP Login should have succeeded
Title Should Be Welcome Page
END
Anonymous group
GROUP
Log Group name is optional.
END
Nesting
GROUP
GROUP Nested group
Log Groups can be nested.
END
IF True
GROUP
Log Groups can also be nested with other control structures.
END
END
END
```
As the above examples demonstrates, groups can have a name, but the name is optional. Groups can also be nested freely with each others and with other control structures.
[User keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) are in general recommended over the `GROUP` syntax, because they are reusable and because they simplify tests or keywords where they are used by hiding and encapsulating lower level details. In the log file user keywords and groups look the same, though, except that instead of a `KEYWORD` label there is a `GROUP` label.
All groups within a test or a keyword share the same variable namespace. This means that, unlike when using keywords, there is no need to use arguments or return values for sharing values. This can be a benefit in simple cases, but if there are lot of variables, the benefit can turn into a problem and cause a huge mess.
Note
The `GROUP` syntax is new in Robot Framework 7.2.
#### [`GROUP` with templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-429)
The `GROUP` syntax can be used for grouping iterations with [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates):
```
*** Settings ***
Library String
Test Template Upper case should be
*** Test Cases ***
Template example
GROUP ASCII characters
a A
z Z
END
GROUP Latin-1 characters
ä Ä
ß SS
END
GROUP Numbers
1 1
9 9
END
*** Keywords ***
Upper case should be
[Arguments] ${char} ${expected}
${actual} = Convert To Upper Case ${char}
Should Be Equal ${actual} ${expected}
```
#### [Programmatic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-430)
One of the primary usages for groups is making it possible to create structured tests and user keywords programmatically. For example, the following [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) adds a group with two keywords at the end of each modified test. Groups can be added also by [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) that use the [listener API version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
```
from robot.api import SuiteVisitor
class GroupAdder(SuiteVisitor):
def start_test(self, test):
group = test.body.create_group(name='Example')
group.body.create_keyword(name='Log', args=['Hello, world!'])
group.body.create_keyword(name='No Operation')
```
## [2\.10 Advanced features](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-258)
- [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names)
- [Keyword scopes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-scopes)
- [Specifying a keyword explicitly](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-a-keyword-explicitly)
- [Specifying explicit priority between libraries and resources](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-explicit-priority-between-libraries-and-resources)
- [2\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts)
- [Test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout)
- [User keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout)
- [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parallel-execution-of-keywords)
### [2\.10.1 Handling keywords with same names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-431)
Keywords that are used with Robot Framework are either [library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) or [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). The former come from [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) or [external libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-libraries), and the latter are either created in the same file where they are used or then imported from [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-432)
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 currently executed [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-433)
Scopes do not help if keywords with same names exists in two different libraries or in two different resource files. In addition to that, scopes do not help if a keyword in library should be used instead of a keyword with the same name in a resource file. In such cases, it is possible to use *the full keyword name*, where the keyword name is prefixed with the name of a library or a resource and a dot is used as a separator.
With library keywords, the full name means using format LibraryName.Keyword Name. For example, the keyword Get File from the [OperatingSystem](https://robotframework.org/robotframework/latest/libraries/OperatingSystem.html) library can be used as OperatingSystem.Get File, even if there was another Get File keyword somewhere else. If the library is implemented in a nested module, the full name must contain the full module name like root.sub.Library.Keyword. If a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) is given to a library when importing it, the specified name must be used also in the full keyword name.
With user keywords in resource files the full name is constructed the same way as with library keywords. The name of the resource is derived from the basename of the resource file without the file extension. For example, a keyword Some Keyword in a resource file example.resource can be used like example.Some Keyword. Note that this syntax does not work if several resource files have the same basename. In such cases, either resource files or keywords must be renamed.
With user keywords in a [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), the full name contains only the keyword name without any prefix.
When comparing full keyword names, the library/resource part is case and space-insensitive and the keyword part is case, space and underscore-insensitive.
#### [Specifying explicit priority between libraries and resources](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-434)
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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library.
Note
Although the keyword has the word *library* in its name, it works also with resource files. 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\.10.2 Timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-435)
Sometimes keywords may take exceptionally long time to execute or just hang endlessly. Robot Framework allows you to set timeouts both for [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-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, the test environment or the 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.
#### [Test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-436)
The test case timeout can be set either by using the Test Timeout setting in the Setting section or the \[Timeout\] setting with individual test cases. Test Timeout defines a default timeout for all the test cases in that suite, whereas \[Timeout\] applies a timeout to a particular 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. It is also possible to use explicit `NONE` value for this purpose. The timeout is effectively ignored also if its value is zero or negative.
Regardless of where the test timeout is defined, the value given to it contains the duration of the timeout. The duration must be given in Robot Framework's [time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format), that is, either directly in seconds like `10` or in a format like `1 minute 30 seconds`. Timeouts can also be specified as [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) making it possible to give them, for example, from the command line.
If there is a timeout and it expires, the keyword that is currently running is stopped and the test case fails. Keywords executed as part of [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) are not interrupted if a test timeout occurs, though, but the test is nevertheless marked failed. If a keyword in teardown may hang, it can be stopped by using [user keyword timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout).
```
*** Settings ***
Test Timeout 2 minutes
*** Test Cases ***
Default timeout
[Documentation] Default timeout from Settings is used.
Some Keyword argument
Override
[Documentation] Override default, use 10 seconds timeout.
[Timeout] 10
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] Disabling timeout with NONE works too and is more explicit.
[Timeout] NONE
Some Keyword argument
```
#### [User keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-437)
Timeouts can be set for user keywords using the \[Timeout\] setting. The syntax is exactly the same as with [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout), but user keyword timeouts do not have any default value. If a user keyword timeout is specified using a variable, the value can be given also as a keyword argument.
```
*** Keywords ***
Hardcoded
[Arguments] ${arg}
[Timeout] 1 minute 42 seconds
Some Keyword ${arg}
Configurable
[Arguments] ${arg} ${timeout}
[Timeout] ${timeout}
Some Keyword ${arg}
Run Keyword with Timeout
[Arguments] ${keyword} @{args} &{kwargs} ${timeout}=1 minute
[Documentation] Wrapper that runs another keyword with a configurable timeout.
[Timeout] ${timeout}
Run Keyword ${keyword} @{args} &{kwargs}
```
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.
Note
With earlier Robot Framework versions it was possible to specify a custom error message to use if a timeout expires. This functionality was deprecated in Robot Framework 3.0.1 and removed in Robot Framework 3.2.
### [2\.10.3 Parallel execution of keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-438)
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 [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library keywords Start Process and Wait For Process for an example.
## [3 Executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-80)
- [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#basic-usage-1)
- [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-execution)
- [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution)
- [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs)
- [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution)
- [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-files)
## [3\.1 Basic usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-439)
Robot Framework test cases are executed from the command line, and the end result is, by default, an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) in XML format and an HTML [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). After the execution, output files can be combined and otherwise [post-processed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs) with the Rebot tool.
- [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution)
- [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#synopsis)
- [Specifying test data to be executed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-executed)
- [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-command-line-options)
- [Using options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-options)
- [Short and long options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#short-and-long-options)
- [Setting option values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-option-values)
- [Disabling options accepting no values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-options-accepting-no-values)
- [Simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns)
- [Tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns)
- [ROBOT\_OPTIONS and REBOT\_OPTIONS environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-options-and-rebot-options-environment-variables)
- [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-results)
- [Command line output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-output)
- [Generated output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generated-output-files)
- [Return codes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes)
- [Errors and warnings during execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution)
- [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files)
- [Argument file syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-file-syntax)
- [Expanding environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#expanding-environment-variables)
- [Using argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-argument-files)
- [Reading argument files from standard input](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reading-argument-files-from-standard-input)
- [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information)
- [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-start-up-scripts)
- [Shell script example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#shell-script-example)
- [Batch file example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#batch-file-example)
- [Python example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-example)
- [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#making-robot-files-executable)
- [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems)
- [Using the Python debugger (pdb)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-the-python-debugger-pdb)
### [3\.1.1 Starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-445)
#### [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-446)
```
robot [options] data
python -m robot [options] data
python path/to/robot/ [options] data
```
Execution is normally started using the robot command created as part of [installation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#installation-instructions). Alternatively it is possible to execute the installed robot module using the selected Python interpreter. This is especially convenient if Robot Framework has been installed under multiple Python versions. Finally, if you know where the installed robot directory exists, it can be executed using Python as well.
Regardless of execution approach, the path (or paths) to the test data to be executed is given as an argument after the command. Additionally, different command line options can be used to alter the test execution or generated outputs in many ways.
#### [Specifying test data to be executed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-447)
Robot Framework test cases are created in [files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) and [directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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, by default, gets its name from the [file or directory name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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 robot script is used, but other execution approaches could be used similarly.
```
robot tests.robot
robot path/to/my_tests/
robot c:\robot\tests.robot
```
Note
When executing a [directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories), all files and directories starting with a dot (.) or an underscore (\_) are ignored and, by default, only files with the .robot extension executed. See the [Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) section for more details.
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 concatenating 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:
```
robot my_tests.robot your_tests.robot
robot --name Example path/to/tests/pattern_*.robot
```
Starting from Robot Framework 6.1, it is also possible to define a [test suite initialisation file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) for the automatically created top-level suite. The path to the init file is given similarly to the test case files:
```
robot __init__.robot my_tests.robot other_tests.robot
```
### [3\.1.2 Using command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-448)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-449)
When options are used, they must always be given between the runner script and the data sources. For example:
```
robot -L debug my_tests.robot
robot --include smoke --variable HOST:10.0.0.42 path/to/tests/
```
#### [Short and long options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-450)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-scripts), because they are easier to understand.
The long option names are case-insensitive and hyphen-insensitive, which facilitates writing option names in an easy-to-read format. For example, \--SuiteStatLevel and \--suite-stat-level are equivalent to, but easier to read than, \--suitestatlevel.
Note
Long options being hyphen-insensitive is new in Robot Framework 6.1.
#### [Setting option values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-451)
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.
#### [Disabling options accepting no values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-452)
Options accepting no values can be disabled by using the same option again with `no` prefix added or dropped. The last option has precedence regardless of how many times options are used. For example, would not activate the dry-run mode and would return normal status rc.
#### [Simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-453)
Many command line options take arguments as *simple patterns*. These [glob-like patterns](http://en.wikipedia.org/wiki/Glob_\(programming\)) are matched according to the following rules:
- `*` matches any string, even an empty string.
- `?` matches any single character.
- `[abc]` matches one character in the bracket.
- `[!abc]` matches one character not in the bracket.
- `[a-z]` matches one character from the range in the bracket.
- `[!a-z]` matches one character not from the range in the bracket.
- Unlike with glob patterns normally, path separator characters `/` and \\ and the newline character `\n` are matches by the above wildcards.
- Unless noted otherwise, pattern matching is case, space, and underscore insensitive.
Examples:
```
--test Example* # Matches tests with name starting 'Example'.
--test Example[1-2] # Matches tests 'Example1' and 'Example2'.
--include f?? # Matches tests with a tag that starts with 'f' is three characters long.
```
All matching in above examples is case, space and underscore insensitive. For example, the second example would also match test named `example 1`.
If the matched text happens to contain some of the wildcard characters and they need to be matched literally, it is possible to do that by using the `[...]` syntax. The pattern `[*]` matches the literal `*` character, `[?]` matches `?`, and `[[]` matches `[`. Lone `[` and `]` do not need to be escaped.
Note
Support for brackets like `[abc]` and `[!a-z]` is new in Robot Framework 3.1.
#### [Tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-454)
Most tag related options accept arguments as *tag patterns*. They support same wildcards as [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) (e.g. `examp??`, `ex*le`), but they also support `AND`, `OR` and `NOT` operators explained below. These operators can be used for combining two or more individual tags or patterns together.
`AND` or `&`
The whole pattern matches if all individual patterns match. `AND` and `&` are equivalent:
```
--include fooANDbar # Matches tests containing tags 'foo' and 'bar'.
--exclude xx&yy&zz # Matches tests containing tags 'xx', 'yy', and 'zz'.
```
`OR`
The whole pattern matches if any individual pattern matches:
```
--include fooORbar # Matches tests containing either tag 'foo' or tag 'bar'.
--exclude xxORyyORzz # Matches tests containing any of tags 'xx', 'yy', or 'zz'.
```
`NOT`
The whole pattern matches if the pattern on the left side matches but the one on the right side does not. If used multiple times, none of the patterns after the first `NOT` must not match:
```
--include fooNOTbar # Matches tests containing tag 'foo' but not tag 'bar'.
--exclude xxNOTyyNOTzz # Matches tests containing tag 'xx' but not tag 'yy' or tag 'zz'.
```
The pattern can also start with `NOT` in which case the pattern matches if the pattern after `NOT` does not match:
```
--include NOTfoo # Matches tests not containing tag 'foo'
--include NOTfooANDbar # Matches tests not containing tags 'foo' and 'bar'
```
The above operators can also be used together. The operator precedence, from highest to lowest, is `AND`, `OR` and `NOT`:
```
--include xANDyORz # Matches tests containing either tags 'x' and 'y', or tag 'z'.
--include xORyNOTz # Matches tests containing either tag 'x' or 'y', but not tag 'z'.
--include xNOTyANDz # Matches tests containing tag 'x', but not tags 'y' and 'z'.
```
Although tag matching itself is case-insensitive, all operators are case-sensitive and must be written with upper case letters. If tags themselves happen to contain upper case `AND`, `OR` or `NOT`, they need to specified using lower case letters to avoid accidental operator usage:
```
--include port # Matches tests containing tag 'port', case-insensitively
--include PORT # Matches tests containing tag 'P' or 'T', case-insensitively
--exclude handoverORportNOTnotification
```
#### [ROBOT\_OPTIONS and REBOT\_OPTIONS environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-455)
Environment variables ROBOT\_OPTIONS and REBOT\_OPTIONS can be used to specify default options for [test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) and [result post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs), respectively. The options and their values must be defined as a space separated list and they are placed in front of any explicit options on the command line. The main use case for these environment variables is setting global default values for certain options to avoid the need to repeat them every time tests are run or Rebot used.
```
export ROBOT_OPTIONS="--outputdir results --tagdoc 'mytag:Example doc with spaces'"
robot tests.robot
export REBOT_OPTIONS="--reportbackground blue:red:yellow"
rebot --name example output.xml
```
### [3\.1.3 Test results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-456)
#### [Command line output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-457)
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 tests, 1 passed, 1 failed
==============================================================================
Output: /path/to/output.xml
Report: /path/to/report.html
Log: /path/to/log.html
```
There is also a notification on the console whenever a top-level keyword in a test case ends. A green dot is used if a keyword passes and a red F if it fails. These markers are written to the end of line and they are overwritten by the test status when the test itself ends. Writing the markers is disabled if console output is redirected to a file.
#### [Generated output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-458)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files).
#### [Return codes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-459)
Runner scripts communicate the overall execution status to the system running them using return codes. When the execution starts successfully and no tests fail, the return code is zero. All possible return codes are explained in the table below.
| RC | Explanation |
|---|---|
| 0 | All tests passed. |
| 1-249 | Returned number of tests failed. |
| 250 | 250 or more failures. |
| 251 | Help or version information printed. |
| 252 | Invalid data or command line option. |
| 253 | 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 the Bash shell the return code is in the `$?` variable, and in Windows it is in the `%ERRORLEVEL%` variable. If you use some external tool for running tests, consult its documentation for how to get the return code.
The return code can be set to zero regardless the execution status by 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 execution can be determined.
Note
Same return codes are also used with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot).
Note
When [getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information), the \--nostatusrc option has an effect only with Robot Framework 7.4 and newer.
#### [Errors and warnings during execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-460)
During the test execution there can be unexpected problems like failing to import a library or a resource file or a keyword being [deprecated](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecating-keywords). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log). Normally these errors and warnings are generated by Robot Framework itself, but libraries can also log [errors and warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-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.robot' in table 'Setting' in element on row 2: Resource file 'resource.robot' does not exist |
| 20090322 19:58:43.931 | WARN | Keyword 'SomeLibrary.Example Keyword' is deprecated. Use keyword \`Other Keyword\` instead. |
### [3\.1.4 Argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-461)
Argument files allow placing all or some command line options and arguments into an external file where they will be read. This avoids the problems with characters that are problematic on the command line. If lot of options or arguments are needed, argument files also prevent the command that is used on the command line growing too long.
Argument files are taken into use with \--argumentfile (-A) option along with possible other command line options.
Note
Unlike other [long command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#short-and-long-options), \--argumentfile cannot be given in shortened format like \--argumentf.
#### [Argument file syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-462)
Argument files can contain both command line options and paths to the executed data, one option or a data source per line. Both short and long options are supported, but the latter are recommended in this context because they are easier to understand. 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 NAME:Hello, world!
# This is a comment
path/to/my/tests
```
In the above example the separator between options and their values is a single space. It is possible to use either an equal sign (=) or any number of spaces. As an example, the following three lines are identical:
```
--name An Example
--name=An Example
--name An Example
```
If argument files contain non-ASCII characters, they must be saved using the UTF-8 encoding. Argument files can use any extension. Typically .txt works fine, but a custom extension like .args can be used to separate argument files from normal text files.
#### [Expanding environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-463)
Starting from Robot Framework 7.4, it is possible to use environment variables in argument files and get them replaced *before* files are processed otherwise. For backwards compatibility reasons, this functionality is not enabled by default, but it is easy to opt-in by starting an argument file with a line `# expandvars: true`. The functionality may be enabled by default in the future, and it is possible to opt-out already now by using `# expandvars: false`.
Environment variables can be used in format `$NAME` and `${NAME}`. In addition to that, default values are supported like `${NAME=default}`. If a literal dollar sign is needed, it can be escaped by doubling it like `$$not_var`:
```
# expandvars: true
--name $NAME
--doc ${NAME}v${VERSION}
--metadata Default:${META=default value}
--metadata Escape:$$100
```
Environment variables are not limited to option values. They can also contain option names, both names and values, and using the comment character even enables conditional options:
```
# expandvars: true
--${NAME} ${VALUE}
${NAME_AND_VALUE}
${COND1=} --metadata COND1:This is enabled by default. Set 'COND1' to '#' to disable.
${COND2=#} --metadata COND2:This is disabled by default. Set 'COND2' to '' to enable.
```
Environment variable names are case-sensitive, limited to ASCII letters, numbers and underscores, and they cannot start with a number. Using a non-existing variable or an invalid variable name causes an error.
#### [Using argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-464)
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. When an argument file is used with other arguments, its contents are placed into the original list of arguments to the same place where the argument file option was. This means that options in argument files can override options before it, and its options can be overridden by options after it. It is possible to use \--argumentfile option multiple times or even recursively:
```
robot --argumentfile all_options_and_arguments.txt
robot --argumentfile defaults.args --name Example tests.robot
robot -A first.txt -A second.txt -A third.txt tests.robot
```
#### [Reading argument files from standard input](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-465)
Special argument file name `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 | robot --argumentfile STDIN
generate_arguments.sh | robot --name Example --argumentfile STDIN tests.robot
```
### [3\.1.5 Getting help and version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-466)
Both when executing tests and when post-processing outputs, it is possible to get command line help with the option \--help (-h). This help text provides version information, a short general introduction and explanation of the available command line options.
It is also possible to get just the version information with the option \--version. This information also contains Python version and the platform type:
```
$ robot --version
Robot Framework 7.4 (Python 3.14.0 on linux)
C:\>rebot --version
Rebot 7.3.1 (Python 3.13.7 on win32)
```
When help or version information is printed to the console, the execution exits with a special [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) 251 by default. Starting from Robot Framework 7.4, the return code can be changed to zero by using the \--nostatusrc option like `robot --version --nostatusrc`.
### [3\.1.6 Creating start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-467)
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.
#### [Shell script example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-468)
In this example, the same web tests in the login directory are executed with different browsers and the results combined afterwards using [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). The script also accepts command line options itself and simply forwards them to the robot command using the handy \$\* variable:
```
#!/bin/bash
robot --name Firefox --variable BROWSER:Firefox --output out/fx.xml --log none --report none $* login
robot --name IE --variable BROWSER:IE --output out/ie.xml --log none --report none $* login
rebot --name Login --outputdir out --output login.xml out/fx.xml out/ie.xml
```
#### [Batch file example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-469)
Implementing the above shell script example using batch files is not very complicated either. Notice that arguments to batch files can be forwarded to executed commands using %\*:
```
@echo off
robot --name Firefox --variable BROWSER:Firefox --output out\fx.xml --log none --report none %* login
robot --name IE --variable BROWSER:IE --log none --output out\ie.xml --report none %* login
rebot --name Login --outputdir out --output login.xml out\fx.xml out\ie.xml
```
Note
Prior to Robot Framework 3.1 robot and rebot commands were implemented as batch files on Windows and using them in another batch file required prefixing the whole command with call.
#### [Python example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-470)
When start-up scripts gets more complicated, implementing them using shell scripts or batch files is not that convenient. This is especially true if both variants are needed and same logic needs to be implemented twice. In such situations it is often better to switch to Python. It is possible to execute Robot Framework from Python using the [subprocess module](https://docs.python.org/library/subprocess.html), but often using Robot Framework's own [programmatic API](https://robot-framework.readthedocs.io/) is more convenient. The easiest APIs to use are robot.run\_cli and robot.rebot\_cli that accept same command line arguments than the robot and rebot commands.
The following example implements the same logic as the earlier shell script and batch file examples. In Python arguments to the script itself are available in sys.argv:
```
#!/usr/bin/env python
import sys
from robot import run_cli, rebot_cli
common = ['--log', 'none', '--report', 'none'] + sys.argv[1:] + ['login']
run_cli(['--name', 'Firefox', '--variable', 'BROWSER:Firefox', '--output', 'out/fx.xml'] + common, exit=False)
run_cli(['--name', 'IE', '--variable', 'BROWSER:IE', '--output', 'out/ie.xml'] + common, exit=False)
rebot_cli(['--name', 'Login', '--outputdir', 'out', 'out/fx.xml', 'out/ie.xml'])
```
Note
exit=False is needed because by default run\_cli exits to system with the correct [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes). rebot\_cli does that too, but in the above example that is fine.
### [3\.1.7 Making \*.robot files executable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-471)
On UNIX-like operating systems it is possible to make \*.robot files executable by giving them execution permission and adding a [shebang](https://en.wikipedia.org/wiki/Shebang_\(Unix\)) like in this example:
```
#!/usr/bin/env robot
*** Test Cases ***
Example
Log to console Executing!
```
If the above content would be in a file example.robot and that file would be executable, it could be executed from the command line like below. Starting from Robot Framework 3.2, individually executed files can have any extension, or no extension at all, so the same would work also if the file would be named just example.
```
./example.robot
```
This trick does not work when executing a directory but can be handy when executing a single file. It is probably more often useful when [automating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) than when automating tests.
### [3\.1.8 Debugging problems](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-472)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-output) and in the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file), and sometimes the error message alone is enough to pinpoint the problem. More often that not, however, [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#communicating-with-robot-framework) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). 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 library keyword.
Logged tracebacks do not contain information about methods inside Robot Framework itself. If you suspect an error is caused by a bug in the framework, you can enable showing internal traces by setting environment variable ROBOT\_INTERNAL\_TRACES to any non-empty value.
If the log file still does not have enough information, it is a good idea to enable the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Log and Log Variables are useful. If nothing else works, it is always possible to search help from [mailing lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists) or elsewhere.
#### [Using the Python debugger (pdb)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-473)
It is also possible to use the [pdb](http://docs.python.org/library/pdb.html) module from the Python standard library to set a break point and interactively debug a running test. The typical way of invoking pdb by inserting:
```
import pdb; pdb.set_trace()
```
at the location you want to break into debugger will not work correctly with Robot Framework, as the standard output stream is redirected during keyword execution. Instead, you can use the following:
```
import sys, pdb; pdb.Pdb(stdout=sys.__stdout__).set_trace()
```
from within a python library or alternatively:
```
Evaluate pdb.Pdb(stdout=sys.__stdout__).set_trace() modules=sys, pdb
```
can be used directly in a test case.
## [3\.2 Test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-440)
This section describes how the test suite structure created from the parsed test data is executed, how test status is determined, and how to continue executing a test case if there are failures, and how to stop the whole test execution gracefully.
- [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-flow)
- [Executed suites and tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executed-suites-and-tests)
- [Setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns)
- [Execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-order)
- [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-and-suite-statuses)
- [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pass)
- [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#fail)
- [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip)
- [Migrating from criticality to SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#migrating-from-criticality-to-skip)
- [Suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-status)
- [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuing-on-failure)
- [Execution continues on teardowns automatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-continues-on-teardowns-automatically)
- [All top-level keywords are executed when tests have templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#all-top-level-keywords-are-executed-when-tests-have-templates)
- [Special failures from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#special-failures-from-keywords)
- [Run Keyword And Continue On Failure keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#run-keyword-and-continue-on-failure-keyword)
- [Enabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#enabling-continue-on-failure-using-tags)
- [Disabling continue-on-failure using tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags)
- [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-1)
- [BuiltIn keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#builtin-keywords)
- [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully)
- [Pressing `Ctrl-C`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pressing-ctrl-c)
- [Using signals](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-signals)
- [Using keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-keywords)
- [Stopping when first test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-when-first-test-case-fails)
- [Stopping using `robot:exit-on-failure` tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-using-robot-exit-on-failure-tag)
- [Stopping on parsing or execution error](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error)
- [Handling teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-teardowns)
### [3\.2.1 Execution flow](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-474)
#### [Executed suites and tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-475)
Test cases are always executed within a test suite. A test suite created from a [suite file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) has tests directly, whereas suites created from [directories](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). The exact [execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#execution-order) and how possible [setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns) affect the execution are discussed in the following sections.
#### [Setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-476)
Setups and teardowns can be used on [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown), [test case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown) and [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup-and-teardown) levels.
##### 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 contain are marked 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) 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 test setup 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.
##### User keyword setup
User keyword setup is executed before the keyword body. If the setup fails, the body is not executed. There is not much difference between the keyword setup and the first keyword in the body.
Note
User keyword setups are new in Robot Framework 7.0.
##### User keyword teardown
User keyword teardown is run after the keyword is executed otherwise, regardless the status. User keyword teardowns are executed fully even if some of their keywords would fail.
#### [Execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-477)
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.robot -> My Suite
02__another_suite.robot -> 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) allow listing files nicely one file per line.
It is also possible to [randomize the execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order) using the \--randomize option.
### [3\.2.2 Test and suite statuses](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-478)
This section explains how tests can get [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pass), [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#fail) or [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) status and how the [suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-status) is determined based on test statuses.
Note
The SKIP status is new in Robot Framework 4.0.
#### [PASS](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-479)
A test gets the PASS status if it is executed and none of the keywords it contains fails.
##### Prematurely passing tests
Normally all keywords are executed, but it is also possible to use [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Pass Execution and Pass Execution If to stop execution with the PASS status and not run the remaining keywords.
How Pass Execution and Pass Execution If behave in different situations is explained below:
- When used in any [setup or teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns) (suite, test or keyword), these keywords pass that setup or teardown. Possible teardowns of the started keywords are executed. Test execution or statuses are not affected otherwise.
- When used in a test case outside setup or teardown, the keywords pass that particular test case. Possible test and keyword teardowns are executed.
- Possible [continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure) that occur before these keyword are used, as well as failures in teardowns executed afterwards, will fail the execution.
- It is mandatory to give an explanation message why execution was interrupted, and it is also possible to modify test case tags. For more details, and usage examples, see the [documentation of these keywords](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html).
Passing execution in the middle of a test, setup or teardown should be used with care. In the worst case it leads to tests that skip all the parts that could actually uncover problems in the tested application. In cases where execution cannot continue do to external factors, it is often safer to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) the test.
#### [FAIL](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-480)
The most common reason for a test to get the FAIL status is that one of the keywords it contains fails. The keyword itself can fail by [raising an exception](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) or the keyword can be called incorrectly. Other reasons for failures include syntax errors and the test being empty.
If a [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) fails, tests in that suite are marked failed without running them. If a [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) fails, tests are marked failed retroactively.
#### [SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-481)
Starting from Robot Framework 4.0, tests can get also SKIP status in addition to PASS and FAIL. There are many different ways to get this status.
##### Skipping before execution
The command line option \--skip can be used to skip specified tests without running them at all. It works based on [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) and supports [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) like `examp??` and `tagANDanother`. If it is used multiple times, all tests matching any of specified tags or tag patterns are skipped:
```
--skip require-network
--skip windowsANDversion9?
--skip python2.* --skip python3.[0-6]
```
Tests can also be skipped by tagging the test with the `robot:skip` [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags). This tag can also be set using a variable, which allows skipping test dynamically during execution.
```
*** Variables ***
${SKIP} robot:skip
*** Test Cases ***
Literal
[Documentation] Unconditionally skipped.
[Tags] robot:skip
Log This is not executed
As variable
[Documentation] Skipped unless ${SKIP} is set to a different value.
[Tags] ${SKIP}
Log This is not executed by default
```
The difference between \--skip and \--exclude is that with the latter tests are [omitted from the execution altogether](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) and they will not be shown in logs and reports. With the former they are included, but not actually executed, and they will be visible in logs and reports.
Note
`robot:skip` is new in Robot Framework 5.0.
Note
Support for using variables with tags used for skipping is new in Robot Framework 7.2.
##### Skipping dynamically during execution
Tests can get the skip status during execution in various ways:
- Using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Skip anywhere in the test case, including setup or teardown. Using Skip keyword has two effects: the test gets the SKIP status and rest of the test is not executed. However, if the test has a teardown, it will be run.
- Using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Skip If which takes a condition and skips the test if the condition is true.
- [Library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) may also trigger skip behavior by using a special exceptions. This is explained the [Skipping tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipping-tests) section in the [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) chapter.
- If [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) is skipped using any of the above means, all tests in the suite are skipped without executing them.
- If [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown) is skipped, all tests will be marked skipped retroactively.
##### Automatically skipping failed tests
The command line option \--skiponfailure can be used to automatically mark failed tests skipped. It works based on [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) and supports [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) like the \--skip option discussed above:
```
--skiponfailure not-ready
--skiponfailure experimentalANDmobile
```
Starting from RF 5.0, the reserved tag `robot:skip-on-failure` can alternatively be used to achieve the same effect as above:
```
*** Test Cases ***
Example
[Tags] robot:skip-on-failure
Fail this test will be marked as skipped instead of failed
```
The motivation for this functionality is allowing execution of tests that are not yet ready or that are testing a functionality that is not yet ready. Instead of such tests failing, they will be marked skipped and their tags can be used to separate them from possible other skipped tests.
#### [Migrating from criticality to SKIP](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-482)
Earlier Robot Framework versions supported criticality concept that allowed marking tests critical or non-critical. By default all tests were critical, but the \--critical and \--noncritical options could be used to configure that. The difference between critical and non-critical tests was that non-critical tests were not included when determining the final status for an executed test suite or for the whole test run. In practice the test status was two dimensional having PASS and FAIL in one axis and criticality on the other.
Non-critical failed tests were in many ways similar to the current skipped tests. Because these features are similar and having both SKIP and criticality would have created strange test statuses like non-critical SKIP, the criticality concept was removed in Robot Framework 4.0 when the SKIP status was introduced. The problems with criticality are explained in more detail in the [issue that proposed removing it](https://github.com/robotframework/robotframework/issues/3624).
The main use case for the criticality concept was being able to run tests that are not yet ready or that are testing a functionality that is not yet ready. This use case is nowadays covered by the skip-on-failure functionality discussed in the previous section.
To ease migrating from criticality to skipping, the old \--noncritical option worked as an alias for the new \--skiponfailure in Robot Framework 4.0 and also the old \--critical option was preserved. Both old options were deprecated and they were removed in Robot Framework 5.0.
#### [Suite status](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-483)
Suite status is determined solely based on statuses of the tests it contains:
- If any test has failed, suite status is FAIL.
- If there are no failures but at least one test has passed, suite status is PASS.
- If all tests have been skipped or the are no tests at all, suite status is SKIP.
### [3\.2.3 Continuing on failure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-484)
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 a drawback that often subsequent keywords would give more information about the state of the system, though, and in some cases those subsequent keywords would actually take care of the needed cleanup activities. Hence Robot Framework offers several features to continue even if there are failures.
#### [Execution continues on teardowns automatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-485)
To make it sure that all the cleanup activities are taken care of, the continue-on-failure mode is automatically enabled in [suite, test and keyword teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setups-and-teardowns). In practice this means that in teardowns all the keywords in all levels are always executed.
If this behavior is not desired, the special `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags can be used to [disable it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags).
#### [All top-level keywords are executed when tests have templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-486)
When using [test templates](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates), all the top-level keywords are executed to make it sure that all the different combinations are covered. In this usage continuing is limited to the top-level keywords, and inside them the execution ends normally if there are non-continuable failures.
```
*** Test Cases ***
Continue with templates
[Template] Should be Equal
this fails
this is run
```
If this behavior is not desired, the special `robot:stop-on-failure` and `robot:recursive-stop-on-failure` tags can be used to [disable it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#disabling-continue-on-failure-using-tags).
#### [Special failures from keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-487)
[Library keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) report failures using exceptions, and it is possible to use special exceptions to tell Robot Framework that execution can continue regardless the failure. How these exceptions can be created is explained in the [Continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuable-failures) section in the [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) section.
When a test ends and there have been continuable failures, 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 a continuable failure. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-488)
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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 discussed above.
```
*** Test Cases ***
Example
Run Keyword and Continue on Failure Should be Equal 1 2
Log This is executed but test fails in the end
```
#### [TRY/EXCEPT](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-491)
Robot Framework 5.0 introduced native `TRY/EXCEPT` syntax that can be used for handling failures:
```
*** Test Cases ***
Example
TRY
Some Keyword
EXCEPT Expected error message
Error Handler Keyword
END
```
For more details see the separate [TRY/EXCEPT syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#try-except-syntax) section.
#### [BuiltIn keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-492)
There are several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords that can be used to execute other keywords so that execution can continue after possible failures:
- Run Keyword And Expect Error executes a keyword and expects it to fail with the specified error message. The aforementioned `TRY/EXCEPT` syntax is nowadays generally recommended instead.
- Run Keyword And Ignore Error executes a keyword and silences possible error. It returns the status along with possible keyword return value or error message. The `TRY/EXCEPT` syntax generally works better in this case as well.
- Run Keyword And Warn On Failure is a wrapper for Run Keyword And Ignore Error that automatically logs a warning if the executed keyword fails.
- Run Keyword And Return Status executes a keyword and returns Boolean `True` or `False` depending on did it pass or fail.
### [3\.2.4 Stopping test execution gracefully](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-493)
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.
The tests that are automatically failed get `robot:exit` tag and the generated report will include `NOT robot:exit` [combined tag pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics) to easily see those tests that were not skipped. Note that the test in which the exit happened does not get the `robot:exit` tag.
Note
Prior to Robot Framework 3.1, the special tag was named `robot-exit`.
#### [Pressing `Ctrl-C`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-494)
The execution is stopped when `Ctrl-C` is pressed in the console where the tests are running. The execution is stopped immediately, but reports and logs are still generated.
If `Ctrl-C` is pressed again, the execution ends immediately and reports and logs are not created.
#### [Using signals](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-495)
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.
#### [Using keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-496)
The execution can be stopped also by the executed keywords. There is a separate Fatal Error [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword for this purpose, and custom keywords can use [fatal exceptions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution) when they fail.
#### [Stopping when first test case fails](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-497)
If option \--exitonfailure (-X) is used, the whole execution stops immediately if any test fails.
#### [Stopping using `robot:exit-on-failure` tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-498)
If a failed test has a [special](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) `robot:exit-on-failure` tag, the whole execution stops immediately after that test.
Note
This functionality is new in Robot Framework 7.2.
#### [Stopping on parsing or execution error](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-499)
Robot Framework separates *failures* caused by failing keywords from *errors* caused by, for example, invalid settings or failed test library imports. By default these errors are reported as [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but errors themselves do not fail tests or affect execution otherwise. If \--exitonerror option is used, however, all such errors are considered fatal and execution stopped so that remaining tests are marked failed. With parsing errors encountered before execution even starts, this means that no tests are actually run.
Note
Also logging something with the `ERROR` [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) is considered an error and stops the execution if the \--exitonerror option is used.
#### [Handling teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-500)
By default teardowns of the tests and suites that have been started are executed even if the test execution is stopped using one of the methods above. This allows clean-up activities to be run regardless how execution ends.
It is also possible to skip teardowns when execution is stopped by using \--skipteardownonexit option. This can be useful if, for example, clean-up tasks take a lot of time.
## [3\.3 Task execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-441)
Robot Framework can be used also for other automation purposes than test automation, and starting from Robot Framework 3.1 it is possible to explicitly [create](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) and execute tasks. For most parts task execution and test execution work the same way, and this section explains the differences.
- [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generic-automation-mode)
- [3\.3.2 Task related command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-related-command-line-options)
### [3\.3.1 Generic automation mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-501)
When Robot Framework is used execute a file and it notices that the file has tasks, not tests, it automatically sets itself into the generic automation mode. This mode does not change the actual execution at all, but when logs and reports are created, they use term *task*, not *test*. They have, for example, headers like `Task Log` and `Task Statistics` instead of `Test Log` and `Test Statistics`.
The generic automation mode can also be enabled by using the \--rpa option. In that case the executed files can have either tests or tasks. Alternatively \--norpa can be used to force the test automation mode even if executed files contain tasks. If neither of these options are used, it is an error to execute multiple files so that some have tests and others have tasks.
The execution mode is stored in the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and read by [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot) if outputs are post-processed. The mode can also [be set when using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-execution-mode) if necessary.
## [3\.4 Post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-442)
[XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) 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, and using it separately allows creating custom reports and logs as well as combining and merging results.
- [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-rebot)
- [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#synopsis-1)
- [Specifying options and arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-options-and-arguments)
- [Return codes with Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes-with-rebot)
- [Controlling execution mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-execution-mode)
- [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-reports-logs-and-output-files)
- [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs)
- [3\.4.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs)
- [Merging re-executed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-re-executed-tests)
- [Merging suites executed in pieces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-suites-executed-in-pieces)
- [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-output-files)
### [3\.4.1 Using Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-503)
#### [Synopsis](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-504)
```
rebot [options] outputs
python -m robot.rebot [options] outputs
python path/to/robot/rebot.py [options] outputs
```
The most common way to use Rebot is using the rebot command. Alternatively it is possible to execute the installed robot.rebot module or the robot/rebot.py file using the selected Python interpreter.
#### [Specifying options and arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-505)
The basic syntax for using Rebot is exactly the same as when [starting test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) and also most of the command line options are identical. The main difference is that arguments to Rebot are [XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) instead of test data files or directories.
#### [Return codes with Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-506)
Return codes from Rebot are exactly same as when [running tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes).
#### [Controlling execution mode](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-507)
Rebot notices have [tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) or [tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) been run, and by default preserves the execution mode. The mode affects logs and reports so that in the former case they will use term *test* like `Test Log` and `Test Statistics`, and in the latter case term *task* like `Task Log` and `Task Statistics`.
Rebot also supports using \--rpa or \--norpa options to set the execution mode explicitly. This is necessary if multiple output files are processed and they have conflicting modes.
### [3\.4.2 Creating reports, logs and output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-508)
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:
```
rebot output.xml
rebot path/to/output_file.xml
rebot --include smoke --name Smoke_Tests c:\results\output.xml
```
Another common usage is creating only the output file when running tests (log and report generation can be disabled with ) 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.
Rebot does not create XML output files by default, but it is possible to create them by using the \--output (-o) option. Log and report are created by default, but they can be disabled by using value `NONE` (case-insensitive) if they are not needed:
```
rebot --include smoke --output smoke.xml --log none --report none original.xml
```
### [3\.4.3 Combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-509)
An important feature in 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-test-data-to-be-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.4 Merging outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-510)
If same tests are re-executed or a single test suite executed in pieces, combining results like discussed above creates an unnecessary top-level test suite. In these cases it is typically better to merge results instead. Merging is done by using \--merge (-R) option which changes the way how Rebot combines two or more output files. This option itself takes no arguments and all other command line options can be used with it normally:
```
rebot --merge original.xml merged.xml
rebot --merge --name Example first.xml second.xml third.xml
```
When suites are merged, documentation, suite setup and suite teardown are got from the last merged suite. Suite metadata from all merged suites is preserved so that values in latter suites have precedence.
How merging tests works is explained in the following sections discussing the two main merge use cases.
Note
Getting suite documentation and metadata from merged suites is new in Robot Framework 6.0.
#### [Merging re-executed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-511)
There is often a need to re-execute a subset of tests, for example, after fixing a bug in the system under test or in the tests themselves. This can be accomplished by [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) by names (\--test and \--suite options), tags (\--include and \--exclude), or by previous status (\--rerunfailed or \--rerunfailedsuites).
Combining re-execution results with the original results using the default [combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs) approach does not work too well. The main problem is that you get separate test suites and possibly already fixed failures are also shown. In this situation it is better to use \--merge (-R) option to tell Rebot to merge the results instead. In practice this means that tests from the latter test runs replace tests in the original. An exception to this rule is that [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped) tests in latter runs are ignored and original tests preserved.
This usage is best illustrated by a practical example using \--rerunfailed and \--merge together:
```
robot --output original.xml tests # first execute all tests
robot --rerunfailed original.xml --output rerun.xml tests # then re-execute failing
rebot --merge original.xml rerun.xml # finally merge results
```
The message of the merged tests contains a note that results have been replaced. The message also shows the old status and message of the test.
Merged results must always have same top-level test suite. Tests and suites in merged outputs that are not found from the original output are added into the resulting output. How this works in practice is discussed in the next section.
Note
Ignoring skipped tests in latter runs is new in Robot Framework 4.1.
#### [Merging suites executed in pieces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-512)
Another important use case for the \--merge option is merging results got when running a test suite in pieces using, for example, \--include and \--exclude options:
```
robot --include smoke --output smoke.xml tests # first run some tests
robot --exclude smoke --output others.xml tests # then run others
rebot --merge smoke.xml others.xml # finally merge results
```
When merging outputs like this, the resulting output contains all tests and suites found from all given output files. If some test is found from multiple outputs, latest results replace the earlier ones like explained in the previous section. Also this merging strategy requires the top-level test suites to be same in all outputs.
### [3\.4.5 JSON output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-513)
Rebot can create and process output files also in the [JSON](https://json.org/) format. Creating JSON output files is done using the normal \--output option so that the specified file has a .json extension:
```
rebot --output output.json output.xml
```
When reading output files, JSON files are automatically recognized by the extension:
```
rebot output.json
rebot output1.json output2.json
```
When combining or merging results, it is possible to mix JSON and XML output files:
```
rebot output1.xml output2.json
rebot --merge original.xml rerun.json
```
The JSON output file structure is documented in the result.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
Note
Support for JSON output files is new in Robot Framework 7.0. Prior to Robot Framework 7.2 JSON output files contained only information about the executed suite, but nowadays they contain the same result data as [XML output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file).
## [3\.5 Configuring execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-443)
This section explains different command line options that can be used for configuring the [test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-test-execution) or [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). Options related to generated [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) are discussed in the next section.
- [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse)
- [Executing individual files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-individual-files)
- [Included and excluded files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files)
- [Selecting files by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-name-or-path)
- [Selecting files by extension](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-extension)
- [Using custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers)
- [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases)
- [By test names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names)
- [By suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names)
- [By tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names)
- [Re-executing failed test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-cases)
- [Re-executing failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-suites)
- [When no tests match selection](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection)
- [3\.5.3 Setting metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-metadata)
- [Setting suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name)
- [Setting suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation)
- [Setting free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata)
- [Setting test tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags)
- [3\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-where-to-search-libraries-and-other-extensions)
- [Locations automatically in module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#locations-automatically-in-module-search-path)
- [PYTHONPATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pythonpath)
- [Using `--pythonpath` option](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-pythonpath-option)
- [Configuring `sys.path` programmatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-sys-path-programmatically)
- [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-variables)
- [3\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run)
- [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order)
- [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data)
- [Example: Select every Xth test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-select-every-xth-test)
- [Example: Exclude tests by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-exclude-tests-by-name)
- [Example: Disable setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#example-disable-setups-and-teardowns)
- [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#controlling-console-output)
- [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type)
- [Console width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-width)
- [Console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors)
- [Console links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links)
- [Console markers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-markers)
- [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners)
### [3\.5.1 Selecting files to parse](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-514)
#### [Executing individual files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-515)
When executing individual files, Robot Framework tries to parse and run them regardless the name or the file extension. What parser to use depends on the extension:
- .robot files and files that are not recognized are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
- .rst and .rest files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .rbt and .json files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Files supported by [custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers) are parsed by a matching parser.
Examples:
```
robot example.robot # Standard Robot Framework parser.
robot example.tsv # Must be compatible with the standard parser.
robot example.rst # reStructuredText parser.
robot x.robot y.rst # Parse both files using an appropriate parser.
```
#### [Included and excluded files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-516)
When executing a [directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-directories), files and directories are parsed using the following rules:
- All files and directories starting with a dot (.) or an underscore (\_) are ignored.
- .robot files are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
- .robot.rst files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .rbt files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Files supported by [custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-custom-parsers) are parsed by a matching parser.
- Other files are ignored unless parsing them has been enabled by using the \--parseinclude or \--extension options discussed in the subsequent sections.
#### [Selecting files by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-517)
When executing a directory, it is possible to parse only certain files based on their name or path by using the \--parseinclude (-I) option. This option has slightly different semantics depending on the value it is used with:
- If the value is just a file name like `example.robot`, files matching the name in all directories will be parsed.
- To match only a certain file in a certain directory, files can be given as relative or absolute paths like `path/to/tests.robot`.
- If the value is a path to a directory, all files inside that directory are parsed, recursively.
Examples:
```
robot --parseinclude example.robot tests # Parse `example.robot` files anywhere under `tests`.
robot -I example_*.robot -I ???.robot tests # Parse files matching `example_*.robot` or `???.robot` under `tests`.
robot -I tests/example.robot tests # Parse only `tests/example.robot`.
robot --parseinclude tests/example tests # Parse files under `tests/example` directory, recursively.
```
Values used with \--parseinclude are case-insensitive and support [glob patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) like `example_*.robot`. There are, however, two small differences compared to how patterns typically work with Robot Framework:
- `*` matches only a single path segment. For example, `path/*/tests.robot` matches path/to/tests.robot but not path/to/nested/tests.robot.
- `**` can be used to enable recursive matching. For example, `path/**/tests.robot` matches both path/to/tests.robot and path/to/nested/tests.robot.
If the pattern contains an extension, files with that extension are parsed even if they by [default would not be](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files). What parser to use depends on the used extension:
- .rst and .rest files are parsed using the [reStructuredText parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
- .json files are parsed using the [JSON parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
- Other files are parsed using the normal [Robot Framework parser](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-file-formats).
Notice that when you use a pattern like `*.robot` and there exists a file that matches the pattern in the execution directory, the shell may resolve the pattern before Robot Framework is called and the value passed to it is the file name, not the original pattern. In such cases you need to quote or escape the pattern like `'*.robot'` or `\*.robot`.
Note
\--parseinclude is new in Robot Framework 6.1.
#### [Selecting files by extension](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-518)
In addition to using the \--parseinclude option discussed in the previous section, it is also possible to enable parsing files that are [not parsed by default](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#included-and-excluded-files) by using the \--extension (-F) option. Matching extensions is case insensitive and the leading dot can be omitted. If there is a need to parse more than one kind of files, it is possible to use a colon `:` to separate extensions:
```
robot --extension rst path/to/tests # Parse only *.rst files.
robot -F robot:rst path/to/tests # Parse *.robot and *.rst files.
```
The above is equivalent to the following \--parseinclude usage:
```
robot --parseinclude *.rst path/to/tests
robot -I *.robot -I *.rst path/to/tests
```
Because the \--parseinclude option is more powerful and covers all same use cases as the \--extension option, the latter is likely to be deprecated in the future. Users are recommended to use \--parseinclude already now.
#### [Using custom parsers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-519)
External parsers can parse files that Robot Framework does not recognize otherwise. For more information about creating and using such parsers see the [Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface) section.
### [3\.5.2 Selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-520)
Robot Framework offers several command line options for selecting which test cases to execute. The same options work also when [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks) and when post-processing outputs with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot).
#### [By test names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-521)
The easiest way to select only some tests to be run is using the \--test (-t) option. As the name implies, it can be used for selecting tests by their names. Given names are case, space and underscore insensitive and they also support [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns). The option can be used multiple times to match multiple tests:
```
--test Example # Match only tests with name 'Example'.
--test example* # Match tests starting with 'example'.
--test first --test second # Match tests with name 'first' or 'second'.
```
To pinpoint a test more precisely, it is possible to prefix the test name with a suite name:
```
--test mysuite.mytest # Match test 'mytest' in suite 'mysuite'.
--test root.sub.test # Match test 'test' in suite 'sub' in suite 'root'.
--test *.sub.test # Match test 'test' in suite 'sub' anywhere.
```
Notice that when the given name includes a suite name, it must match the whole suite name starting from the root suite. Using a wildcard as in the last example above allows matching tests with a parent suite anywhere.
Using the \--test option is convenient when only a few tests needs to be selected. A common use case is running just the test that is currently being worked on. If a bigger number of tests needs to be selected, it is typically easier to select them [by suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) or [by tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names).
When [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks), it is possible to use the \--task option as an alias for \--test.
#### [By suite names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-522)
Tests can be selected also by suite names with the \--suite (-s) option that selects all tests in matching suites. Similarly as with \--test, given names are case, space and underscore insensitive and support [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns). To pinpoint a suite more precisely, it is possible to prefix the name with the parent suite name:
```
--suite Example # Match only suites with name 'Example'.
--suite example* # Match suites starting with 'example'.
--suite first --suite second # Match suites with name 'first' or 'second'.
--suite root.child # Match suite 'child' in root suite 'root'.
--suite *.parent.child # Match suite 'child' with parent 'parent' anywhere.
```
If the name contains a parent suite name, it must match the whole suite name the same way as with \--test. Using a wildcard as in the last example above allows matching suites with a parent suite anywhere.
Note
Prior to Robot Framework 7.0, \--suite with a parent suite did not need to match the whole suite name. For example, `parent.child` would match suite `child` with parent `parent` anywhere. The name must be prefixed with a wildcard if this behavior is desired nowadays.
If both \--suite and \--test options are used, only the specified tests in specified suites are selected:
```
--suite mysuite --test mytest # Match test 'mytest' if its inside suite 'mysuite'.
```
Using the \--suite option is more or less the same as executing the appropriate suite file or directory directly. The main difference is that if a file or directory is run directly, possible higher level [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) are ignored:
```
# Root suite is 'Tests' and its possible initialization file is used.
robot --suite example path/to/tests
# Root suite is 'Example' and higher level initialization files are ignored.
robot path/to/tests/example.robot
```
Prior to Robot Framework 6.1, files not matching the \--suite option were not parsed at all for performance reasons. This optimization was not possible anymore after suites got a new Name setting that can override the default suite name that is got from the file or directory name. New \--parseinclude option has been added to [explicitly select which files are parsed](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-by-name-or-path) if this kind of parsing optimization is needed.
#### [By tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-523)
It is possible to include and exclude test cases by [tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases) names with the \--include (-i) and \--exclude (-e) options, respectively. If the \--include option is used, only test cases having a matching tag are selected, and with the \--exclude option 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. In that case a test is selected if it has a tag that matches any included tags, and also has no tag that matches any excluded tags.
In addition to specifying a tag to match fully, it is possible to use [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*` and `?` are wildcards and `AND`, `OR`, and `NOT` operators can be used for combining individual tags or patterns together:
```
--include feature-4?
--exclude bug*
--include fooANDbar
--exclude xxORyyORzz
--include fooNOTbar
```
Another way to exclude tests by tags is using the `robot:exclude` [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags). This tag can also be set using a variable, which allows excluding test dynamically during execution.
```
*** Variables ***
${EXCLUDE} robot:exclude
*** Test Cases ***
Literal
[Documentation] Unconditionally excluded.
[Tags] robot:exclude
Log This is not executed
As variable
[Documentation] Excluded unless ${EXCLUDE} is set to a different value.
[Tags] ${EXCLUDE}
Log This is not executed by default
```
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, often called smoke tests, can be tagged with `smoke` and executed with `--include smoke`.
- Unfinished test can be committed to version control with a tag such as `not_ready` and excluded from the test execution with `--exclude not_ready`.
- Tests can be tagged with `sprint-<num>`, where `<num>` specifies the number of the current sprint, and after executing all test cases, a separate report containing only the tests for a certain sprint can be generated (for example,
```
rebot
--include sprint-42 output.xml
```
).
Options \--include and \--exclude can be used in combination with \--suite and \--test discussed in the previous section. In that case tests that are selected must match all selection criteria:
```
--suite example --include tag # Match test if it is in suite 'example' and has tag 'tag'.
--suite example --exclude tag # Match test if it is in suite 'example' and does not have tag 'tag'.
--test ex* --include tag # Match test if its name starts with 'ex' and it has tag 'tag'.
--test ex* --exclude tag # Match test if its name starts with 'ex' and it does not have tag 'tag'.
```
Note
`robot:exclude` is new in Robot Framework 5.0.
Note
Using variables with `robot:exclude` is new in Robot Framework 7.2. Using variables with tags matched against \--include and \--exclude is not supported.
Note
In Robot Framework 7.0 \--include and \--test were cumulative and selected tests needed to match only either of these options. That behavior caused [backwards incompatibility problems](https://github.com/robotframework/robotframework/issues/5023) and it was reverted already in Robot Framework 7.0.1.
#### [Re-executing failed test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-524)
Command line option \--rerunfailed (-R) can be used to select all failed tests from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for re-execution. This option is useful, for example, if running all tests takes a lot of time and one wants to iteratively fix failing test cases.
```
robot tests # first execute all tests
robot --rerunfailed output.xml tests # then re-execute failing
```
Behind the scenes this option selects the failed tests as they would have been selected individually using the \--test option. It is possible to further fine-tune the list of selected tests by using \--test, \--suite, \--include and \--exclude options.
It is an error if the output contains no failed tests, but this behavior can be changed by using the \--runemptysuite option [discussed below](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). Using an output not originating from executing the same tests that are run now causes undefined results. Using a special value `NONE` as the output is same as not specifying this option at all.
Tip
Re-execution results and original results can be [merged together](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs) using the \--merge command line option.
#### [Re-executing failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-525)
Command line option \--rerunfailedsuites (-S) can be used to select all failed suites from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) for re-execution. Like \--rerunfailed (-R), this option is useful when full test execution takes a lot of time. Note that all tests from a failed test suite will be re-executed, even passing ones. This option is useful when the tests in a test suite depends on each other.
Behind the scenes this option selects the failed suites as they would have been selected individually with the \--suite option. It is possible to further fine-tune the list of selected tests by using \--test, \--suite, \--include and \--exclude options.
#### [When no tests match selection](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-526)
By default when no tests match the selection criteria test execution fails with an error like:
```
[ ERROR ] Suite 'Example' contains no tests matching tag 'xxx'.
```
Because no outputs are generated, this behavior can be problematic if tests are executed and results processed automatically. Luckily a command line option \--RunEmptySuite (case-insensitive) 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.
Similar situation can occur also when processing output files with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). It is possible that no test match the used filtering criteria or that the output file contained no tests to begin with. By default executing Rebot fails in these cases, but it has a separate \--ProcessEmptySuite option that can be used to alter the behavior. In practice this option works the same way as \--RunEmptySuite when running tests.
Note
Using \--RunEmptySuite with \--ReRunFailed or \--ReRunFailedSuites requires Robot Framework 5.0.1 or newer.
### [3\.5.4 Configuring where to search libraries and other extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-532)
When Robot Framework imports a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import), [listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners), or some other Python based extension, it uses the Python interpreter to import the module containing the extension from the system. The list of locations where modules are looked for is called *the module search path*, and its contents can be configured using different approaches explained in this section.
Robot Framework uses Python's module search path also when importing [resource and variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-and-variable-files) if the specified path does not match any file directly.
The module search path being set correctly so that libraries and other extensions are found is a requirement for successful test execution. If you need to customize it using approaches explained below, it is often a good idea to create a custom [start-up script](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-script).
#### [Locations automatically in module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-533)
Python interpreters have their own standard library as well as a directory where third party modules are installed automatically in the module search path. This means that test libraries [packaged using Python's own packaging system](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#packaging-libraries) are automatically installed so that they can be imported without any additional configuration.
#### [PYTHONPATH](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-534)
Python reads additional locations to be added to the module search path from PYTHONPATH environment variables. If you want to specify more than one location in any of them, you need to separate the locations with a colon on UNIX-like machines (e.g. `/opt/libs:$HOME/testlibs`) and with a semicolon on Windows (e.g. `D:\libs;%HOMEPATH%\testlibs`).
Environment variables can be configured permanently system wide or so that they affect only a certain user. Alternatively they can be set temporarily before running a command, something that works extremely well in custom [start-up scripts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#start-up-scripts).
#### [Using `--pythonpath` option](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-535)
Robot Framework has a separate command line option \--pythonpath (-P) for adding locations to the module search path.
Multiple locations can be given by separating them with a colon (`:`) or a semicolon (`;`) or by using this option multiple times. If the value contains both colons and semicolons, it is split from semicolons. Paths can also be [glob patterns](https://en.wikipedia.org/wiki/Glob_\(programming\)) matching multiple paths, but they typically need to be escaped when used on the console.
Examples:
```
--pythonpath libs
--pythonpath /opt/testlibs:mylibs.zip:yourlibs
--pythonpath /opt/testlibs --pythonpath mylibs.zip --pythonpath yourlibs
--pythonpath c:\temp;d:\resources
--pythonpath lib/\*.zip # '*' is escaped
```
Note
Both colon and semicolon work regardless the operating system. Using semicolon is new in Robot Framework 5.0.
#### [Configuring `sys.path` programmatically](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-536)
Python interpreters store the module search path they use as a list of strings in [sys.path](http://docs.python.org/library/sys.html#sys.path) attribute. This list can be updated dynamically during execution, and changes are taken into account next time when something is imported.
### [3\.5.5 Setting variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-537)
[Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can be set from the command line either [individually](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables) using the \--variable (-v) option or through [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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\.5.6 Dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-538)
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 \--dryrun.
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) are shown, for example, when test library or resource file imports cannot be resolved.
It is possible to disable dry run validation of specific [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords) by adding a special `robot:no-dry-run` [keyword tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) to them. This is useful if a keyword fails in the dry run mode for some reason, but work fine when executed normally.
Note
The dry run mode does not validate variables.
### [3\.5.7 Randomizing execution order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-539)
The test execution order can be randomized using option \--randomize \<what\>\[:\<seed\>\], where `<what>` is one of the following:
`tests`
Test cases inside each test suite are executed in random order.
`suites`
All test suites are executed in a random order, but test cases inside suites are run in the order they are defined.
`all`
Both test cases and test suites are executed in a random order.
`none`
Neither execution order of test nor suites is randomized. This value can be used to override the earlier value set with \--randomize.
It is possible to give a custom seed to initialize the random generator. This is useful if you want to re-run tests using the same order as earlier. The seed is given as part of the value for \--randomize in format `<what>:<seed>` and it must be an integer. If no seed is given, it is generated randomly. The executed top level test suite automatically gets [metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) named Randomized that tells both what was randomized and what seed was used.
Examples:
```
robot --randomize tests my_test.robot
robot --randomize all:12345 path/to/tests
```
### [3\.5.8 Programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-540)
If the provided built-in features to modify test data before execution are not enough, Robot Framework makes it possible to do custom modifications programmatically. This is accomplished by creating a so called *pre-run modifier* and activating it using the \--prerunmodifier option.
Pre-run modifiers should be implemented as visitors that can traverse through the executable test suite structure and modify it as needed. The visitor interface is explained as part of the [Robot Framework API documentation](http://robot-framework.readthedocs.org/en/master/autodoc/robot.model.html#module-robot.model.visitor), and it possible to modify executed [test suites](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite), [test cases](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [keywords](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.Keyword) using it. The examples below ought to give an idea of how pre-run modifiers can be used and how powerful this functionality is.
When a pre-run modifier is taken into use on the command line using the \--prerunmodifier option, it can be specified either as a name of the modifier class or a path to the modifier file. If the modifier is given as a class name, the module containing the class must be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), and if the module name is different than the class name, the given name must include both like `module.ModifierClass`. If the modifier is given as a path, the class name must be same as the file name. For most parts this works exactly like when [importing a test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import).
If a modifier requires arguments, like the examples below do, they can be specified after the modifier name or path using either a colon (`:`) or a semicolon (`;`) as a separator. If both are used in the value, the one used first is considered to be the actual separator. Starting from Robot Framework 4.0, arguments also support the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) as well as [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) based on [type hints](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) and [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) the same way as keywords do.
If more than one pre-run modifier is needed, they can be specified by using the \--prerunmodifier option multiple times. If similar modifying is needed before creating logs and reports, [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results) can be enabled using the \--prerebotmodifier option.
Pre-run modifiers are executed before other configuration affecting the executed test suite and test cases. Most importantly, options related to [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) are processed after modifiers, making it possible to use options like \--include also with possible dynamically added tests.
Another way to modify tests is using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) interface. Modifying the `data` argument passed to the `start_suite` listener method when it is called for the first time has in practice the same effect as using a pre-run modifier. The main difference is that `--include/--exclude` and other such options do not have an effect to the added tests. The main benefit of using listeners is that they allow making modifications dynamically based on what happens during the execution.
Tip
Modifiers are taken into use from the command line exactly the same way as [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface). See the [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line) section for more information and examples.
#### [Example: Select every Xth test](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-541)
The first example shows how a pre-run modifier can remove tests from the executed test suite structure. In this example only every Xth tests is preserved, and the X is given from the command line along with an optional start index.
```
"""Pre-run modifier that selects only every Xth test for execution.
Starts from the first test by default. Tests are selected per suite.
"""
from robot.api import SuiteVisitor
class SelectEveryXthTest(SuiteVisitor):
def __init__(self, x: int, start: int = 0):
self.x = x
self.start = start
def start_suite(self, suite):
"""Modify suite's tests to contain only every Xth."""
suite.tests = suite.tests[self.start::self.x]
def end_suite(self, suite):
"""Remove suites that are empty after removing tests."""
suite.suites = [s for s in suite.suites if s.test_count > 0]
def visit_test(self, test):
"""Avoid visiting tests and their keywords to save a little time."""
pass
```
If the above pre-run modifier is in a file SelectEveryXthTest.py and the file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), it could be used like this:
```
# Specify the modifier as a path. Run every second test.
robot --prerunmodifier path/to/SelectEveryXthTest.py:2 tests.robot
# Specify the modifier as a name. Run every third test, starting from the second.
robot --prerunmodifier SelectEveryXthTest:3:1 tests.robot
```
#### [Example: Exclude tests by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-542)
Also the second example removes tests, this time based on a given name pattern. In practice it works like a negative version of the built-in \--test option.
```
"""Pre-run modifier that excludes tests by their name.
Tests to exclude are specified by using a pattern that is both case and space
insensitive and supports '*' (match anything) and '?' (match single character)
as wildcards.
"""
from robot.api import SuiteVisitor
from robot.utils import Matcher
class ExcludeTests(SuiteVisitor):
def __init__(self, pattern):
self.matcher = Matcher(pattern)
def start_suite(self, suite):
"""Remove tests that match the given pattern."""
suite.tests = [t for t in suite.tests if not self._is_excluded(t)]
def _is_excluded(self, test):
return self.matcher.match(test.name) or self.matcher.match(test.longname)
def end_suite(self, suite):
"""Remove suites that are empty after removing tests."""
suite.suites = [s for s in suite.suites if s.test_count > 0]
def visit_test(self, test):
"""Avoid visiting tests and their keywords to save a little time."""
pass
```
Assuming the above modifier is in a file named ExcludeTests.py, it could be used like this:
```
# Exclude test named 'Example'.
robot --prerunmodifier path/to/ExcludeTests.py:Example tests.robot
# Exclude all tests ending with 'something'.
robot --prerunmodifier path/to/ExcludeTests.py:*something tests.robot
```
#### [Example: Disable setups and teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-543)
Sometimes when debugging tests it can be useful to disable setups or teardowns. This can be accomplished by editing the test data, but pre-run modifiers make it easy to do that temporarily for a single run:
```
"""Pre-run modifiers for disabling suite and test setups and teardowns."""
from robot.api import SuiteVisitor
class SuiteSetup(SuiteVisitor):
def start_suite(self, suite):
suite.setup = None
class SuiteTeardown(SuiteVisitor):
def start_suite(self, suite):
suite.teardown = None
class TestSetup(SuiteVisitor):
def start_test(self, test):
test.setup = None
class TestTeardown(SuiteVisitor):
def start_test(self, test):
test.teardown = None
```
Assuming that the above modifiers are all in a file named disable.py and this file is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path), setups and teardowns could be disabled, for example, as follows:
```
# Disable suite teardowns.
robot --prerunmodifier disable.SuiteTeardown tests.robot
# Disable both test setups and teardowns by using '--prerunmodifier' twice.
robot --prerunmodifier disable.TestSetup --prerunmodifier disable.TestTeardown tests.robot
```
Note
Prior to Robot Framework 4.0 `setup` and `teardown` were accessed via the intermediate `keywords` attribute and, for example, suite setup was disabled like `suite.keywords.setup = None`.
### [3\.5.9 Controlling console output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-544)
There are various command line options to control how test execution is reported on the console.
#### [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-545)
The overall console output type is set with the \--console option. It supports the following case-insensitive values:
`verbose`
Every test suite and test case is reported individually. This is the default.
`dotted`
Only show `.` for passed test, `F` for failed tests, `s` for skipped tests and `x` for tests which are skipped because [test execution exit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). Failed tests are listed separately after execution. This output type makes it easy to see are there any failures during execution even if there would be a lot of tests.
`quiet`
No output except for [errors and warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings).
`none`
No output whatsoever. Useful when creating a custom output using, for example, [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface).
Separate convenience options \--dotted (-.) and \--quiet are shortcuts for `--console dotted` and `--console quiet`, respectively.
Examples:
```
robot --console quiet tests.robot
robot --dotted tests.robot
```
#### [Console width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-546)
The width of the test execution output in the console can be set using the option \--consolewidth (-W). The default width is 78 characters.
Tip
On many UNIX-like machines you can use handy `$COLUMNS` environment variable like `--consolewidth $COLUMNS`.
#### [Console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-547)
The \--consolecolors (-C) option is used to control whether colors should be used in the console output. Colors are implemented using [ANSI escape codes](http://en.wikipedia.org/wiki/ANSI_escape_code) with a backup mechanism for older Windows versions that do not support ANSI codes.
This option supports the following case-insensitive values:
`auto`
Colors are enabled when outputs are written into the console, but not when they are redirected into a file or elsewhere. This is the default.
`on`
Colors are used also when outputs are redirected. Does not work on Windows.
`ansi`
Same as `on` but forces ANSI codes to be used unconditionally on Windows.
`off`
Colors are disabled.
Note
Using ANSI codes on Windows by default is new in Robot Framework 7.1.
#### [Console links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-548)
Result file paths written to the console at the end of the execution are, by default, hyperlinks. This behavior can be controlled with the \--consolelinks option that accepts the following case-insensitive values:
`auto`
Paths are converted to links when [console colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) are enabled. This is the default.
`off`
Links are unconditionally disabled.
The hyperlink support depends also on the console that is used, but nowadays the [support is pretty good](https://github.com/Alhadis/OSC8-Adoption). The commonly used [Windows Console](https://en.wikipedia.org/wiki/Windows_Console) does not support links, though, but the newer [Windows Terminal](https://en.wikipedia.org/wiki/Windows_Terminal) does.
Note
Hyperlink support is new in Robot Framework 7.1.
#### [Console markers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-549)
Special markers `.` (success) and `F` (failure) are shown on the console when using the [verbose output](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type) and top level keywords in test cases end. The markers allow following the test execution in high level, and they are erased when test cases end.
It is possible to configure when markers are used with \--consolemarkers (-K) option. It supports the following case-insensitive values:
`auto`
Markers are enabled when the standard output is written into the console, but not when it is redirected into a file or elsewhere. This is the default.
`on`
Markers are always used.
`off`
Markers are disabled.
### [3\.5.10 Setting listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-550)
[Listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) can be used to monitor the test execution. When they are taken into use from the command line, they are specified using the \--listener command line option. The value can either be a path to a listener or a listener name. See the [Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) section for more details about importing listeners and using them in general.
## [3\.6 Output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-444)
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\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-output-files)
- [Output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory)
- [Output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file)
- [Log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file)
- [Report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file)
- [XUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file)
- [Debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file)
- [Timestamping output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files)
- [Setting titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles)
- [Setting background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors)
- [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels)
- [Available log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-log-levels)
- [Setting log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level)
- [Visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level)
- [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs)
- [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-statistics)
- [Configuring displayed suite statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics)
- [Including and excluding tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics)
- [Generating combined tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics)
- [Creating links from tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names)
- [Adding documentation to tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags)
- [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords)
- [Removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords)
- [Flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keywords)
- [Flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keyword-during-execution-time)
- [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords)
- [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution)
- [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports)
- [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results)
- [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log)
### [3\.6.1 Different output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-551)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-552)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-553)
Output files contain all execution results in machine readable XML or JSON format. [Log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file), [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [xUnit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit) files are typically generated based on them, and they can also be combined and otherwise post-processed with [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot). Various external tools also process output files to be able to show detailed execution information.
Tip
Generating [report](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) and [xUnit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit) files as part of test execution does not require processing output files after execution. Disabling [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) generation when running tests can thus save memory.
The command line option \--output (-o) determines the path where the output file is created. The path is relative to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) and the default value is output.xml when executing tests. When [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs) with Rebot, new output files are not created unless the \--output option is explicitly used.
It is possible to disable the output file by using a special value `NONE` with the \--output option. If no outputs are needed, they should all be explicitly disabled using `--output NONE --report NONE --log NONE`.
##### XML output format
Output files are created using XML by default. The XML output format is documented in the result.xsd [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
##### JSON output format
Robot Framework supports also JSON outputs and this format is used automatically if the output file extension is .json. The JSON output format is documented in the result.json [schema file](https://github.com/robotframework/robotframework/tree/master/doc/schema#readme).
Note
JSON output files are supported during execution starting from Robot Framework 7.2. [Rebot](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rebot) can create them based on XML output files already with Robot Framework 7.0.
##### Legacy XML format
There were some [backwards incompatible changes](https://github.com/robotframework/robotframework/blob/master/doc/releasenotes/rf-7.0.rst#changes-to-output-xml) to the XML output file format in Robot Framework 7.0. To make it possible to use new Robot Framework versions with external tools that are not yet updated to support the new format, there is a \--legacyoutput option that produces output files that are compatible with Robot Framework 6.x and earlier. Robot Framework itself can process output files both in the old and in the new formats.
We hope that external tools are updated soon, but we plan to support this option at least until Robot Framework 8.0. If you encounter tools that are not compatible, please inform the tool developers about changes.
#### [Log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-554)
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.
[](https://robotframework.org/robotframework/latest/images/log_passed.html)
An example of beginning of a log file
[](https://robotframework.org/robotframework/latest/images/log_failed.html)
An example of a log file with keyword details visible
[](https://robotframework.org/robotframework/latest/images/log_skipped.html)
An example of a log file with skipped and passed tests
#### [Report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-555)
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 tests pass and bright red if any test fails. Background can also be yellow, which means that all tests were [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped).
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.
[](https://robotframework.org/robotframework/latest/images/report_passed.html)
An example report file of successful test execution
[](https://robotframework.org/robotframework/latest/images/report_failed.html)
An example report file of failed test execution
#### [XUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-556)
XUnit result files contain the test execution summary in [xUnit](http://en.wikipedia.org/wiki/XUnit) compatible XML format. These files can thus be used as an input for external tools that understand xUnit reports. For example, [Jenkins](http://jenkins-ci.org/) continuous integration server supports generating statistics based on xUnit compatible results.
XUnit output files are not created unless the command line option \--xunit (-x) is used explicitly. This option requires a path to the generated xUnit file, relatively to the [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory), as a value.
XUnit output files were changed pretty heavily in Robot Framework 5.0. They nowadays contain separate `<testsuite>` elements for each suite, `<testsuite>` elements have `timestamp` attribute, and [suite documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation) and [metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) is stored as `<property>` elements.
#### [Debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-557)
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 [fileviewer.py](https://bitbucket.org/robotframework/robottools/src/master/fileviewer/) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-558)
All output files generated by Robot Framework itself 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 output files like output-20080604-163225.xml and mylog-20080604-163225.html:
```
robot --timestampoutputs --log mylog.html --report NONE tests.robot
```
#### [Setting titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-559)
The default titles for [logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) and [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) 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.
Example:
```
robot --logtitle "Smoke Test Log" --reporttitle "Smoke Test Report" --include smoke my_tests/
```
Note
Prior to Robot Framework 3.1, underscores in the given titles were converted to spaces. Nowadays spaces need to be escaped or quoted like in the example above.
#### [Setting background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-560)
By default the [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) has red background if there are failures, green background if there are passed tests and possibly some skipped ones, and a yellow background if all tests are skipped or no tests have been run. 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 blue:red:orange
--reportbackground #00E:#E00
```
If you specify two colors, the first one will be used instead of the default green (pass) color and the second instead of the default red (fail). 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 two have same semantics as earlier and the last one replaces the default yellow (skip) color.
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, red and yellow colors are specified using hexadecimal values `#9e9`, `#f66` and `#fed84f`, respectively.
### [3\.6.2 Log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-561)
#### [Available log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-562)
Messages in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) can have different log levels. Some of the messages are written by Robot Framework itself, but also executed keywords can [log information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) using different levels. The available log levels are:
`FAIL`
Used when a keyword fails. Can be used only by Robot Framework itself.
`ERROR`
Used for displaying errors. Errors are shown in [the console and in the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but they do not affect test case statuses. If the [\--exitonerror option is enabled](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error), errors stop the whole execution, though,
`WARN`
Used for displaying warnings. Warnings are shown in [the console and in the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution), but they do not affect test case statuses.
`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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-563)
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.
It is possible to use the \--loglevel option also when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown).
#### [Visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-564)
If the log file contains messages at `DEBUG` or `TRACE` levels, a visible log level drop down is shown in the upper right corner. This allows users to remove messages below chosen level from the view. This can be useful especially when running test at `TRACE` level.
[](https://robotframework.org/robotframework/latest/images/visible_log_level.html)
An example log showing the visible log level drop down
By default the drop down will be set at the lowest level in the log file, so that all messages are shown. The default visible log level can be changed using \--loglevel option by giving the default after the normal log level separated by a colon:
```
--loglevel DEBUG:INFO
```
In the above example, tests are run using level `DEBUG`, but the default visible level in the log file is `INFO`.
### [3\.6.3 Splitting logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-565)
Normally the log file is just a single HTML file. When the amount of the test cases increases, the size of the file can grow so large that opening it into a browser is inconvenient or even impossible. Hence, 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.
The JavaScript files are saved to the same directory where the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) itself is saved. It is the common [output directory](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory) by default, but it can be changed with the \--log command line option.
Note
When copying the log files, you need to copy also all the log-\*.js files or some information will be missing.
### [3\.6.4 Configuring statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-566)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-567)
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. By 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-568)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names):
```
--tagstatinclude some-tag --tagstatinclude another-tag
--tagstatexclude owner-*
--tagstatinclude prefix-* --tagstatexclude prefix-13
```
#### [Generating combined tag statistics](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-569)
The command line option \--tagstatcombine can be used to generate aggregate tags that combine statistics from multiple tags. The combined tags are specified using [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*` and `?` are supported as wildcards and `AND`, `OR` and `NOT` operators can be used for combining individual tags or patterns together.
The following examples illustrate creating combined tag statistics using different patterns, and the figure below shows a snippet of the resulting Statistics by Tag table:
```
--tagstatcombine owner-*
--tagstatcombine smokeANDmytag
--tagstatcombine smokeNOTowner-janne*
```

Examples of combined tag statistics
As the above example illustrates, the name of the added combined statistic is, by default, just the given pattern. If this is not good enough, it is possible to give a custom name after the pattern by separating them with a colon (`:`):
```
--tagstatcombine "prio1ORprio2:High priority tests"
```
Note
Prior to Robot Framework 3.1, underscores in the custom name were converted to spaces. Nowadays spaces need to be escaped or quoted like in the example above.
#### [Creating links from tag names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-570)
You can add external links to the Statistics by Tag table by using the command line option \--tagstatlink. Arguments to this option are given in the format `tag:link:name`, where `tag` specifies the tags to assign the link to, `link` is the link to be created, and `name` is the name to give to the link.
`tag` may be a single tag, but more commonly a [simple pattern](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) where `*` matches anything and `?` matches any single character. When `tag` is a pattern, the matches to wildcards may be used in `link` and `title` with the syntax `%N`, where "N" is the index of the match starting from 1.
The following examples illustrate the usage of this option, and the figure below shows a snippet of the resulting Statistics by Tag table when example test data is executed with these options:
```
--tagstatlink mytag:http://www.google.com:Google
--tagstatlink example-bug-*:http://example.com
--tagstatlink owner-*:mailto:%1@domain.com?subject=Acceptance_Tests:Send_Mail
```

Examples of links from tag names
### [3\.6.5 Removing and flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-572)
Most of the content of [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) comes from keywords and their log messages. When creating higher level reports, log files are not necessarily needed at all, and in that case keywords and their messages just take space unnecessarily. Log files themselves can also grow overly large, especially if they contain [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) or other constructs that repeat certain keywords multiple times.
In these situations, command line options \--removekeywords and \--flattenkeywords can be used to dispose or flatten unnecessary keywords. They can be used both when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). When used during execution, they only affect the log file, not the XML output file. With `rebot` they affect both logs and possibly generated new output XML files.
#### [Removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-573)
The \--removekeywords option removes keywords and their messages altogether. It has the following modes of operation, and it can be used multiple times to enable multiple modes. Keywords that contain [errors or warnings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings) are not removed except when using the `ALL` mode.
`ALL`
Remove data from all keywords unconditionally.
`PASSED`
Remove keyword data from passed test cases. In most cases, log files created using this option contain enough information to investigate possible failures.
`FOR`
Remove all passed iterations from [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) except the last one.
`WHILE`
Remove all passed iterations from [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) except the last one.
`WUKS`
Remove all failing keywords inside [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Wait Until Keyword Succeeds except the last one.
`NAME:<pattern>`
Remove data from all keywords matching the given pattern regardless the keyword status. The pattern is matched against the full name of the keyword, prefixed with the possible library or resource file name like `MyLibrary.Keyword Name`. The pattern is case, space, and underscore insensitive, and it supports [simple patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#simple-patterns) with `*`, `?` and `[]` as wildcards.
`TAG:<pattern>`
Remove data from keywords with tags that match the given pattern. Tags are case and space insensitive and they can be specified using [tag patterns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tag-patterns) where `*`, `?` and `[]` are supported as wildcards and `AND`, `OR` and `NOT` operators can be used for combining individual tags or patterns together. Can be used both with [library keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) and [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags).
Examples:
```
rebot --removekeywords all --output removed.xml output.xml
robot --removekeywords passed --removekeywords for tests.robot
robot --removekeywords name:HugeKeyword --removekeywords name:resource.* tests.robot
robot --removekeywords tag:huge tests.robot
```
Removing keywords is done after parsing the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) and generating an internal model based on it. Thus it does not reduce memory usage as much as [flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#flattening-keywords).
#### [Flattening keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-574)
The \--flattenkeywords option flattens matching keywords. In practice this means that matching keywords get all log messages from their child keywords, recursively, and child keywords are discarded otherwise. Flattening supports the following modes:
`FOR`
Flatten [FOR loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#for-loops) fully.
`WHILE`
Flatten [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) fully.
`ITERATION`
Flatten individual `FOR` and `WHILE` loop iterations.
`FORITEM`
Deprecated alias for `ITERATION`.
`NAME:<pattern>`
Flatten keywords matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `NAME:<pattern>` mode.
`TAG:<pattern>`
Flatten keywords with tags matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `TAG:<pattern>` mode.
Examples:
```
robot --flattenkeywords name:HugeKeyword --flattenkeywords name:resource.* tests.robot
rebot --flattenkeywords foritem --output flattened.xml original.xml
```
Flattening keywords is done already when the [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is parsed initially. This can save a significant amount of memory especially with deeply nested keyword structures.
#### [Flattening keyword during execution time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-575)
Starting from Robot Framework 6.1, it is possible to enable the keyword flattening during the execution time. This can be done only on an user keyword level by defining the [reserved tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reserved-tags) `robot:flatten` as a [keyword tag](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags). Using this tag will work similarly as the command line option described in the previous chapter, e.g. all content except for log messages is removed from under the keyword having the tag. One important difference is that in this case, the removed content is not written to the output file at all, and thus cannot be accessed at later time.
```
*** Keywords ***
Example
[Tags] robot:flatten
Log Keywords and the loop are removed, but logged messages are preserved.
FOR ${i} IN RANGE 1 101
Log Iteration ${i}/100.
END
```
### [3\.6.6 Automatically expanding keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-576)
Keywords that have passed are closed in the log file by default. Thus information they contain is not visible unless you expand them. If certain keywords have important information that should be visible when the log file is opened, you can use the \--expandkeywords option to set keywords automatically expanded in log file similar to failed keywords. Expanding supports the following modes:
`NAME:<pattern>`
Expand keywords matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `NAME:<pattern>` mode.
`TAG:<pattern>`
Expand keywords with tags matching the given pattern. Pattern matching rules are same as when [removing keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-keywords) using the `TAG:<pattern>` mode.
If you need to expand keywords matching different names or patterns, you can use the \--expandkeywords multiple times.
Examples:
```
robot --expandkeywords name:SeleniumLibrary.CapturePageScreenshot tests.robot
rebot --expandkeywords tag:example --expandkeywords tag:another output.xml
```
Note
The \--expandkeywords option is new in Robot Framework 3.2.
### [3\.6.7 Setting start and end time of execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-577)
When [combining outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#combining-outputs) using Rebot, 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.
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 , where all separators are optional and the parts from milliseconds to hours can be omitted. For example, 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
```
### [3\.6.8 Limiting error message length in reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-578)
If a test case fails and has a long error message, the message shown in [reports](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is automatically cut from the middle to keep reports easier to read. By default messages longer than 40 lines are cut, but that can be configured by using the \--maxerrorlines command line option. The minimum value for this option is 10, and it is also possible to use a special value `NONE` to show the full message.
Full error messages are always visible in [log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) as messages of the failed keywords.
Note
The \--maxerrorlines option is new in Robot Framework 3.1.
### [3\.6.9 Programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-579)
If the provided built-in features to modify results are not enough, Robot Framework makes it possible to do custom modifications programmatically. This is accomplished by creating a model modifier and activating it using the \--prerebotmodifier option.
This functionality works nearly exactly like [programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data) that can be enabled with the \--prerunmodifier option. The obvious difference is that this time modifiers operate with the [result model](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#module-robot.result.model), not the [running model](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#module-robot.running.model). For example, the following modifier marks all passed tests that have taken more time than allowed as failed:
```
from robot.api import SuiteVisitor
class ExecutionTimeChecker(SuiteVisitor):
def __init__(self, max_seconds: float):
self.max_milliseconds = max_seconds * 1000
def visit_test(self, test):
if test.status == 'PASS' and test.elapsedtime > self.max_milliseconds:
test.status = 'FAIL'
test.message = 'Test execution took too long.'
```
If the above modifier would be in file ExecutionTimeChecker.py, it could be used, for example, like this:
```
# Specify modifier as a path when running tests. Maximum time is 42 seconds.
robot --prerebotmodifier path/to/ExecutionTimeChecker.py:42 tests.robot
# Specify modifier as a name when using Rebot. Maximum time is 3.14 seconds.
# ExecutionTimeChecker.py must be in the module search path.
rebot --prerebotmodifier ExecutionTimeChecker:3.14 output.xml
```
If more than one model modifier is needed, they can be specified by using the \--prerebotmodifier option multiple times. When executing tests, it is possible to use \--prerunmodifier and \--prerebotmodifier options together.
### [3\.6.10 System log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-580)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) 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
robot --name Syslog_example path/to/tests
```
## [4 Extending Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-126)
- [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries)
- [4\.2 Remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface)
- [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface)
- [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-interface)
## [4\.1 Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-581)
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-128)
#### Supported programming languages
Robot Framework itself is written with [Python](http://python.org/) and naturally test libraries extending it can be implemented using the same language. It is also possible to implement libraries with C using [Python C API](http://docs.python.org/c-api/index.html), although it is often easier to interact with C code from Python libraries using [ctypes](http://docs.python.org/library/ctypes.html) module.
Libraries implemented using Python can also act as wrappers to functionality implemented using other programming languages. A good example of this approach is the [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library), and another widely used approaches is running external scripts or tools as separate processes.
#### Different test library APIs
Robot Framework has three different test library APIs.
Static API
> The simplest approach is having a module or a class with functions/methods which map directly to [keyword names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-names). Keywords also take the same [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) as the methods implementing them. Keywords [report failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) with exceptions, [log](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) by writing to standard output and can [return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#returning-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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) and the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api) differ from it is then discussed in sections of their own.
### [4\.1.2 Creating test library class or module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-129)
Test libraries can be implemented as Python modules or classes.
#### Library name
As discussed under the [Using test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) section, libraries can be [imported by name or path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import):
```
*** Settings ***
Library MyLibrary
Library module.LibraryClass
Library path/AnotherLibrary.py
```
When a library is imported by a name, the library module must be in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) and the name can either refer to a library module or to a library class. When a name refers directly to a library class, the name must be in format like `modulename.ClassName`. Paths to libraries always refer to modules.
Even when a library import refers to a module, either by a name or by a path, a class in the module, not the module itself, is used as a library in these cases:
1. If the module contains a class that has the same name as the module. The class can be either implemented in the module or imported into it.
This makes it possible to import libraries using simple names like `MyLibrary` instead of specifying both the module and the class like `module.MyLibrary` or `MyLibrary.MyLibrary`. When importing a library by a path, it is not even possible to directly refer to a library class and automatically using a class from the imported module is the only option.
2. If the module contains exactly one class decorated with the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator). In this case the class needs to be implemented in the module, not imported to it.
This approach has all the same benefits as the earlier one, but it also allows the class name to differ from the module name.
Using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) for this purpose is new in Robot Framework 7.2.
Tip
If the library name is really long, it is often a good idea to give it a [simpler alias](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) at the import time.
#### Providing arguments to libraries
All test libraries implemented as classes can take arguments. These arguments are specified after the library name when the library is imported, 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.
The number of arguments needed by the library is the same as the number of arguments accepted by the library's `__init__` method. The default values, argument conversion, and other such features work the same way as with [keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments). 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.
```
*** Settings ***
Library MyLibrary 10.0.0.1 8080
Library AnotherLib ${ENVIRONMENT}
```
Example implementations for the libraries used in the above example:
```
from example import Connection
class MyLibrary:
def __init__(self, host, port=80):
self.connection = Connection(host, port)
def send_message(self, message):
self.connection.send(message)
```
```
class AnotherLib:
def __init__(self, environment):
self.environment = environment
def do_something(self):
if self.environment == 'test':
do_something_in_test_environment()
else:
do_something_in_other_environments()
```
If a library is imported multiple times with different arguments within a single suite, it needs to be given a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library) or otherwise latter imports are ignored:
```
*** Settings ***
Library MyLibrary 10.0.0.1 8080 AS RemoteLibrary
Library MyLibrary 127.0.0.1 AS LocalLibrary
*** Test Cases ***
Example
RemoteLibrary.Send Message Hello!
LocalLibrary.Send Message Hi!
```
#### 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`
A new instance is created for every test case. A possible suite setup and suite teardown share yet another instance.
Prior to Robot Framework 3.2 this value was `TEST CASE`, but nowadays `TEST` is recommended. Because all unrecognized values are considered same as `TEST`, both values work with all versions. For the same reason it is possible to also use value `TASK` if the library is targeted for [RPA](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#rpa) usage more than testing. `TEST` is also the default value if the `ROBOT_LIBRARY_SCOPE` attribute is not set.
`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.
Prior to Robot Framework 3.2 this value was `TEST SUITE`. That value still works, but `SUITE` is recommended with libraries targeting Robot Framework 3.2 and newer.
`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.
Note
If a library is imported multiple times with different [arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#providing-arguments-to-libraries), a new instance is created every time regardless the scope.
When the `SUITE` or `GLOBAL` scopes are used with 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 opened browsers.
Example library using the `SUITE` scope:
```
class ExampleLibrary:
ROBOT_LIBRARY_SCOPE = 'SUITE'
def __init__(self):
self._counter = 0
def count(self):
self._counter += 1
print(self._counter)
def clear_count(self):
self._counter = 0
```
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) to provide debugging information. Library documentation tool [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) also writes this information into the keyword documentations it generates.
Version information is read from attribute `ROBOT_LIBRARY_VERSION`, similarly as [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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.
An example module using `__version__`:
```
__version__ = '0.1'
def keyword():
pass
```
#### Documentation format
Library documentation tool [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) supports documentation in multiple formats. If you want to use something else than Robot Framework's own [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting), you can specify the format in the source code using `ROBOT_LIBRARY_DOC_FORMAT` attribute similarly as [scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope) and [version](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version) are set with their own `ROBOT_LIBRARY_*` attributes.
The possible case-insensitive values for documentation format are `ROBOT` (default), `HTML`, `TEXT` (plain text), and `reST` ([reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText)). Using the `reST` format requires the [docutils](https://pypi.python.org/pypi/docutils) module to be installed when documentation is generated.
Setting the documentation format is illustrated by the following example that uses reStructuredText format. See [Documenting libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-libraries) section and [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) chapter for more information about documenting test libraries in general.
```
"""A library for *documentation format* demonstration purposes.
This documentation is created using reStructuredText__. Here is a link
to the only \`Keyword\`.
__ http://docutils.sourceforge.net
"""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def keyword():
"""**Nothing** to see here. Not even in the table below.
======= ===== =====
Table here has
nothing to see.
======= ===== =====
"""
pass
```
#### Library acting as listener
[Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface) allows external listeners to get notifications about test execution. They are called, for example, when suites, tests, and keywords start and end. Sometimes getting such notifications is also useful for test libraries, and they can register a custom listener by using `ROBOT_LIBRARY_LISTENER` attribute. The value of this attribute should be an instance of the listener to use, possibly the library itself.
For more information and examples see [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners) section.
#### `@library` decorator
An easy way to configure libraries implemented as classes is using the `robot.api.deco.library` class decorator. It allows configuring library's [scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope), [version](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version), [custom argument converters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters), [documentation format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) and [listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-acting-as-listener) with optional arguments `scope`, `version`, `converter`, `doc_format` and `listener`, respectively. When these arguments are used, they set the matching `ROBOT_LIBRARY_SCOPE`, `ROBOT_LIBRARY_VERSION`, `ROBOT_LIBRARY_CONVERTERS`, `ROBOT_LIBRARY_DOC_FORMAT` and `ROBOT_LIBRARY_LISTENER` attributes automatically:
```
from robot.api.deco import library
from example import Listener
@library(scope='GLOBAL', version='3.2b1', doc_format='reST', listener=Listener())
class Example:
...
```
The `@library` decorator also disables the [automatic keyword discovery](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#what-methods-are-considered-keywords) by setting the `ROBOT_AUTO_KEYWORDS` argument to `False` by default. This means that it is mandatory to decorate methods with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) to expose them as keywords. If only that behavior is desired and no further configuration is needed, the decorator can also be used without parenthesis like:
```
from robot.api.deco import library
@library
class Example:
...
```
If needed, the automatic keyword discovery can be enabled by using the `auto_keywords` argument:
```
from robot.api.deco import library
@library(scope='GLOBAL', auto_keywords=True)
class Example:
...
```
The `@library` decorator only sets class attributes `ROBOT_LIBRARY_SCOPE`, `ROBOT_LIBRARY_VERSION`, `ROBOT_LIBRARY_CONVERTERS`, `ROBOT_LIBRARY_DOC_FORMAT` and `ROBOT_LIBRARY_LISTENER` if the respective arguments `scope`, `version`, `converters`, `doc_format` and `listener` are used. The `ROBOT_AUTO_KEYWORDS` attribute is set always and its presence can be used as an indication that the `@library` decorator has been used. When attributes are set, they override possible existing class attributes.
When a class is decorated with the `@library` decorator, it is used as a library even when a [library import refers only to a module containing it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-name). This is done regardless does the class name match the module name or not.
Note
The `@library` decorator is new in Robot Framework 3.2, the `converters` argument is new in Robot Framework 5.0, and specifying that a class in an imported module should be used as a library is new in Robot Framework 7.2.
### [4\.1.3 Creating keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-130)
#### What methods are considered keywords
When the static library API is used, Robot Framework uses introspection to find out what keywords the library class or module implements. By default it excludes methods and functions starting with an underscore. All the methods and functions that are not ignored are considered keywords. For example, the library below implements a single keyword My Keyword.
```
class MyLibrary:
def my_keyword(self, arg):
return self._helper_method(arg)
def _helper_method(self, arg):
return arg.upper()
```
#### Limiting public methods becoming keywords
Automatically considering all public methods and functions keywords typically works well, but there are cases where it is not desired. There are also situations where keywords are created when not expected. For example, when implementing a library as class, it can be a surprise that also methods in possible base classes are considered keywords. When implementing a library as a module, functions imported into the module namespace becoming keywords is probably even a bigger surprise.
This section explains how to prevent methods and functions becoming keywords.
##### Class based libraries
When a library is implemented as a class, it is possible to tell Robot Framework not to automatically expose methods as keywords by setting the `ROBOT_AUTO_KEYWORDS` attribute to the class with a false value:
```
class Example:
ROBOT_AUTO_KEYWORDS = False
```
When the `ROBOT_AUTO_KEYWORDS` attribute is set like this, only methods that have explicitly been decorated with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) or otherwise have the `robot_name` attribute become keywords. The `@keyword` decorator can also be used for setting a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name), [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) and [argument types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) to the keyword.
Although the `ROBOT_AUTO_KEYWORDS` attribute can be set to the class explicitly, it is more convenient to use the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) that sets it to `False` by default:
```
from robot.api.deco import keyword, library
@library
class Example:
@keyword
def this_is_keyword(self):
pass
@keyword('This is keyword with custom name')
def xxx(self):
pass
def this_is_not_keyword(self):
pass
```
Note
Both limiting what methods become keywords using the `ROBOT_AUTO_KEYWORDS` attribute and the `@library` decorator are new in Robot Framework 3.2.
Another way to explicitly specify what keywords a library implements is using the [dynamic](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or the [hybrid](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api) library API.
##### Module based libraries
When implementing a library as a module, all functions in the module namespace become keywords. This is true also with imported functions, and that can cause nasty surprises. For example, if the module below would be used as a library, it would contain a keyword Example Keyword, as expected, but also a keyword Current Thread.
```
from threading import current_thread
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
```
A simple way to avoid imported functions becoming keywords is to only import modules (e.g. `import threading`) and to use functions via the module (e.g `threading.current_thread()`). Alternatively functions could be given an alias starting with an underscore at the import time (e.g. `from threading import current_thread as _current_thread`).
A more explicit way to limit what functions become keywords is using the module level `__all__` attribute that [Python itself uses for similar purposes](https://docs.python.org/tutorial/modules.html#importing-from-a-package). If it is used, only the listed functions can be keywords. For example, the library below implements only one keyword Example Keyword:
```
from threading import current_thread
__all__ = ['example_keyword']
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
def this_is_not_keyword():
pass
```
If the library is big, maintaining the `__all__` attribute when keywords are added, removed or renamed can be a somewhat big task. Another way to explicitly mark what functions are keywords is using the `ROBOT_AUTO_KEYWORDS` attribute similarly as it can be used with [class based libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#class-based-libraries). When this attribute is set to a false value, only functions explicitly decorated with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator) become keywords. For example, also this library implements only one keyword Example Keyword:
```
from threading import current_thread
from robot.api.deco import keyword
ROBOT_AUTO_KEYWORDS = False
@keyword
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
def this_is_not_keyword():
pass
```
Note
Limiting what functions become keywords using `ROBOT_AUTO_KEYWORDS` is a new feature in Robot Framework 3.2.
##### Using `@not_keyword` decorator
Functions in modules and methods in classes can be explicitly marked as "not keywords" by using the `@not_keyword` decorator. When a library is implemented as a module, this decorator can also be used to avoid imported functions becoming keywords.
```
from threading import current_thread
from robot.api.deco import not_keyword
not_keyword(current_thread) # Don't expose `current_thread` as a keyword.
def example_keyword():
thread_name = current_thread().name
print(f"Running in thread '{thread_name}'.")
@not_keyword
def this_is_not_keyword():
pass
```
Using the `@not_keyword` decorator is pretty much the opposite way to avoid functions or methods becoming keywords compared to disabling the automatic keyword discovery with the `@library` decorator or by setting the `ROBOT_AUTO_KEYWORDS` to a false value. Which one to use depends on the context.
Note
The `@not_keyword` decorator is new in Robot Framework 3.2.
#### 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 library implemented as a module in the MyLibrary.py file:
```
def hello(name):
print(f"Hello, {name}!")
def do_nothing():
pass
```
The example below illustrates how the example library above can be used. If you want to try this yourself, make sure that the library is in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
```
*** Settings ***
Library MyLibrary
*** Test Cases ***
My Test
Do Nothing
Hello world
```
##### Setting custom name
It is possible to expose a different name for a keyword instead of the default keyword name which maps to the method name. This can be accomplished by setting the `robot_name` attribute on the method to the desired custom name:
```
def login(username, password):
...
login.robot_name = 'Login via user panel'
```
```
*** Test Cases ***
My Test
Login Via User Panel ${username} ${password}
```
Instead of explicitly setting the `robot_name` attribute like in the above example, it is typically easiest to use the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator):
```
from robot.api.deco import keyword
@keyword('Login via user panel')
def login(username, password):
...
```
Using this decorator without an argument will have no effect on the exposed keyword name, but will still set the `robot_name` attribute. This allows [marking methods to expose as keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#marking-methods-to-expose-as-keywords) without actually changing keyword names. Methods that have the `robot_name` attribute also create keywords even if the method name itself would start with an underscore.
Setting a custom keyword name can also enable library keywords to accept arguments using the [embedded arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names) syntax.
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) have other means for sharing this information, so this section is not relevant to them.
The most common and also the simplest situation is when a keyword needs an exact number of arguments. In this case, the method 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 keywords taking different numbers of arguments:
```
def no_arguments():
print("Keyword got no arguments.")
def one_argument(arg):
print(f"Keyword got one argument '{arg}'.")
def three_arguments(a1, a2, a3):
print(f"Keyword got three arguments '{a1}', '{a2}' and '{a3}'.")
```
#### Default values to keywords
It is often useful that some of the arguments that a keyword uses have default values.
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(f"Got argument '{arg}'.")
def multiple_defaults(arg1, arg2='default 1', arg3='default 2'):
print(f"Got arguments '{arg1}', '{arg2}' and '{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.
```
*** Test Cases ***
Defaults
One Default
One Default argument
Multiple Defaults required arg
Multiple Defaults required arg optional
Multiple Defaults required arg optional 1 optional 2
```
#### Variable number of arguments (`*varargs`)
Robot Framework supports also keywords that take any number of arguments.
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(f"Required: {required}\nOthers:")
for arg in others:
print(arg)
def also_defaults(req, def1="default 1", def2="default 2", *rest):
print(req, def1, def2, rest)
```
```
*** Test Cases ***
Varargs
Any Arguments
Any Arguments argument
Any Arguments arg 1 arg 2 arg 3 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
```
#### Free keyword arguments (`**kwargs`)
Robot Framework supports [Python's \*\*kwargs syntax](https://docs.python.org/tutorial/controlflow.html#keyword-arguments). How to use use keywords that accept *free keyword arguments*, also known as *free named arguments*, is [discussed under the Creating test cases section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments). In this section we take a look at how to create such keywords.
If you are already familiar how kwargs work with Python, understanding how they work with Robot Framework test libraries is rather simple. The example below shows the basic functionality:
```
def example_keyword(**stuff):
for name, value in stuff.items():
print(name, value)
```
```
*** Test Cases ***
Keyword Arguments
Example Keyword hello=world # Logs 'hello world'.
Example Keyword foo=1 bar=42 # Logs 'foo 1' and 'bar 42'.
```
Basically, all arguments at the end of the keyword call that use the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) `name=value`, and that do not match any other arguments, are passed to the keyword as kwargs. To avoid using a literal value like `foo=quux` as a free keyword argument, it must be [escaped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping) like `foo\=quux`.
The following example illustrates how normal arguments, varargs, and kwargs work together:
```
def various_args(arg=None, *varargs, **kwargs):
if arg is not None:
print('arg:', arg)
for value in varargs:
print('vararg:', value)
for name, value in sorted(kwargs.items()):
print('kwarg:', name, value)
```
```
*** Test Cases ***
Positional
Various Args hello world # Logs 'arg: hello' and 'vararg: world'.
Named
Various Args arg=value # Logs 'arg: value'.
Kwargs
Various Args a=1 b=2 c=3 # Logs 'kwarg: a 1', 'kwarg: b 2' and 'kwarg: c 3'.
Various Args c=3 a=1 b=2 # Same as above. Order does not matter.
Positional and kwargs
Various Args 1 2 kw=3 # Logs 'arg: 1', 'vararg: 2' and 'kwarg: kw 3'.
Named and kwargs
Various Args arg=value hello=world # Logs 'arg: value' and 'kwarg: hello world'.
Various Args hello=world arg=value # Same as above. Order does not matter.
```
For a real world example of using a signature exactly like in the above example, see Run Process and Start Keyword keywords in the [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) library.
#### Keyword-only arguments
Starting from Robot Framework 3.1, it is possible to use [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) with different keywords. This support is provided by Python's [keyword-only arguments](https://www.python.org/dev/peps/pep-3102). Keyword-only arguments are specified after possible `*varargs` or after a dedicated `*` marker when `*varargs` are not needed. Possible `**kwargs` are specified after keyword-only arguments.
Example:
```
def sort_words(*words, case_sensitive=False):
key = str.lower if case_sensitive else None
return sorted(words, key=key)
def strip_spaces(word, *, left=True, right=True):
if left:
word = word.lstrip()
if right:
word = word.rstrip()
return word
```
```
*** Test Cases ***
Example
Sort Words Foo bar baZ
Sort Words Foo bar baZ case_sensitive=True
Strip Spaces ${word} left=False
```
#### Positional-only arguments
Python supports so called [positional-only arguments](https://www.python.org/dev/peps/pep-0570/) that make it possible to specify that an argument can only be given as a [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-argument), not as a [named argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument) like `name=value`. Positional-only arguments are specified before normal arguments and a special `/` marker must be used after them:
```
def keyword(posonly, /, normal):
print(f"Got positional-only argument {posonly} and normal argument {normal}.")
```
The above keyword could be used like this:
```
*** Test Cases ***
Example
# Positional-only and normal argument used as positional arguments.
Keyword foo bar
# Normal argument can also be named.
Keyword foo normal=bar
```
If a positional-only argument is used with a value that contains an equal sign like `example=usage`, it is not considered to mean [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) even if the part before the `=` would match the argument name. This rule only applies if the positional-only argument is used in its correct position without other arguments using the name argument syntax before it, though.
```
*** Test Cases ***
Example
# Positional-only argument gets literal value `posonly=foo` in this case.
Keyword posonly=foo normal=bar
# This fails.
Keyword normal=bar posonly=foo
```
Positional-only arguments are fully supported starting from Robot Framework 4.0. Using them as positional arguments works also with earlier versions, but using them as named arguments causes an error on Python side.
#### Argument conversion
Arguments defined in Robot Framework test data are, by default, passed to keywords as Unicode strings. There are, however, several ways to use non-string values as well:
- [Variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) can contain any kind of objects as values, and variables used as arguments are passed to keywords as-is.
- Keywords can themselves [convert arguments they accept](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#manual-argument-conversion) to other types.
- It is possible to specify argument types explicitly using [function annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) or the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator). In these cases Robot Framework converts arguments automatically.
- Automatic conversion is also done based on [keyword default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values).
- Libraries can register [custom argument converters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters).
Automatic argument conversion based on function annotations, types specified using the `@keyword` decorator, and argument default values are all new features in Robot Framework 3.1. The [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section specifies which argument conversion are supported in these cases.
Prior to Robot Framework 4.0, automatic conversion was done only if the given argument was a string. Nowadays it is done regardless the argument type.
##### Manual argument conversion
If no type information is specified to Robot Framework, all arguments not passed as [variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variables) are given to keywords as Unicode strings. This includes cases like this:
```
*** Test Cases ***
Example
Example Keyword 42 False
```
It is always possible to convert arguments passed as strings insider keywords. In simple cases this means using `int()` or `float()` to convert arguments to numbers, but other kind of conversion is possible as well. When working with Boolean values, care must be taken because all non-empty strings, including string `False`, are considered true by Python. Robot Framework's own `robot.utils.is_truthy()` utility handles this nicely as it considers strings like `FALSE`, `NO` and `NONE` (case-insensitively) to be false:
```
from robot.utils import is_truthy
def example_keyword(count, case_insensitive):
count = int(count)
if is_truthy(case_insensitive):
...
```
Keywords can also use Robot Framework's argument conversion functionality via the [robot.api.TypeInfo](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.arguments.html#robot.running.arguments.typeinfo.TypeInfo) class and its `convert` method. This can be useful if the needed conversion logic is more complicated or the are needs for better error reporting than what simply using, for example, `int()` provides.
```
from robot.api import TypeInfo
def example_keyword(count, case_insensitive):
count = TypeInfo.from_type(int).convert(count)
if TypeInfo.from_type(bool).convert(case_insensitive):
...
```
Tip
It is generally recommended to specify types using type hints or otherwise and let Robot Framework handle argument conversion automatically. Manual argument conversion should only be needed in special cases.
Note
`robot.api.TypeInfo` is new in Robot Framework 7.0.
##### Specifying argument types using function annotations
Starting from Robot Framework 3.1, arguments passed to keywords are automatically converted if argument type information is available and the type is recognized. The most natural way to specify types is using Python [function annotations](https://www.python.org/dev/peps/pep-3107/). For example, the keyword in the previous example could be implemented as follows and arguments would be converted automatically:
```
def example_keyword(count: int, case_insensitive: bool = True):
if case_insensitive:
...
```
See the [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section below for a list of types that are automatically converted and what values these types accept. It is an error if an argument having one of the supported types is given a value that cannot be converted. Annotating only some of the arguments is fine.
Annotating arguments with other than the supported types is not an error, and it is also possible to use annotations for other than typing purposes. In those cases no conversion is done, but annotations are nevertheless shown in the documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc).
Keywords can also have a return type annotation specified using the `->` notation at the end of the signature like `def example() -> int:`. This information is not used for anything during execution, but starting from Robot Framework 7.0 it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
##### Specifying argument types using `@keyword` decorator
An alternative way to specify explicit argument types is using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator). Starting from Robot Framework 3.1, it accepts an optional `types` argument that can be used to specify argument types either as a dictionary mapping argument names to types or as a list mapping arguments to types based on position. These approaches are shown below implementing the same keyword as in earlier examples:
```
from robot.api.deco import keyword
@keyword(types={'count': int, 'case_insensitive': bool})
def example_keyword(count, case_insensitive=True):
if case_insensitive:
...
@keyword(types=[int, bool])
def example_keyword(count, case_insensitive=True):
if case_insensitive:
...
```
Regardless of the approach that is used, it is not necessarily to specify types for all arguments. When specifying types as a list, it is possible to use `None` to mark that a certain argument does not have type information and arguments at the end can be omitted altogether. For example, both of these keywords specify the type only for the second argument:
```
@keyword(types={'second': float})
def example1(first, second, third):
...
@keyword(types=[None, float])
def example2(first, second, third):
...
```
Starting from Robot Framework 7.0, it is possible to specify the keyword return type by using key `'return'` with an appropriate type in the type dictionary. This information is not used for anything during execution, but it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
If any types are specified using the `@keyword` decorator, type information got from [annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) is ignored with that keyword. Setting `types` to `None` like `@keyword(types=None)` disables type conversion altogether so that also type information got from [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) is ignored.
##### Implicit argument types based on default values
If type information is not got explicitly using annotations or the `@keyword` decorator, Robot Framework 3.1 and newer tries to get it based on possible argument default value. In this example `count` and `case_insensitive` get types `int` and `bool`, respectively:
```
def example_keyword(count=-1, case_insensitive=True):
if case_insensitive:
...
```
When type information is got implicitly based on the default values, argument conversion itself is not as strict as when the information is got explicitly:
- Conversion may be attempted also to other "similar" types. For example, if converting to an integer fails, float conversion is attempted.
- Conversion failures are not errors, keywords get the original value in these cases instead.
If an argument has an explicit type and a default value, conversion is first attempted based on the explicit type. If that fails, then conversion is attempted based on the default value. In this special case conversion based on the default value is strict and a conversion failure causes an error.
If argument conversion based on default values is not desired, the whole argument conversion can be disabled with the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) like `@keyword(types=None)`.
Note
Prior to Robot Framework 4.0 conversion was done based on the default value only if the argument did not have an explict type.
##### Supported conversions
The table below lists the types that Robot Framework 3.1 and newer convert arguments to. These characteristics apply to all conversions:
- Type can be explicitly specified using [function annotations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) or the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator).
- If not explicitly specified, type can be got implicitly from [argument default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values).
- Conversion is done regardless of the type of the given argument. If the argument type is incompatible with the expected type, conversion fails.
- Conversion failures cause an error if the type has been specified explicitly. If the type is got based on a default value, the given argument is used as-is.
Note
If an argument has both a type hint and a default value, conversion is first attempted based on the type hint and then, if that fails, based on the default value type. This behavior is likely to change in the future so that conversion based on the default value is done *only* if the argument does not have a type hint. That will change conversion behavior in cases like `arg: list = None` where `None` conversion will not be attempted anymore. Library creators are strongly recommended to specify the default value type explicitly like `arg: list | None = None` already now.
The type to use can be specified either using concrete types (e.g. [list](https://docs.python.org/library/stdtypes.html#list)), by using abstract base classes (ABC) (e.g. [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence)), or by using sub classes of these types (e.g. [MutableSequence](https://docs.python.org/library/collections.abc.html#collections.abc.MutableSequence)). Also types in in the [typing](https://docs.python.org/library/typing.html) module that map to the supported concrete types or ABCs (e.g. `List`) are supported. In all these cases the argument is converted to the concrete type.
In addition to using the actual types (e.g. `int`), it is possible to specify the type using type names as a string (e.g. `'int'`) and some types also have aliases (e.g. `'integer'`). Matching types to names and aliases is case-insensitive.
The Accepts column specifies which given argument types are converted. If the given argument already has the expected type, no conversion is done. Other types cause conversion failures.
| Type | ABC | Aliases | Accepts | Explanation | Examples |
|---|---|---|---|---|---|
| [bool](https://docs.python.org/library/functions.html#bool) | | boolean | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float), [None](https://docs.python.org/library/constants.html#None) | Strings `TRUE`, `YES`, `ON` and `1` are converted to `True`, the empty string as well as `FALSE`, `NO`, `OFF` and `0` are converted to `False`, and the string `NONE` is converted to `None`. Other strings and other accepted values are passed as-is, allowing keywords to handle them specially if needed. All string comparisons are case-insensitive. True and false strings can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations. | `TRUE` (converted to `True`) `off` (converted to `False`) `example` (used as-is) |
| [int](https://docs.python.org/library/functions.html#int) | [Integral](https://docs.python.org/library/numbers.html#numbers.Integral) | integer, long | [str](https://docs.python.org/library/functions.html#func-str), [float](https://docs.python.org/library/functions.html#float) | Conversion is done using the [int](https://docs.python.org/library/functions.html#int) built-in function. Floats are accepted only if they can be represented as integers exactly. For example, `1.0` is accepted and `1.1` is not. If converting a string to an integer fails and the type is got implicitly based on a default value, conversion to float is attempted as well. Starting from Robot Framework 4.1, it is possible to use hexadecimal, octal and binary numbers by prefixing values with `0x`, `0o` and `0b`, respectively. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. Starting from Robot Framework 7.0, strings representing floats are accepted as long as their decimal part is zero. This includes using the scientific notation like `1e100`. | `42` `-1` `10 000 000` `1e100` `0xFF` `0o777` `0b1010` `0xBAD_C0FFEE` `${1}` `${1.0}` |
| [float](https://docs.python.org/library/functions.html#float) | [Real](https://docs.python.org/library/numbers.html#numbers.Real) | double | [str](https://docs.python.org/library/functions.html#func-str), [Real](https://docs.python.org/library/numbers.html#numbers.Real) | Conversion is done using the [float](https://docs.python.org/library/functions.html#float) built-in. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. | `3.14` `2.9979e8` `10 000.000 01` `10_000.000_01` |
| [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | Conversion is done using the [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) class. [Decimal](https://docs.python.org/library/decimal.html#decimal.Decimal) is recommended over [float](https://docs.python.org/library/functions.html#float) when decimal numbers need to be represented exactly. Starting from Robot Framework 4.1, spaces and underscores can be used as visual separators for digit grouping purposes. | `3.14` `10 000.000 01` `10_000.000_01` |
| [str](https://docs.python.org/library/functions.html#func-str) | | string, unicode | Anything | All arguments are converted to Unicode strings. Most values are converted simply by using `str(value)`. An exception is that bytes are mapped directly to Unicode code points with same ordinals. This means that, for example, `b"hyv\xe4"` becomes `"hyvä"`. Another exception is that [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) objects are explicitly rejected. New in Robot Framework 4.0. Converting bytes specially and rejecting `Secret` objects are new in Robot Framework 7.4. | |
| [bytes](https://docs.python.org/library/functions.html#func-bytes) | | | [str](https://docs.python.org/library/functions.html#func-str), [bytearray](https://docs.python.org/library/functions.html#func-bytearray) | Strings are converted to bytes so that each Unicode code point below 256 is directly mapped to a matching byte. Higher code points are not allowed. Integers and sequences of integers are converted to matching bytes directly. They must be in range 0-255. Support for integers and sequences of integers is new in Robot Framework 7.4. | Strings: `good` `hyvä` (converted to `hyv\xe4`) `\x00` (converted to the null byte) Integers and sequences of integers: `0` (converted to the null byte) `[82, 70, 33]` (converted to `RF!`) |
| [bytearray](https://docs.python.org/library/functions.html#func-bytearray) | | | [str](https://docs.python.org/library/functions.html#func-str), [bytes](https://docs.python.org/library/functions.html#func-bytes) | Same conversion as with [bytes](https://docs.python.org/library/functions.html#func-bytes), but the result is a [bytearray](https://docs.python.org/library/functions.html#func-bytearray). | |
| [datetime](https://docs.python.org/library/datetime.html#datetime.datetime) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | String timestamps are expected to be in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) like format `YYYY-MM-DD hh:mm:ss.mmmmmm`, where any non-digit character can be used as a separator or separators can be omitted altogether. Additionally, only the date part is mandatory, all possibly missing time components are considered to be zeros. Special values `NOW` and `TODAY` (case-insensitive) can be used to get the current local `datetime`. This is new in Robot Framework 7.3. Integers and floats are considered to represent seconds since the [Unix epoch](http://en.wikipedia.org/wiki/Unix_time). | `2022-02-09T16:39:43.632269` `20220209 16:39` `2022-02-09` `now` (current local date and time) `TODAY` (same as above) `${1644417583.632269}` (Epoch time) |
| [date](https://docs.python.org/library/datetime.html#datetime.date) | | | [str](https://docs.python.org/library/functions.html#func-str) | Same timestamp conversion as with [datetime](https://docs.python.org/library/datetime.html#datetime.datetime), but all time components are expected to be omitted or to be zeros. Special values `NOW` and `TODAY` (case-insensitive) can be used to get the current local `date`. This is new in Robot Framework 7.3. | `2018-09-12` `20180912` `today` (current local date) `NOW` (same as above) |
| [timedelta](https://docs.python.org/library/datetime.html#datetime.timedelta) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int), [float](https://docs.python.org/library/functions.html#float) | Strings are expected to represent a time interval in one of the time formats Robot Framework supports: [time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number), [time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string) or [time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string). Integers and floats are considered to be seconds. | `42` (42 seconds) `1 minute 2 seconds` `01:02` (same as above) |
| [Path](https://docs.python.org/library/pathlib.html) | [PathLike](https://docs.python.org/library/os.html#os.PathLike) | | [str](https://docs.python.org/library/functions.html#func-str) | Strings are converted to [pathlib.Path](https://docs.python.org/library/pathlib.html) objects. On Windows `/` is converted to \\ automatically. New in Robot Framework 6.0. | `/tmp/absolute/path` `relative/path/to/file.ext` `name.txt` |
| [Enum](https://docs.python.org/library/enum.html#enum.Enum) | | | [str](https://docs.python.org/library/functions.html#func-str) | The specified type must be an enumeration (a subclass of [Enum](https://docs.python.org/library/enum.html#enum.Enum) or [Flag](https://docs.python.org/library/enum.html#enum.Flag)) and given arguments must match its member names. Matching member names is case, space, underscore and hyphen insensitive, but exact matches have precedence over normalized matches. Ignoring hyphens is new in Robot Framework 7.0. Enumeration documentation and members are shown in documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. | `NORTH` (Direction.NORTH) `north west` (Direction.NORTH\_WEST) |
| [IntEnum](https://docs.python.org/library/enum.html#enum.IntEnum) | | | [str](https://docs.python.org/library/functions.html#func-str), [int](https://docs.python.org/library/functions.html#int) | The specified type must be an integer based enumeration (a subclass of [IntEnum](https://docs.python.org/library/enum.html#enum.IntEnum) or [IntFlag](https://docs.python.org/library/enum.html#enum.IntFlag)) and given arguments must match its member names or values. Matching member names works the same way as with `Enum`. Values can be given as integers and as strings that can be converted to integers. Enumeration documentation and members are shown in documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. New in Robot Framework 4.1. | `OFF` (PowerState.OFF) `1` (PowerState.ON) |
| [Literal](https://docs.python.org/library/typing.html#typing.Literal) | | | Depends on usage | Only specified values are accepted. Values can be strings, integers, bytes, Booleans, enums and `None`, and used arguments are converted using the value type specific conversion logic. Strings are case, space, underscore and hyphen insensitive, but exact matches have precedence over normalized matches. `Literal` provides similar functionality as `Enum`, but does not support custom documentation. New in Robot Framework 7.0. | `OFF` `on` |
| [None](https://docs.python.org/library/constants.html#None) | | | [str](https://docs.python.org/library/functions.html#func-str) | String `NONE` (case-insensitive) and the empty string are converted to the Python `None` object. Other values cause an error. Converting the empty string is new in Robot Framework 7.4. | `None` |
| [Any](https://docs.python.org/library/typing.html#typing.Any) | | | Anything | Any value is accepted. No conversion is done. New in Robot Framework 6.1. | |
| [object](https://docs.python.org/3/library/functions.html#object) | | | Anything | Any value is accepted. No conversion is done. New in Robot Framework 7.4. | |
| [list](https://docs.python.org/library/stdtypes.html#list) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Converts strings and sequences to `list`. Strings must be Python list or tuple literals. They are converted using the [ast.literal\_eval](https://docs.python.org/library/ast.html#ast.literal_eval) function and possible tuples converted further to lists. They can contain any values `ast.literal_eval` supports, including lists and other collections. If the argument is a list, it is used without conversion. Tuples and other sequences are converted to lists. Support for tuple literals is new in Robot Framework 7.4. | `['one', 'two']` `[('one', 1), ('two', 2)]` |
| [tuple](https://docs.python.org/library/stdtypes.html#tuple) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Same as `list`, but the result is [tuple](https://docs.python.org/library/stdtypes.html#tuple). Prior to Robot Framework 7.4, only tuple literals were supported. | `('one', 'two')` |
| [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | | | [str](https://docs.python.org/library/functions.html#func-str), [Sequence](https://docs.python.org/library/collections.abc.html#collections.abc.Sequence) | Same as `list`, but any sequence is accepted without conversion. If the used type is [MutableSequence](https://docs.python.org/library/collections.abc.html#collections.abc.MutableSequence), immutable values are converted to lists. | `[1, 2, 3]` (result is `list`) `(1, 2, 3)` (result is `tuple`) |
| [set](https://docs.python.org/library/stdtypes.html#set) | [Set](https://docs.python.org/library/collections.abc.html#collections.abc.Set) | | [str](https://docs.python.org/library/functions.html#func-str), [Collection](https://docs.python.org/library/collections.abc.html#collections.abc.Collection) | Same as `list`, but also collection objects and set literals are supported and the result is [set](https://docs.python.org/library/stdtypes.html#set). Prior to Robot Framework 7.4, only set literals were supported. | `{1, 2, 3, 42}` `set()` (an empty set) |
| [frozenset](https://docs.python.org/library/stdtypes.html#frozenset) | | | [str](https://docs.python.org/library/functions.html#func-str), [Collection](https://docs.python.org/library/collections.abc.html#collections.abc.Collection) | Same as `set`, but the result is a [frozenset](https://docs.python.org/library/stdtypes.html#frozenset). | `{1, 2, 3, 42}` `frozenset()` (an empty set) |
| [dict](https://docs.python.org/library/stdtypes.html#dict) | | dictionary | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Converts strings and mappings to `dict`. Strings must be Python dictionary literals. They are converted to `dict` using the [ast.literal\_eval](https://docs.python.org/library/ast.html#ast.literal_eval) function. They can contain any values `ast.literal_eval` supports, including dictionaries and other collections. | `{'a': 1, 'b': 2}` `{'key': 1, 'nested': {'key': 2}}` |
| [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | | map | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Same as `dict`, but the original mapping type is preserved. If type is [MutableMapping](https://docs.python.org/library/collections.abc.html#collections.abc.MutableMapping), immutable values are converted to `dict`. | |
| [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict) | | | [str](https://docs.python.org/library/functions.html#func-str), [Mapping](https://docs.python.org/library/collections.abc.html#collections.abc.Mapping) | Same as `dict`, but dictionary items are also converted to the specified types and items not included in the type spec are not allowed. New in Robot Framework 6.0. Normal `dict` conversion was used earlier. | `{'width': 1600, 'enabled': True}` |
| [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) | | | [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) | Using the [Secret type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-type) as a type hint ensures that only [secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables) are accepted as arguments. New in Robot Framework 7.4. | |
Note
Starting from Robot Framework 5.0, types that have a converted are automatically shown in [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) outputs.
Note
Prior to Robot Framework 4.0, most types supported converting string `NONE` (case-insensitively) to Python `None`. That support has been removed and `None` conversion is only done if an argument has `None` as an explicit type or as a default value.
##### Specifying multiple possible types
It is possible to specify that an argument has multiple possible types. In this situation argument conversion is attempted based on each type, from left to right, and the value of the first succeeding conversion is used. If none of these conversions succeeds, the whole conversion fails.
###### Union syntax
When using function annotations, the natural syntax to specify that an argument has multiple possible types is using a [Union](https://docs.python.org/3/library/typing.html#typing.Union):
```
from typing import Union
def example(length: Union[int, float], padding: Union[int, str, None] = None):
...
```
When using Python 3.10 or newer, it is possible to use the [native union syntax](https://peps.python.org/pep-0604/) like `int | float` instead:
```
def example(length: int | float, padding: int | str | None = None):
...
```
Robot Framework 7.0 enhanced the support for the union syntax so that also "stringly typed" unions like `"int | float"` work. This syntax works also with older Python versions:
```
def example(length: "int | float", padding: "int | str | None" = None):
...
```
###### Using tuples
An alternative is specifying types as a tuple. It is not recommended with annotations, because that syntax is not supported by other tools, but it works well with the `@keyword` decorator:
```
from robot.api.deco import keyword
@keyword(types={'length': (int, float), 'padding': (int, str, None)})
def example(length, padding=None):
...
```
With the above examples the `length` argument would first be converted to an integer and if that fails then to a float. The `padding` would be first converted to an integer, then to a string, and finally to `None`.
###### When argument matches one of the types
If the given argument has one of the accepted types, then no conversion is done and the argument is used as-is. For example, if the `length` argument typed like `length: int | float` is used with a floating point number `1.5`, it is not converted to an integer. Notice that using non-string values like floats as an argument requires using variables as these examples giving different values to the `length` argument demonstrate:
```
*** Test Cases ***
Conversion
Example 10 # Argument is a string. Converted to an integer.
Example 1.5 # Argument is a string. Converted to a float.
Example ${10} # Argument is an integer. Accepted as-is.
Example ${1.5} # Argument is a float. Accepted as-is.
```
If one of the accepted types is string like in `padding: int | str | None`, then no conversion is done if the given argument is a string. As the following examples giving different values to the `padding` argument demonstrate, also in these cases passing other types is possible using variables:
```
*** Test Cases ***
Conversion
Example 1 big # Argument is a string. Accepted as-is.
Example 1 10 # Argument is a string. Accepted as-is.
Example 1 ${10} # Argument is an integer. Accepted as-is.
Example 1 ${None} # Argument is `None`. Accepted as-is.
Example 1 ${1.5} # Argument is a float. Converted to an integer.
```
If the given argument does not have any of the accepted types, conversion is attempted in the order types are specified.
Note
The order of types changes the conversion result in cases where the used value does not match any of the types, but conversion to multiple types would succeed.
For example, if typing is `float | int` and the used value is string `42`, the result will be float `42.0` instead of integer `42`. The reason is that a string does not match either of the types and `float` conversion is attempted first. If the order is changed to `int | float`, the result will be an integer.
String `3.14` would be converted to a float regardless the order, because `int` conversion does not succeed. The order does not affect usages where the value is already an integer or a float either, because there is no need for conversion in such cases.
###### Handling `Any` and `object`
If `Any` or `object` is used as a type hint on its own like `arg: Any` or `arg: object`, any value is accepted without conversion. How they work when used in an union differs, though.
If `Any` is used in a union like `arg: int | Any`, any value is accepted without conversion. This allows using `Any` as an escape hatch that disables argument conversion altogether.
On the other hand, if `object` is used in an union like `arg: int | object`, conversion is attempted to types before `object`. This allows attempting conversion to certain type or types, but getting the original value if conversions fail.
Note
Although this subtle difference in behavior may be useful, it is also somewhat confusing and the plan is to change it in Robot Framework 8.0 so that `Any` behaves like `object`. See the issue [\#5571](https://github.com/robotframework/robotframework/issues/5571) for more information and comment the issue if you do not think the planned change is a good idea.
###### Handling unrecognized types
If types that are not recognized by Robot Framework are used in an union, they are handled like this:
- If a used value matches any of the types, including unrecognized types, the value is used as-is without conversion.
- Otherwise conversion is attempted to recognized types from left to right.
- If any conversion succeeds, the converted value is returned.
- If no conversion succeeds, the original value is returned.
For example, with the following keyword string `"7"` would be converted to an integer, but string `"something"` would be used as-is:
```
def example(argument: int | Unrecognized):
...
```
Starting from Robot Framework 6.1, the above logic works also if an unrecognized type is listed before a recognized type like `Unrecognized | int`. Also in this case `int` conversion is attempted, and the argument id passed as-is if it fails. With earlier Robot Framework versions, `int` conversion would not be attempted at all.
##### Parameterized types
With generics also the parameterized syntax like `list[int]` or `dict[str, int]` works. When this syntax is used, the given value is first converted to the base type and then individual items are converted to the nested types. Conversion with different generic types works according to these rules:
- With lists there can be only one type like `list[float]`. All list items are converted to that type.
- With tuples there can be any number of types like `tuple[int, int]` and `tuple[str, int, bool]`. Tuples used as arguments are expected to have exactly that amount of items and they are converted to matching types.
- To create a homogeneous tuple, it is possible to use exactly one type and ellipsis like `tuple[int, ...]`. In this case tuple can have any number of items, including zero, and they are all converted to the specified type.
- With dictionaries there must be exactly two types like `dict[str, int]`. Dictionary keys are converted using the first type and values using the second.
- With sets there can be exactly one type like `set[float]`. Conversion logic is the same as with lists.
Using the native `list[int]` syntax requires [Python 3.9](https://peps.python.org/pep-0585/) or newer. If there is a need to support also earlier Python versions, it is possible to either use matching types from the [typing](https://docs.python.org/library/typing.html) module like `List[int]` or use the "stringly typed" syntax like `'list[int]'`.
Note
Support for converting nested types with generics is new in Robot Framework 6.0. Same syntax works also with earlier versions, but arguments are only converted to the base type and nested type information is ignored.
Note
Support for "stringly typed" parameterized generics is new in Robot Framework 7.0.
##### Secret type
Robot Framework has a custom [robot.api.types.Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) type that encapsulates values so that they are not shown in log files. If the `Secret` type is used as an argument type, only `Secret` objects are accepted and trying to use, for example, literal strings fails. The encapsulated value is available in the `value` attribute so keywords can access it easily:
```
from example import SUT
from robot.api.types import Secret
def login_to_sut(user: str, token: Secret):
SUT.login(user, token.value)
```
The [Secret variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#secret-variables) section explains how to create `Secret` objects in the data, on the command line, and elsewhere. In the data that involves using [variable type conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-type-conversion) and, for example, [environment variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables):
```
*** Variables ***
${USER} robot
${TOKEN: Secret} %{ROBOT_TOKEN}
*** Test Cases ***
Example
Login to SUT ${USER} ${TOKEN}
```
Keywords can also accept `Secret` objects in addition to strings by using the union syntax like `str | Secret`:
```
from example import SUT
from robot.api import logger
from robot.api.types import Secret
def input_password(password: str | Secret):
logger.debug(f"Typing password: {password}")
if isinstance(password, Secret):
password = password.value
SUT.input_password(password)
```
In this kind of cases it is important to not log or otherwise disclose actual secret values. The string representation of `Secret` objects is always `<secret>` and thus logging `f"Typing password: {password}"` in the above example is safe, but logging it at the end of the example would not be. The `repr()` of `Secret` objects is `Secret(value=<secret>)` so the real value is not shown in that string representation either.
Using the `Secret` type in complex type hints works similarly as with other types. The following example is similar to the example above, but uses a [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict) with a `Secret` item:
```
from typing import TypedDict
from robot.api.types import Secret
class Credential(TypedDict):
user: str
token: Secret
def login_to_sut(credentials: Credential):
SUT.login(credentials["user"], credentials["token"].value)
```
```
*** Variables ***
${TOKEN: Secret} %{ROBOT_TOKEN}
&{CREDENTIALS} user=robot token=${TOKEN}
*** Test Cases ***
Example
Login to SUT ${CREDENTIALS}
```
Warning
Secret objects do not hide or encrypt their values. The real values are thus available for all code that can access these objects directly or indirectly via Robot Framework APIs.
Warning
Actual secret values that keywords pass forward may be logged or otherwise disclosed by external modules or tools using them.
Note
The [Secret](https://robot-framework.readthedocs.io/en/master/autodoc/robot.utils.html#robot.utils.secret.Secret) type is new in Robot Framework 7.4.
##### Custom argument converters
In addition to doing argument conversion automatically as explained in the previous sections, Robot Framework supports custom argument conversion. This functionality has two main use cases:
- Overriding the standard argument converters provided by the framework.
- Adding argument conversion for custom types and for other types not supported out-of-the-box.
Argument converters are functions or other callables that get arguments used in data and convert them to desired format before arguments are passed to keywords. Converters are registered for libraries by setting `ROBOT_LIBRARY_CONVERTERS` attribute (case-sensitive) to a dictionary mapping desired types to converts. When implementing a library as a module, this attribute must be set on the module level, and with class based libraries it must be a class attribute. With libraries implemented as classes, it is also possible to use the `converters` argument with the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator). Both of these approaches are illustrated by examples in the following sections.
Note
Custom argument converters are new in Robot Framework 5.0.
###### Overriding default converters
Let's assume we wanted to create a keyword that accepts [date](https://docs.python.org/library/datetime.html#datetime.date) objects for users in Finland where the commonly used date format is `dd.mm.yyyy`. The usage could look something like this:
```
*** Test Cases ***
Example
Keyword 25.1.2022
```
[Automatic argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) supports dates, but it expects them to be in `yyyy-mm-dd` format so it will not work. A solution is creating a custom converter and registering it to handle [date](https://docs.python.org/library/datetime.html#datetime.date) conversion:
```
from datetime import date
# Converter function.
def parse_fi_date(value):
day, month, year = value.split('.')
return date(int(year), int(month), int(day))
# Register converter function for the specified type.
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
# Keyword using custom converter. Converter is resolved based on argument type.
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Conversion errors
If we try using the above keyword with invalid argument like `invalid`, it fails with this error:
```
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: not enough values to unpack (expected 3, got 1)
```
This error is not too informative and does not tell anything about the expected format. Robot Framework cannot provide more information automatically, but the converter itself can be enhanced to validate the input. If the input is invalid, the converter should raise a `ValueError` with an appropriate message. In this particular case there would be several ways to validate the input, but using [regular expressions](https://en.wikipedia.org/wiki/Regular_expression) makes it possible to validate both that the input has dots (`.`) in correct places and that date parts contain correct amount of digits:
```
from datetime import date
import re
def parse_fi_date(value):
# Validate input using regular expression and raise ValueError if not valid.
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return date(int(year), int(month), int(day))
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
With the above converter code, using the keyword with argument `invalid` fails with a lot more helpful error message:
```
ValueError: Argument 'arg' got value 'invalid' that cannot be converted to date: Expected date in format 'dd.mm.yyyy', got 'invalid'.
```
###### Restricting value types
By default Robot Framework tries to use converters with all given arguments regardless their type. This means that if the earlier example keyword would be used with a variable containing something else than a string, conversion code would fail in the `re.match` call. For example, trying to use it with argument `${42}` would fail like this:
```
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date: TypeError: expected string or bytes-like object
```
This error situation could naturally handled in the converter code by checking the value type, but if the converter only accepts certain types, it is typically easier to just restrict the value to that type. Doing it requires only adding appropriate type hint to the converter:
```
def parse_fi_date(value: str):
...
```
Notice that this type hint *is not* used for converting the value before calling the converter, it is used for strictly restricting which types can be used. With the above addition calling the keyword with `${42}` would fail like this:
```
ValueError: Argument 'arg' got value '42' (integer) that cannot be converted to date.
```
If the converter can accept multiple types, it is possible to specify types as a [Union](https://docs.python.org/3/library/typing.html#typing.Union). For example, if we wanted to enhance our keyword to accept also integers so that they would be considered seconds since the [Unix epoch](http://en.wikipedia.org/wiki/Unix_time), we could change the converter like this:
```
from datetime import date
import re
from typing import Union
# Accept both strings and integers.
def parse_fi_date(value: Union[str, int]):
# Integers are converted separately.
if isinstance(value, int):
return date.fromtimestamp(value)
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return date(int(year), int(month), int(day))
ROBOT_LIBRARY_CONVERTERS = {date: parse_fi_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Converting custom types
A problem with the earlier example is that [date](https://docs.python.org/library/datetime.html#datetime.date) objects could only be given in `dd.mm.yyyy` format. It would not work if there was a need to support dates in different formats like in this example:
```
*** Test Cases ***
Example
Finnish 25.1.2022
US 1/25/2022
ISO 8601 2022-01-22
```
A solution to this problem is creating custom types instead of overriding the default [date](https://docs.python.org/library/datetime.html#datetime.date) conversion:
```
from datetime import date
import re
from typing import Union
from robot.api.deco import keyword, library
# Custom type. Extends an existing type but that is not required.
class FiDate(date):
# Converter function implemented as a classmethod. It could be a normal
# function as well, but this way all code is in the same class.
@classmethod
def from_string(cls, value: str):
match = re.match(r'(\d{1,2})\.(\d{1,2})\.(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'dd.mm.yyyy', got '{value}'.")
day, month, year = match.groups()
return cls(int(year), int(month), int(day))
# Another custom type.
class UsDate(date):
@classmethod
def from_string(cls, value: str):
match = re.match(r'(\d{1,2})/(\d{1,2})/(\d{4})$', value)
if not match:
raise ValueError(f"Expected date in format 'mm/dd/yyyy', got '{value}'.")
month, day, year = match.groups()
return cls(int(year), int(month), int(day))
# Register converters using '@library' decorator.
@library(converters={FiDate: FiDate.from_string, UsDate: UsDate.from_string})
class Library:
# Uses custom converter supporting 'dd.mm.yyyy' format.
@keyword
def finnish(self, arg: FiDate):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Uses custom converter supporting 'mm/dd/yyyy' format.
@keyword
def us(self, arg: UsDate):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Uses IS0-8601 compatible default conversion.
@keyword
def iso_8601(self, arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
# Accepts date in different formats.
@keyword
def any(self, arg: Union[FiDate, UsDate, date]):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
###### Strict type validation
Converters are not used at all if the argument is of the specified type to begin with. It is thus easy to enable strict type validation with a custom converter that does not accept any value. For example, the Example keyword accepts only `StrictType` instances:
```
class StrictType:
pass
def strict_converter(arg):
raise TypeError(f'Only StrictType instances accepted, got {type(arg).__name__}.')
ROBOT_LIBRARY_CONVERTERS = {StrictType: strict_converter}
def example(argument: StrictType):
assert isinstance(argument, StrictType)
```
As a convenience, Robot Framework allows setting converter to `None` to get the same effect. For example, this code behaves exactly the same way as the code above:
```
class StrictType:
pass
ROBOT_LIBRARY_CONVERTERS = {StrictType: None}
def example(argument: StrictType):
assert isinstance(argument, StrictType)
```
Note
Using `None` as a strict converter is new in Robot Framework 6.0. An explicit converter function needs to be used with earlier versions.
###### Accessing the test library from converter
Starting from Robot Framework 6.1, it is possible to access the library instance from a converter function. This allows defining dynamic type conversions that depend on the library state. For example, if the library can be configured to test particular locale, you might use the library state to determine how a date should be parsed like this:
```
from datetime import date
import re
def parse_date(value, library):
# Validate input using regular expression and raise ValueError if not valid.
# Use locale based from library state to determine parsing format.
if library.locale == 'en_US':
match = re.match(r'(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<year>\d{4})$', value)
format = 'mm/dd/yyyy'
else:
match = re.match(r'(?P<day>\d{1,2})\.(?P<month>\d{1,2})\.(?P<year>\d{4})$', value)
format = 'dd.mm.yyyy'
if not match:
raise ValueError(f"Expected date in format '{format}', got '{value}'.")
return date(int(match.group('year')), int(match.group('month')), int(match.group('day')))
ROBOT_LIBRARY_CONVERTERS = {date: parse_date}
def keyword(arg: date):
print(f'year: {arg.year}, month: {arg.month}, day: {arg.day}')
```
The `library` argument to converter function is optional, i.e. if the converter function only accepts one argument, the `library` argument is omitted. Similar result can be achieved by making the converter function accept only variadic arguments, e.g. `def parse_date(*varargs)`.
###### Converter documentation
Information about converters is added to outputs produced by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) automatically. This information includes the name of the type, accepted values (if specified using type hints) and documentation. Type information is automatically linked to all keywords using these types.
Used documentation is got from the converter function by default. If it does not have any documentation, documentation is got from the type. Both of these approaches to add documentation to converters in the previous example thus produce the same result:
```
class FiDate(date):
@classmethod
def from_string(cls, value: str):
"""Date in ``dd.mm.yyyy`` format."""
...
class UsDate(date):
"""Date in ``mm/dd/yyyy`` format."""
@classmethod
def from_string(cls, value: str):
...
```
Adding documentation is in general recommended to provide users more information about conversion. It is especially important to document converter functions registered for existing types, because their own documentation is likely not very useful in this context.
#### `@keyword` decorator
Although Robot Framework gets lot of information about keywords automatically, such as their names and arguments, there are sometimes needs to configure this information further. This is typically easiest done by using the `robot.api.deco.keyword` decorator. It has several useful usages that are explained thoroughly elsewhere and only listened here as a reference:
- Exposing methods and functions as keywords when the [automatic keyword discovery](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-public-methods-becoming-keywords) has been disabled by using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator) or otherwise.
- Setting a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) to a keyword. This is especially useful when using the [embedded argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-names).
- Setting [keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags).
- Setting [type information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) to enable automatic argument type conversion. Supports also disabling the argument conversion altogether.
- [Marking methods to expose as keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#marking-methods-to-expose-as-keywords) when using the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
#### `@not_keyword` decorator
The `robot.api.deco.not_keyword` decorator can be used for [disabling functions or methods becoming keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-not-keyword-decorator).
#### Using custom decorators
When implementing keywords, it is sometimes useful to modify them with [Python decorators](https://realpython.com/primer-on-python-decorators/). However, decorators often modify function signatures and can thus confuse Robot Framework's introspection when determining which arguments keywords accept. This is especially problematic when creating library documentation with [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) and when using external tools like [RIDE](https://github.com/robotframework/RIDE). The easiest way to avoid this problem is decorating the decorator itself using [functools.wraps](https://docs.python.org/library/functools.html#functools.wraps). Other solutions include using external modules like [decorator](https://pypi.org/project/decorator/) and [wrapt](https://wrapt.readthedocs.io/) that allow creating fully signature-preserving decorators.
Note
Support for "unwrapping" decorators decorated with `functools.wraps` is a new feature in Robot Framework 3.2.
#### Embedding arguments into keyword names
Library keywords can also accept *embedded arguments* the same way as [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-user-keywords). This section mainly covers the Python syntax to use to create such keywords, the embedded arguments syntax itself is covered in detail as part of [user keyword documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#embedding-arguments-into-keyword-name).
Library keywords with embedded arguments need to have a [custom name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) that is typically set using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-decorator). Values matching embedded arguments are passed to the function or method implementing the keyword as positional arguments. If the function or method accepts more arguments, they can be passed to the keyword as normal positional or named arguments. Argument names do not need to match the embedded argument names, but that is generally a good convention.
Keywords accepting embedded arguments:
```
from robot.api.deco import keyword
@keyword('Select ${animal} from list')
def select_animal_from_list(animal):
...
@keyword('Number of ${animals} should be')
def number_of_animals_should_be(animals, count):
...
```
Tests using the above keywords:
```
*** Test Cases ***
Embedded arguments
Select cat from list
Select dog from list
Embedded and normal arguments
Number of cats should be 2
Number of dogs should be count=3
```
If type information is specified, automatic [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion) works also with embedded arguments:
```
@keyword('Add ${quantity} copies of ${item} to cart')
def add_copies_to_cart(quantity: int, item: str):
...
```
Note
Embedding type information to keyword names like `Add ${quantity: int} copies of ${item: str} to cart` similarly as with [user keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion-with-embedded-arguments) *is not supported* with library keywords.
Note
Support for mixing embedded arguments and normal arguments is new in Robot Framework 7.0.
#### Asynchronous keywords
Starting from Robot Framework 6.1, it is possible to run native asynchronous functions (created by `async def`) just like normal functions:
```
import asyncio
from robot.api.deco import keyword
@keyword
async def this_keyword_waits():
await asyncio.sleep(5)
```
You can get the reference of the loop using `asyncio.get_running_loop()` or `asyncio.get_event_loop()`. Be careful when modifying how the loop runs, it is a global resource. For example, never call `loop.close()` because it will make it impossible to run any further coroutines. If you have any function or resource that requires the event loop, even though `await` is not used explicitly, you have to define your function as async to have the event loop available.
More examples of functionality:
```
import asyncio
from robot.api.deco import keyword
async def task_async():
await asyncio.sleep(5)
@keyword
async def examples():
tasks = [task_async() for _ in range(10)]
results = await asyncio.gather(*tasks)
background_task = asyncio.create_task(task_async())
await background_task
# If running with Python 3.10 or higher
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(task_async())
task2 = tg.create_task(task_async())
```
Note
Robot Framework waits for the function to complete. If you want to have a task that runs for a long time, use, for example, `asyncio.create_task()`. It is your responsibility to manage the task and save a reference to avoid it being garbage collected. If the event loop closes and a task is still pending, a message will be printed to the console.
Note
If execution of keyword cannot continue for some reason, for example a signal stop, Robot Framework will cancel the async task and any of its children. Other async tasks will continue running normally.
### [4\.1.4 Communicating with Robot Framework](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-131)
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`.
Normal execution failures and errors can be reported using the standard exceptions such as `AssertionError`, `ValueError` and `RuntimeError`. There are, however, some special cases explained in the subsequent sections where special exceptions are needed.
##### Error messages
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 .
It is possible to avoid adding the exception type as a prefix to failure message also with non generic exceptions. This is done by adding a special `ROBOT_SUPPRESS_NAME` attribute with value `True` to your exception.
Python:
```
class MyError(RuntimeError):
ROBOT_SUPPRESS_NAME = True
```
In all cases, it is important for the users that the exception message is as informative as possible.
##### HTML in error messages
It is also possible to have HTML formatted error messages by starting the message with text `*HTML*`:
```
raise AssertionError("*HTML* <a href='robotframework.org'>Robot Framework</a> rulez!!")
```
This method can be used both when raising an exception in a library, like in the example above, and [when users provide an error message in the test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#failures).
##### Cutting long messages automatically
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.
##### Tracebacks
The traceback of the exception is also logged using `DEBUG` [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). 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`.
#### Exceptions provided by Robot Framework
Robot Framework provides some exceptions that libraries can use for reporting failures and other events. These exceptions are exposed via the [robot.api](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html) package and contain the following:
`Failure`
Report failed validation. There is no practical difference in using this exception compared to using the standard `AssertionError`. The main benefit of using this exception is that its name is consistent with other provided exceptions.
`Error`
Report error in execution. Failures related to the system not behaving as expected should typically be reported using the `Failure` exception or the standard `AssertionError`. This exception can be used, for example, if the keyword is used incorrectly. There is no practical difference, other than consistent naming with other provided exceptions, compared to using this exception and the standard `RuntimeError`.
`ContinuableFailure`
Report failed validation but allow continuing execution. See the [Continuable failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continuable-failures) section below for more information.
`SkipExecution`
Mark the executed test or task [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped). See the [Skipping tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipping-tests) section below for more information.
`FatalError`
Report error that stops the whole execution. See the [Stopping test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution) section below for more information.
Note
All these exceptions are new in Robot Framework 4.0. Other features than skipping tests, which is also new in Robot Framework 4.0, are available by other means in earlier versions.
#### Continuable failures
It is possible to [continue test execution even when there are failures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). The easiest way to do that is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.ContinuableFailure` exception:
```
from robot.api import ContinuableFailure
def example_keyword():
if something_is_wrong():
raise ContinuableFailure('Something is wrong but execution can continue.')
...
```
An alternative is creating a custom exception that has a special `ROBOT_CONTINUE_ON_FAILURE` attribute set to a `True` value. This is demonstrated by the example below.
```
class MyContinuableError(RuntimeError):
ROBOT_CONTINUE_ON_FAILURE = True
```
#### Skipping tests
It is possible to [skip](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skip) tests with a library keyword. The easiest way to do that is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.SkipExecution` exception:
```
from robot.api import SkipExecution
def example_keyword():
if test_should_be_skipped():
raise SkipExecution('Cannot proceed, skipping test.')
...
```
An alternative is creating a custom exception that has a special `ROBOT_SKIP_EXECUTION` attribute set to a `True` value. This is demonstrated by the example below.
```
class MySkippingError(RuntimeError):
ROBOT_SKIP_EXECUTION = True
```
#### Stopping test execution
It is possible to fail a test case so that [the whole test execution is stopped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). The easiest way to accomplish this is using the [provided](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#exceptions-provided-by-robot-framework) `robot.api.FatalError` exception:
```
from robot.api import FatalError
def example_keyword():
if system_is_not_running():
raise FatalError('System is not running!')
...
```
In addition to using the `robot.api.FatalError` exception, it is possible create a custom exception that has a special `ROBOT_EXIT_ON_FAILURE` attribute set to a `True` value. This is illustrated by the example below.
```
class MyFatalError(RuntimeError):
ROBOT_EXIT_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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) simply by writing to the standard output stream (stdout) or to the standard error stream (stderr), and they can even use different [log levels](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). Another, and often better, logging possibility is using the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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`. In this formant `*LEVEL*` must be in the beginning of a line and `LEVEL` must be one of the available concrete log levels `TRACE`, `DEBUG`, `INFO`, `WARN` or `ERROR`, or a pseudo log level `HTML` or `CONSOLE`. The pseudo levels can be used for [logging HTML](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-html) and [logging to console](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-to-console), respectively.
##### Errors and warnings
Messages with `ERROR` or `WARN` level are automatically written to the console and a separate [Test Execution Errors section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) in the log files. This makes these messages more visible than others 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, for example, one badly placed `</table>` tag can ruin the log file quite badly.
When using the [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api), various logging methods have optional `html` attribute that can be set to `True` to enable logging in HTML format.
##### 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.
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](http://en.wikipedia.org/wiki/Unix_time) and it must be placed after the [log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-log-levels) 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. It is, however, even easier to get accurate timestamps using the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis). A big benefit of adding timestamps explicitly is that this approach works also with the [remote library interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library-interface).
```
import time
def example_keyword():
timestamp = int(time.time() * 1000)
print(f'*INFO:{timestamp}* Message with timestamp')
```
##### Logging to console
Libraries have several options for writing messages to the console. As already discussed, warnings and 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.
Starting from Robot Framework 6.1, libraries can use a pseudo log level `CONSOLE` for logging messages *both* to the log file and to the console:
```
def my_keyword(arg):
print('*CONSOLE* Message both to log and to console.')
```
These messages will be logged to the log file using the `INFO` level similarly as with the `HTML` pseudo log level. When using this approach, messages are logged to the console only after the keyword execution ends.
Another option is writing messages to `sys.__stdout__` or `sys.__stderr__`. When using this approach, messages are written to the console immediately and are not written to the log file at all:
```
import sys
def my_keyword(arg):
print('Message only to console.', file=sys.__stdout__)
```
The final option is using the [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api). Also in with this approach messages are written to the console immediately:
```
from robot.api import logger
def log_to_console(arg):
logger.console('Message only to console.')
def log_to_console_and_log_file(arg):
logger.info('Message both to log and to console.', also_console=True)
```
##### 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` or `ERROR` level can be used to make messages more visible and `HTML` is useful if any kind of formatting is needed. Level `CONSOLE` can be used when the message needs to shown both in console and in the log file.
The following examples clarify how logging with different levels works.
```
print('Hello from a library.')
print('*WARN* Warning from a library.')
print('*ERROR* Something unexpected happen that may indicate a problem in the test.')
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('*CONSOLE* This logs into console and log file.')
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 | ERROR | Something unexpected happen that may indicate a problem in the test. |
| 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 logs into console and log file. |
| 16:18:42.123 | INFO | This is **bold**. |
| 16:18:42.123 | INFO | [Robot Framework](http://robotframework.org/) |
#### Programmatic logging APIs
Programmatic APIs provide somewhat cleaner way to log information than using the standard output and error streams.
##### Public logging API
Robot Framework has a 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamps).
The public logging API [is thoroughly documented](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#module-robot.api.logger) as part of the API documentation at [https://robot-framework.readthedocs.org](https://robot-framework.readthedocs.org/). Below is a simple usage example:
```
from robot.api import logger
def my_keyword(arg):
logger.debug(f"Got argument '{arg}'.")
do_something()
logger.info('<i>This</i> is a boring example', html=True)
logger.console('Hello, console!')
```
An obvious limitation is that test libraries using this logging API have a dependency to Robot Framework. If Robot Framework is not running, the messages are redirected automatically to Python's standard [logging](http://docs.python.org/library/logging.html) module.
##### Using Python's standard `logging` module
In addition to the new [public logging API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#public-logging-api), Robot Framework offers a built-in support to Python's standard [logging](http://docs.python.org/library/logging.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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(f"Got argument '{arg}'.")
do_something()
logging.info('This is a boring example')
```
The `logging` module has slightly different log levels than Robot Framework. Its levels `DEBUG`, `INFO`, `WARNING` and `ERROR` are mapped directly to the matching Robot Framework log levels, and `CRITICAL` is mapped to `ERROR`. Custom log levels are mapped to the closest standard level smaller than the custom level. For example, a level between `INFO` and `WARNING` is mapped to Robot Framework's `INFO` level.
#### Logging during library initialization
Libraries can also log during the test library import and initialization. These messages do not appear in the [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) like the normal log messages, but are instead written to the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log). This allows logging any kind of useful debug information about the library initialization. Messages logged using the `WARN` or `ERROR` levels are also visible in the [test execution errors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution) section in the log file.
Logging during the import and initialization is possible both using the [standard output and error streams](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) and the [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis). Both of these are demonstrated below.
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__`, the messages may be logged multiple times depending on the [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope).
#### 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-values-from-keywords) in the test data and then used as inputs for other keywords, even from different test libraries.
Values are returned using the `return` statement in methods. Normally, one value is assigned into one [scalar variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables), as illustrated in the example below. This example also illustrates that it is possible to return any objects and to use [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) to access object attributes.
```
from mymodule import MyObject
def return_string():
return "Hello, world!"
def return_object(name):
return MyObject(name)
```
```
*** Test Cases ***
Returning one value
${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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#scalar-variables) at once, into [a list variable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#list-variables), or into scalar variables and a list variable. All these usages require that returned values are lists or list-like objects.
```
def return_two_values():
return 'first value', 'second value'
def return_multiple_values():
return ['a', 'list', 'of', 'strings']
```
```
*** Test Cases ***
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 ${s1} ${s2} a list
Should Be Equal @{li}[0] @{li}[1] of strings
```
#### Detecting is Robot Framework running
Starting from Robot Framework 6.1, it is easy to detect is Robot Framework running at all and is the dry-run mode active by using the `robot_running` and `dry_run_active` properties of the BuiltIn library. A relatively common use case is that library initializers may want to avoid doing some work if the library is not used during execution but is initialized, for example, by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc):
```
from robot.libraries.BuiltIn import BuiltIn
class MyLibrary:
def __init__(self):
builtin = BuiltIn()
if builtin.robot_running and not builtin.dry_run_active:
# Do some initialization that only makes sense during real execution.
```
For more information about using the BuiltIn library as a programmatic API, including another example using `robot_running`, see the [Using BuiltIn library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-builtin-library) section.
#### 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 the worst 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.
Messages logged by non-main threads using the normal logging methods from [programmatic logging APIs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-logging-apis) are silently ignored.
There is also a `BackgroundLogger` in separate [robotbackgroundlogger](https://github.com/robotframework/robotbackgroundlogger) project, with a similar API as the standard `robot.api.logger`. Normal logging methods will ignore messages from other than main thread, but the `BackgroundLogger` will save the background messages so that they can be later logged to Robot's log.
### [4\.1.5 Distributing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-132)
#### 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](http://www.python.org/dev/peps/pep-0257) as in the example 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
```
Python has 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). This tool can create a library documentation from libraries using the static library API, such as the ones above, but it also handles libraries using the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) and [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
The first logical line of a keyword documentation, until the first empty line, is used for a special purpose and should contain a short overall description of the keyword. It is used as a *short documentation* by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) (for example, as a tool tip) and also shown in the [test logs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file).
By default documentation is considered to follow Robot Framework's [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) rules. This simple format allows often used styles like `*bold*` and `_italic_`, tables, lists, links, etc. It is possible to use also HTML, plain text and [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) formats. See the [Documentation format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) section for information how to set the format in the library source code and [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) chapter for more information about the formats in general.
Note
Prior to Robot Framework 3.1, the short documentation contained only the first physical line of the keyword documentation.
#### 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.
Python has 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](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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 [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-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. For information about packaging and distributing Python code see <https://packaging.python.org/>. When such a package is installed using [pip](https://pip.pypa.io/) or other tools, it is automatically in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path).
#### 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 can be deprecated by starting their documentation with text `*DEPRECATED`, case-sensitive, and having a closing `*` also on the first line of the documentation. For example, `*DEPRECATED*`, `*DEPRECATED.*`, and `*DEPRECATED in version 1.5.*` are all valid markers.
When a deprecated keyword is executed, a deprecation warning is logged and the warning is shown also in [the console and the Test Execution Errors section in log files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#errors-and-warnings-during-execution). The deprecation warning starts with text and has rest of the [short documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-libraries) after the deprecation marker, if any, afterwards. For example, if the 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 results.
"""
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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-name-and-documentation).
### [4\.1.6 Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-133)
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. In other words, users do not need to know what APIs their libraries use.
Only differences between static and dynamic libraries are how Robot Framework discovers what keywords a library implements, what arguments and documentation these keywords have, and how the keywords are actually executed. With the static API, all this is done using reflection, 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 must have all keywords in one class or module, whereas with the dynamic API, you can, for example, implement each keyword as a separate class. This use case is not so important with Python, though, because its dynamic capabilities and multi-inheritance already give plenty of flexibility, and there is also possibility to use the [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hybrid-library-api).
Another major use case for the dynamic API is implementing a library so that it works as proxy for an actual library possibly running on some other process or even on another machine. This kind of a proxy library can be very thin, and because keyword names and all other information is got dynamically, there is no need to update the proxy when new keywords are added to 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. Python users may also find the [PythonLibCore](https://github.com/robotframework/PythonLibCore) project useful.
#### Getting keyword names
Dynamic libraries tell what keywords they implement with the `get_keyword_names` method. This method cannot take any arguments, and it must return a list or array of strings 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 be mapped to 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.
##### Marking methods to expose as keywords
If a dynamic library should contain both methods which are meant to be keywords and methods which are meant to be private helper methods, it may be wise to mark the keyword methods as such so it is easier to implement `get_keyword_names`. The `robot.api.deco.keyword` decorator allows an easy way to do this since it creates a [custom 'robot\_name' attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name) on the decorated method. This allows generating the list of keywords just by checking for the `robot_name` attribute on every method in the library during `get_keyword_names`.
```
from robot.api.deco import keyword
class DynamicExample:
def get_keyword_names(self):
# Get all attributes and their values from the library.
attributes = [(name, getattr(self, name)) for name in dir(self)]
# Filter out attributes that do not have 'robot_name' set.
keywords = [(name, value) for name, value in attributes
if hasattr(value, 'robot_name')]
# Return value of 'robot_name', if given, or the original 'name'.
return [value.robot_name or name for name, value in keywords]
def helper_method(self):
...
@keyword
def keyword_method(self):
...
```
#### 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 `run_keyword` method to get it executed. This method takes two or three 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 [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments) given to the keyword in the test data, and the optional third argument is a dictionary containing [named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-arguments). If the third argument is missing, [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries) and [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-dynamic-libraries) are not supported, and other named arguments are mapped to positional arguments.
Note
Prior to Robot Framework 3.1, normal named arguments were mapped to positional arguments regardless did `run_keyword` accept two or three arguments. The third argument only got possible free named arguments.
After getting keyword name and arguments, the library 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 or by using the provided logging APIs, 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 but rest of the methods in the dynamic API are optional. 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, named_args):
print(f"Running keyword '{name}' with positional arguments {args} "
f"and named arguments {named_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 accept. For example, both First Keyword and Second Keyword in the example above could be used with any 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 communicate what arguments their keywords expect by using the `get_keyword_arguments` (alias `getKeywordArguments`) method. This method gets the name of a keyword as an argument, and it must return a list of strings containing the arguments accepted by that keyword.
Similarly as other keywords, dynamic keywords can require any number of [positional arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-arguments), have [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values), accept [variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments), accept [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) and have [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments). The syntax how to represent all these different variables is derived from how they are specified in Python and explained in the following table.
| Argument type | How to represent | Examples |
|---|---|---|
| No arguments | Empty list. | `[]` |
| One or more [positional argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-argument) | List of strings containing argument names. | `['argument']` `['arg1', 'arg2', 'arg3']` |
| [Default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#default-values) | Two ways how to represent the argument name and the default value: As a string where the name and the default are separated with `=`. As a tuple with the name and the default as separate items. New in Robot Framework 3.2. | String with `=` separator: `['name=default']` `['a', 'b=1', 'c=2']` Tuple: `[('name', 'default')]` `['a', ('b', 1), ('c', 2)]` |
| [Positional-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments) | Arguments before the `/` marker. New in Robot Framework 6.1. | `['posonly', '/']` `['p', 'q', '/', 'normal']` |
| [Variable number of arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-number-of-arguments) (varargs) | Argument after possible positional arguments has a `*` prefix | `['*varargs']` `['argument', '*rest']` `['a', 'b=42', '*c']` |
| [Named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments) | Arguments after varargs or a lone `*` if there are no varargs. With or without defaults. Requires `run_keyword` to [support named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries). New in Robot Framework 3.1. | `['*varargs', 'named']` `['*', 'named']` `['*', 'x', 'y=default']` `['a', '*b', ('c', 42)]` |
| [Free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) (kwargs) | Last arguments has `**` prefix. Requires `run_keyword` to [support free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments-with-dynamic-libraries). | `['**named']` `['a', ('b', 42), '**c']` `['*varargs', '**kwargs']` `['*', 'kwo', '**kws']` |
When the `get_keyword_arguments` is used, Robot Framework automatically calculates how many positional arguments the keyword requires and does it support free named arguments or not. If a keyword is used with invalid arguments, an error occurs and `run_keyword` is not even called.
The actual argument names and default values that are returned are also important. They are needed for [named argument support](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax-with-dynamic-libraries) and the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool needs them to be able to create a meaningful library documentation.
As explained in the above table, default values can be specified with argument names either as a string like `'name=default'` or as a tuple like `('name', 'default')`. The main problem with the former syntax is that all default values are considered strings whereas the latter syntax allows using all objects like `('integer', 1)` or `('boolean', True)`. When using other objects than strings, Robot Framework can do [automatic argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values) based on them.
For consistency reasons, also arguments that do not accept default values can be specified as one item tuples. For example, `['a', 'b=c', '*d']` and `[('a',), ('b', 'c'), ('*d',)]` are equivalent.
If `get_keyword_arguments` is missing or returns Python `None` for a certain keyword, that keyword gets an argument specification accepting all arguments. This automatic argument spec is either `[*varargs, **kwargs]` or `[*varargs]`, depending does `run_keyword` [support free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries) or not.
Note
Support to specify arguments as tuples like `('name', 'default')` is new in Robot Framework 3.2. Support for positional-only arguments in dynamic library API is new in Robot Framework 6.1.
#### Getting keyword argument types
Robot Framework 3.1 introduced support for automatic argument conversion and the dynamic library API supports that as well. The conversion logic works exactly like with [static libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion), but how the type information is specified is naturally different.
With dynamic libraries types can be returned using the optional `get_keyword_types` method (alias `getKeywordTypes`). It can return types using a list or a dictionary exactly like types can be specified when using the [@keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator). Type information can be specified using actual types like `int`, but especially if a dynamic library gets this information from external systems, using strings like `'int'` or `'integer'` may be easier. See the [Supported conversions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) section for more information about supported types and how to specify them.
Robot Framework does automatic argument conversion also based on the [argument default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). Earlier this did not work with the dynamic API because it was possible to specify arguments only as strings. As [discussed in the previous section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments), this was changed in Robot Framework 3.2 and nowadays default values returned like `('example', True)` are automatically used for this purpose.
Starting from Robot Framework 7.0, dynamic libraries can also specify the keyword return type by using key `'return'` with an appropriate type in the returned type dictionary. This information is not used for anything during execution, but it is shown by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) for documentation purposes.
#### Getting keyword documentation
If dynamic libraries want to provide keyword documentation, they can implement the `get_keyword_documentation` method (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. The main use case is getting keywords' documentations into a library documentation generated by [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) in practice.
Dynamic libraries can also specify the general library documentation directly in the code as the docstring of the library class and its `__init__` method. If a non-empty documentation is got both directly from the code and from the `get_keyword_documentation` method, the latter has precedence.
#### Getting keyword source information
The dynamic API masks the real implementation of keywords from Robot Framework and thus makes it impossible to see where keywords are implemented. This means that editors and other tools utilizing Robot Framework APIs cannot implement features such as go-to-definition. This problem can be solved by implementing yet another optional dynamic method named `get_keyword_source` (alias `getKeywordSource`) that returns the source information.
The return value from the `get_keyword_source` method must be a string or `None` if no source information is available. In the simple case it is enough to simply return an absolute path to the file implementing the keyword. If the line number where the keyword implementation starts is known, it can be embedded to the return value like `path:lineno`. Returning only the line number is possible like `:lineno`.
The source information of the library itself is got automatically from the imported library class the same way as with other library APIs. The library source path is used with all keywords that do not have their own source path defined.
Note
Returning source information for keywords is a new feature in Robot Framework 3.2.
#### Named argument syntax with dynamic libraries
Also the dynamic library API supports the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax). Using the syntax works based on the argument names and default values [got from the library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) using the `get_keyword_arguments` method.
If the `run_keyword` method accepts three arguments, the second argument gets all positional arguments as a list and the last arguments gets all named arguments as a mapping. If it accepts only two arguments, named arguments are mapped to positional arguments. In the latter case, if a keyword has multiple arguments with default values and only some of the latter ones are given, the framework fills the skipped optional arguments based on the default values returned by the `get_keyword_arguments` method.
Using the named argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has an argument specification `[a, b=d1, c=d2]`. The comment on each row shows how `run_keyword` would be called in these cases if it has two arguments (i.e. signature is `name, args`) and if it has three arguments (i.e. `name, args, kwargs`).
```
*** Test Cases *** # args # args, kwargs
Positional only
Dynamic x # [x] # [x], {}
Dynamic x y # [x, y] # [x, y], {}
Dynamic x y z # [x, y, z] # [x, y, z], {}
Named only
Dynamic a=x # [x] # [], {a: x}
Dynamic c=z a=x b=y # [x, y, z] # [], {a: x, b: y, c: z}
Positional and named
Dynamic x b=y # [x, y] # [x], {b: y}
Dynamic x y c=z # [x, y, z] # [x, y], {c: z}
Dynamic x b=y c=z # [x, y, z] # [x], {y: b, c: z}
Intermediate missing
Dynamic x c=z # [x, d1, z] # [x], {c: z}
```
Note
Prior to Robot Framework 3.1, all normal named arguments were mapped to positional arguments and the optional `kwargs` was only used with free named arguments. With the above examples `run_keyword` was always called like it is nowadays called if it does not support `kwargs`.
#### Free named arguments with dynamic libraries
Dynamic libraries can also support [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments) (`**named`). A mandatory precondition for this support is that the `run_keyword` method [takes three arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords): the third one will get the free named arguments along with possible other named arguments. These arguments are passed to the keyword as a mapping.
What arguments a keyword accepts depends on what `get_keyword_arguments` [returns for it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). If the last argument starts with `**`, that keyword is recognized to accept free named arguments.
Using the free named argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has an argument specification `[a=d1, b=d2, **named]`. The comment shows the arguments that the `run_keyword` method is actually called with.
```
*** Test Cases *** # args, kwargs
No arguments
Dynamic # [], {}
Only positional
Dynamic x # [x], {}
Dynamic x y # [x, y], {}
Only free named
Dynamic x=1 # [], {x: 1}
Dynamic x=1 y=2 z=3 # [], {x: 1, y: 2, z: 3}
Positional and free named
Dynamic x y=2 # [x], {y: 2}
Dynamic x y=2 z=3 # [x], {y: 2, z: 3}
Positional as named and free named
Dynamic a=1 x=1 # [], {a: 1, x: 1}
Dynamic b=2 x=1 a=1 # [], {a: 1, b: 2, x: 1}
```
Note
Prior to Robot Framework 3.1, normal named arguments were mapped to positional arguments but nowadays they are part of the `kwargs` along with the free named arguments.
#### Named-only arguments with dynamic libraries
Starting from Robot Framework 3.1, dynamic libraries can have [named-only arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-only-arguments). This requires that the `run_keyword` method [takes three arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords): the third getting the named-only arguments along with the other named arguments.
In the [argument specification](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) returned by the `get_keyword_arguments` method named-only arguments are specified after possible variable number of arguments (`*varargs`) or a lone asterisk (`*`) if the keyword does not accept varargs. Named-only arguments can have default values, and the order of arguments with and without default values does not matter.
Using the named-only argument syntax with dynamic libraries is illustrated by the following examples. All the examples use a keyword Dynamic that has been specified to have argument specification `[positional=default, *varargs, named, named2=default, **free]`. The comment shows the arguments that the `run_keyword` method is actually called with.
```
*** Test Cases *** # args, kwargs
Only named-only
Dynamic named=value # [], {named: value}
Dynamic named=value named2=2 # [], {named: value, named2: 2}
Named-only with positional and varargs
Dynamic argument named=xxx # [argument], {named: xxx}
Dynamic a1 a2 named=3 # [a1, a2], {named: 3}
Named-only with positional as named
Dynamic named=foo positional=bar # [], {positional: bar, named: foo}
Named-only with free named
Dynamic named=value foo=bar # [], {named: value, foo=bar}
Dynamic named2=2 third=3 named=1 # [], {named: 1, named2: 2, third: 3}
```
#### 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.
| Name | Arguments | Purpose |
|---|---|---|
| `get_keyword_names` | | [Return names](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-dynamic-keyword-names) of the implemented keywords. |
| `run_keyword` | `name, arguments, kwargs` | [Execute the specified keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#running-dynamic-keywords) with given arguments. `kwargs` is optional. |
| `get_keyword_arguments` | `name` | Return keywords' [argument specification](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). Optional method. |
| `get_keyword_types` | `name` | Return keywords' [argument type information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-argument-types). Optional method. New in RF 3.1. |
| `get_keyword_tags` | `name` | Return keywords' [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-tags). Optional method. |
| `get_keyword_documentation` | `name` | Return keywords' and library's [documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-documentation). Optional method. |
| `get_keyword_source` | `name` | Return keywords' [source](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-source-information). Optional method. New in RF 3.2. |
A good example of using the dynamic API is Robot Framework's own [Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-library).
Note
Starting from Robot Framework 7.0, dynamic libraries can have asynchronous implementations of their special methods.
### [4\.1.7 Hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-134)
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](http://docs.python.org/reference/datamodel.html#attribute-access) first.
```
from somewhere import external_keyword
class HybridExample:
def get_keyword_names(self):
return ['my_keyword', 'external_keyword']
def my_keyword(self, arg):
print(f"My Keyword called with '{args}'.")
def __getattr__(self, name):
if name == 'external_keyword':
return external_keyword
raise AttributeError(f"Non-existing attribute '{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`.
#### 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, 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. 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](https://robotframework.org/robotframework/latest/libraries/Telnet.html) library.
### [4\.1.8 Handling Robot Framework's timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-135)
Robot Framework has its own [timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts) that can be used for stopping keyword execution if a test or a keyword takes too much time. There are two things to take into account related to them.
#### Doing cleanup if timeout occurs
Timeouts are technically implemented using `robot.errors.TimeoutExceeded` exception that can occur any time during a keyword execution. If a keyword wants to make sure possible cleanup activities are always done, it needs to handle these exceptions. Probably the simplest way to handle exceptions is using Python's `try/finally` structure:
```
def example():
try:
do_something()
finally:
do_cleanup()
```
A benefit of the above is that cleanup is done regardless of the exception. If there is a need to handle timeouts specially, it is possible to catch `TimeoutExceeded` explicitly. In that case it is important to re-raise the original exception afterwards:
```
from robot.errors import TimeoutExceeded
def example():
try:
do_something()
except TimeoutExceeded:
do_cleanup()
raise
```
Note
The `TimeoutExceeded` exception was named `TimeoutError` prior to Robot Framework 7.3. It was renamed to avoid a conflict with Python's standard exception with the same name. The old name still exists as a backwards compatible alias in the `robot.errors` module and can be used if older Robot Framework versions need to be supported.
#### Allowing timeouts to stop execution
Robot Framework's timeouts can stop normal Python code, but if the code calls functionality implemented using C or some other language, timeouts may not work. Well behaving keywords should thus avoid long blocking calls that cannot be interrupted.
As an example, [subprocess.run](https://docs.python.org/3/library/subprocess.html#subprocess.run) cannot be interrupted on Windows, so the following simple keyword cannot be stopped by timeouts there:
```
import subprocess
def run_command(command, *args):
result = subprocess.run([command, *args], encoding='UTF-8')
print(f'stdout: {result.stdout}\nstderr: {result.stderr}')
```
This problem can be avoided by using the lower level [subprocess.Popen](https://docs.python.org/3/library/subprocess.html#subprocess.Popen) and handling waiting in a loop with short timeouts. This adds quite a lot of complexity, though, so it may not be worth the effort in all cases.
```
import subprocess
def run_command(command, *args):
process = subprocess.Popen([command, *args], encoding='UTF-8',
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
try:
stdout, stderr = process.communicate(timeout=0.1)
except subprocess.TimeoutExpired:
continue
else:
break
print(f'stdout: {stdout}\nstderr: {stderr}')
```
### [4\.1.9 Using Robot Framework's internal modules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-136)
Test libraries 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.
#### Available APIs
[API documentation](http://robot-framework.readthedocs.org/) is hosted separately at the excellent [Read the Docs](http://readthedocs.org/) service. If you are unsure how to use certain API or is using them forward compatible, please send a question to [mailing list](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#mailing-lists).
#### Using BuiltIn library
The safest API to use are methods implementing keywords in the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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):
builtin = BuiltIn()
output = do_something_that_creates_a_lot_of_output(argument)
if builtin.robot_running:
output_dir = builtin.replace_variables('${OUTPUT_DIR}')
else:
output_dir = '.'
with open(os.path.join(output_dir, 'output.txt'), 'w') as file:
file.write(output)
print('*HTML* Output written to <a href="output.txt">output.txt</a>')
```
As the above examples illustrates, BuiltIn also has a convenient `robot_running` property for [detecting is Robot Framework running](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#detecting-is-robot-framework-running).
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.
### [4\.1.10 Extending existing test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-137)
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](https://github.com/robotframework/SeleniumLibrary).
```
from robot.api.deco import keyword
from SeleniumLibrary import SeleniumLibrary
class ExtendedSeleniumLibrary(SeleniumLibrary):
@keyword
def title_should_start_with(self, expected):
title = self.get_title()
if not title.startswith(expected):
raise AssertionError(f"Title '{title}' did not start with '{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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-keywords-with-same-names). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules).
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
[BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Get Library Instance 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-robot-framework-s-internal-modules). The following example illustrates how to implement the same Title Should Start With keyword as in the earlier example about [using inheritance](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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(f"Title '{title}' did not start with '{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.
```
*** Settings ***
Library SeleniumLibrary
Library SeLibExtensions
*** Test Cases ***
Example
Open Browser http://example # SeleniumLibrary
Title Should Start With Example # SeLibExtensions
```
#### Libraries using dynamic or hybrid API
Test libraries that use the [dynamic](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) or [hybrid library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-582)
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. 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries).
- [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-3)
- [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#putting-remote-library-to-use)
- [Importing Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-remote-library)
- [Starting and stopping remote servers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#starting-and-stopping-remote-servers)
- [4\.2.3 Supported argument and return value types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types)
- [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol)
- [Required methods](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#required-methods)
- [Using `get_keyword_names` and keyword specific getters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-get-keyword-names-and-keyword-specific-getters)
- [Using `get_library_information`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-get-library-information)
- [Executing remote keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-remote-keywords)
- [Different argument syntaxes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-argument-syntaxes)
### [4\.2.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-585)
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](http://www.xmlrpc.com/) protocol. There exists ready-made [generic remote servers](https://github.com/robotframework/RemoteInterface#available-remote-servers) for various languages like Python, Java, Ruby, .NET, and so on.
The remote library interface is provided by the Remote library that is one of the [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries). 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#remote-protocol) on top of an XML-RPC channel. The high level architecture of all this is illustrated in the picture below:

Robot Framework architecture with Remote library
Note
The remote client uses Python's standard [XML-RPC module](https://docs.python.org/library/xmlrpc.client.html). It does not support custom XML-RPC extensions implemented by some XML-RPC servers.
### [4\.2.2 Putting Remote library to use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-586)
#### [Importing Remote library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-587)
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 suite, or just want to give it a more descriptive name, you can give it an [alias when importing it](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-custom-name-to-library).
```
*** Settings ***
Library Remote http://127.0.0.1:8270 AS Example1
Library Remote http://example.com:8080/ AS Example2
Library Remote http://10.0.0.2/example 1 minute AS Example3
```
The URL used by the first example above is also the default address that the Remote library uses if no address is given.
The last example above shows how to give a custom timeout to the Remote library as an optional second argument. The timeout is used when initially connecting to the server and if a connection accidentally closes. Timeout can be given in Robot Framework [time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format) like `60s` or `2 minutes 10 seconds`. The default timeout is typically several minutes, but it depends on the operating system and its configuration. Notice that setting a timeout that is shorter than keyword execution time will interrupt the keyword.
Note
Port `8270` is the default port that remote servers are expected to use and it has been [registered by IANA](http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml?search=8270) for this purpose. This port number was selected because 82 and 70 are the ASCII codes of letters `R` and `F`, respectively.
Note
When connecting to the local machine, it is recommended to use IP address `127.0.0.1` instead of machine name `localhost`. This avoids address resolution that can be extremely slow [at least on Windows](http://stackoverflow.com/questions/14504450/pythons-xmlrpc-extremely-slow-one-second-per-call).
Note
If the URI contains no path after the server address, the [XML-RPC module](https://docs.python.org/library/xmlrpc.client.html) used by the Remote library will use `/RPC2` path by default. In practice using `http://127.0.0.1:8270` is thus identical to using `http://127.0.0.1:8270/RPC2`. Depending on the remote server this may or may not be a problem. No extra path is appended if the address has a path even if the path is just `/`. For example, neither `http://127.0.0.1:8270/` nor `http://127.0.0.1:8270/my/path` will be modified.
#### [Starting and stopping remote servers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-588)
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 [Process](https://robotframework.org/robotframework/latest/libraries/Process.html) or [SSH](https://github.com/robotframework/SSHLibrary) libraries, can start the server up, but then you may need to use [Import Library keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-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. Typically servers support the following methods:
- Regardless of the library used, remote servers should provide Stop Remote Server keyword that can be easily used by executed tests.
- Remote servers should have `stop_remote_server` method in their XML-RPC interface.
- Hitting `Ctrl-C` on the console where the server is running should stop the server.
- The server process can be terminated using tools provided by the operating system (e.g.
kill
).
Note
Servers 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-589)
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.
Both the Remote library and the Python remote server handle Python values according to the following rules. Other remote servers should behave similarly.
- Strings, numbers and Boolean values are passed without modifications.
- Python `None` is converted to an empty string.
- All lists, tuples, and other iterable objects (except strings and dictionaries) are passed as lists so that their contents are converted recursively.
- Dictionaries and other mappings are passed as dicts so that their keys are converted to strings and values converted to supported types recursively.
- Returned dictionaries are converted to so called *dot-accessible dicts* that allow accessing keys as attributes using the [extended variable syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extended-variable-syntax) like `${result.key}`. This works also with nested dictionaries like `${root.child.leaf}`.
- Strings containing bytes in the ASCII range that cannot be represented in XML (e.g. the null byte) are sent as [Binary objects](http://docs.python.org/library/xmlrpc.client.html#binary-objects) that internally use XML-RPC base64 data type. Received Binary objects are automatically converted to byte strings.
- Other types are converted to strings.
### [4\.2.4 Remote protocol](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-590)
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 remote protocol is implemented on top of [XML-RPC](http://www.xmlrpc.com/), 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 an extension.
The [Python remote server](https://github.com/robotframework/PythonRemoteServer) can be used as a reference implementation.
#### [Required methods](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-591)
There are two possibilities how remote servers can provide information about the keywords they contain. They are briefly explained below and documented more thoroughly in the subsequent sections.
1. Remote servers can implement the same methods as the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) has. This means `get_keyword_names` method and optional `get_keyword_arguments`, `get_keyword_types`, `get_keyword_tags` and `get_keyword_documentation` methods. Notice that using "camel-case names" like `getKeywordNames` is not possible similarly as in the normal dynamic API.
2. Starting from Robot Framework 4.0, remote servers can have a single `get_library_information` method that returns all library and keyword information as a single dictionary. If a remote server has this method, the other getter methods like `get_keyword_names` are not used at all. This approach has the benefit that there is only one XML-RPC call to get information while the approach explained above requires several calls per keyword. With bigger libraries the difference can be significant.
Regardless how remote servers provide information about their keywords, they must have `run_keyword` method that is used when keywords are executed. How the actual keywords are implemented is not relevant for the Remote library. Remote servers can either act as wrappers for the real test libraries, like the available [generic remote servers](https://github.com/robotframework/RemoteInterface#available-remote-servers) do, or they can implement keywords themselves.
Remote servers should additionally have `stop_remote_server` method in their public interface to ease stopping them. They should also automatically expose this method as Stop Remote Server keyword to allow using it in the test data regardless of the test library. Allowing users to stop the server is not always desirable, and servers may support disabling this functionality somehow. The method, and also the exposed keyword, should return `True` or `False` depending on whether stopping is allowed or not. That makes it possible for external tools to know if stopping the server succeeded.
#### [Using `get_keyword_names` and keyword specific getters](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-592)
This section explains how the Remote library gets keyword names and other information when the server implements `get_keyword_names`. The next sections covers using the newer `get_library_info` method.
The `get_keyword_names` method must return names of the keyword the server contains as a list of strings. Remote servers can, and should, also implement `get_keyword_arguments`, `get_keyword_types`, `get_keyword_tags` and `get_keyword_documentation` methods to provide more information about the keywords. All these methods take the name of the keyword as an argument and what they must return is explained in the table below.
| Method | Return value |
|---|---|
| `get_keyword_arguments` | Arguments as a list of strings in the [same format as with dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). |
| `get_keyword_types` | Type information as a list or dictionary of strings. See below for details. |
| `get_keyword_documentation` | Documentation as a string. |
| `get_keyword_tags` | Tags as a list of strings. |
Type information used for [argument conversion](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-conversion) can be returned either as a list mapping type names to arguments based on position or as a dictionary mapping argument names to type names directly. In practice this works the same way as when [specifying types using the @keyword decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-keyword-decorator) with normal libraries. The difference is that because the XML-RPC protocol does not support arbitrary values, type information needs to be specified using type names or aliases like `'int'` or `'integer'`, not using actual types like `int`. Additionally `None` or `null` values may not be allowed by the XML-RPC server, but an empty string can be used to indicate that certain argument does not have type information instead.
Argument conversion is supported also based on default values using the [same logic as with normal libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). For this to work, arguments with default values must be returned as tuples, not as strings, the [same way as with dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments). For example, argument conversion works if argument information is returned like `[('count', 1), ('caseless', True)]` but not if it is `['count=1', 'caseless=True']`.
Remote servers can also provide [general library documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-general-library-documentation) to be used when generating documentation with the [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc) tool. This information is got by calling `get_keyword_documentation` with special values `__intro__` and `__init__`.
Note
`get_keyword_types` is new in Robot Framework 3.1 and support for argument conversion based on defaults is new in Robot Framework 4.0.
#### [Using `get_library_information`](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-593)
The `get_library_information` method allows returning information about the whole library in one XML-RPC call. The information must be returned as a dictionary where keys are keyword names and values are nested dictionaries containing keyword information. The dictionary can also contain separate entries for generic library information.
The keyword information dictionary can contain keyword arguments, documentation, tags and types, and the respective keys are `args`, `doc`, `tags` and `types`. Information must be provided using same semantics as when `get_keyword_arguments`, `get_keyword_documentation`, `get_keyword_tags` and `get_keyword_types` discussed in the previous section. If some information is not available, it can be omitted from the info dictionary altogether.
`get_library_information` supports also returning general library documentation to be used with [Libdoc](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc). It is done by including special `__intro__` and `__init__` entries into the returned library information dictionary.
For example, a Python library like
```
"""Library documentation."""
from robot.api.deco import keyword
@keyword(tags=['x', 'y'])
def example(a: int, b=True):
"""Keyword documentation."""
pass
def another():
pass
```
could be mapped into this kind of library information dictionary:
```
{
'__intro__': {'doc': 'Library documentation'}
'example': {'args': ['a', 'b=True'],
'types': ['int'],
'doc': 'Keyword documentation.',
'tags': ['x', 'y']}
'another: {'args': []}
}
```
Note
`get_library_information` is new in Robot Framework 4.0.
#### [Executing remote keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-594)
When the Remote library wants the server to execute some keyword, it calls the remote server's `run_keyword` method and passes it the keyword name, a list of arguments, and possibly a dictionary of [free named arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#different-argument-syntaxes). Base types can be used as arguments directly, but more complex types are [converted to supported types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-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. Notice that only the `status` entry is mandatory, others can be omitted if they are not applicable.
| 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](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#logging-information) in format . It is also possible to embed [timestamps](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamps) to the log messages like `*INFO:1308435758660* Message with timestamp`. |
| return | Possible return value. Must be one of the [supported types](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-argument-and-return-value-types). |
| error | Possible error message. Used only when the execution fails. |
| traceback | Possible stack trace to [write into the log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status) using DEBUG level when the execution fails. |
| continuable | When set to `True`, or any value considered `True` in Python, the occurred failure is considered [continuable](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#continue-on-failure). |
| fatal | Like `continuable`, but denotes that the occurred failure is [fatal](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-test-execution-gracefully). |
#### [Different argument syntaxes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-595)
The Remote library is a [dynamic library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library), and in general it handles different argument syntaxes [according to the same rules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-keyword-arguments) as any other dynamic library. This includes mandatory arguments, default values, varargs, as well as [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax-with-dynamic-libraries).
Also free named arguments (`**kwargs`) works mostly the [same way as with other dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-named-arguments-with-dynamic-libraries). First of all, the `get_keyword_arguments` must return an argument specification that contains `**kwargs` exactly like with any other dynamic library. The main difference is that remote servers' `run_keyword` method must have an **optional** third argument that gets the kwargs specified by the user. The third argument must be optional because, for backwards-compatibility reasons, the Remote library passes kwargs to the `run_keyword` method only when they have been used in the test data.
In practice `run_keyword` should look something like the following Python and Java examples, depending on how the language handles optional arguments.
```
def run_keyword(name, args, kwargs=None):
# ...
```
```
public Map run_keyword(String name, List args) {
// ...
}
public Map run_keyword(String name, List args, Map kwargs) {
// ...
}
```
## [4\.3 Listener interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-583)
Robot Framework's listener interface provides a powerful mechanism for getting notifications and for inspecting and modifying data and results during execution. Listeners are called, for example, when suites, tests and keywords start and end, when output files are ready, and finally when the whole execution ends. Example usages include communicating with external test management systems, sending a message when a test fails, and modifying tests during execution.
Listeners are implemented as classes or modules with certain special methods. They can be [taken into use from the command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line) and be [registered by libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners). The former listeners are active during the whole execution while the latter are active only when executing suites where libraries registering them are imported.
There are two supported listener interface versions, [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2) and [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3). They have mostly the same methods, but these methods are called with different arguments. The newer listener version 3 is more powerful and generally recommended.
- [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-structure)
- [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions)
- [Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2)
- [Listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3)
- [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-listeners-into-use)
- [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line)
- [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libraries-as-listeners)
- [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-calling-order)
- [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-examples)
- [Getting information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-information)
- [Modifying data and results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#modifying-data-and-results)
- [More examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#more-examples)
### [4\.3.1 Listener structure](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-596)
Listeners are implement as modules or classes [similarly as libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-library-class-or-module). They can implement certain named hook methods depending on what events they are interested in. For example, if a listener wants to get a notification when a test starts, it can implement the `start_test` method. As discussed in the subsequent sections, different listener versions have slightly different set of available methods and they also are called with different arguments.
```
# Listener implemented as a module using the listener API version 3.
def start_suite(data, result):
print(f"Suite '{data.name}' starting.")
def end_test(data, result):
print(f"Test '{result.name}' ended with status {result.status}.")
```
Listeners do not need to implement any explicit interface, it is enough to simply implement needed methods and they will be recognized automatically. There are, however, base classes [robot.api.interfaces.ListenerV2](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV2) and [robot.api.interfaces.ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) that can be used to get method name completion in editors, type hints, and so on.
```
# Same as the above example, but uses an optional base class and type hints.
from robot import result, running
from robot.api.interfaces import ListenerV3
class Example(ListenerV3):
def start_suite(self, data: running.TestSuite, result: result.TestSuite):
print(f"Suite '{data.name}' starting.")
def end_test(self, data: running.TestCase, result: result.TestCase):
print(f"Test '{result.name}' ended with status {result.status}.")
```
Note
Optional listener base classes are new in Robot Framework 6.1.
In addition to using "snake case" like `start_test` with listener method names, it is possible to use "camel case" like `startTest`. This support was added when it was possible to run Robot Framework on Jython and implement listeners using Java. It is preserved for backwards compatibility reasons, but not recommended with new listeners.
### [4\.3.2 Listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-597)
There are two supported listener interface versions with version numbers 2 and 3. A listener can specify which version to use by having a `ROBOT_LISTENER_API_VERSION` attribute with value 2 or 3, respectively. Starting from Robot Framework 7.0, the listener version 3 is used by default if the version is not specified.
[Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2) and [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) have mostly the same methods, but arguments passed to these methods are different. Arguments given to listener 2 methods are strings and dictionaries containing information about execution. This information can be inspected and sent further, but it is not possible to modify it directly. Listener 3 methods get the same model objects that Robot Framework itself uses, and these model objects can be both inspected and modified.
Listener version 3 is more powerful than the older listener version 2 and generally recommended.
#### [Listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-598)
Listeners using the listener API version 2 get notifications about various events during execution, but they do not have access to actually executed tests and thus cannot directly affect the execution or created results.
Listener methods in the API version 2 are listed in the following table and in the API docs of the optional [ListenerV2](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV2) base class. All methods related to test execution progress have the same signature `method(name, attributes)`, where `attributes` is a dictionary containing details of the event. Listener methods are free to do whatever they want to do with the information they receive, but they cannot directly change it. If that is needed, [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3) can be used instead.
| Method | Arguments | Documentation |
|---|---|---|
| start\_suite | name, attributes | Called when a test suite starts. Contents of the attribute dictionary: `id`: Suite id. `s1` for the top level suite, `s1-s1` for its first child suite, `s1-s2` for the second child, and so on. `longname`: Suite name including parent suites. `doc`: Suite documentation. `metadata`: [Free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) as a dictionary. `source`: An absolute path of the file/directory the suite was created from. `suites`: Names of the direct child suites this suite has as a list. `tests`: Names of the tests this suite has as a list. Does not include tests of the possible child suites. `totaltests`: The total number of tests in this suite. and all its sub-suites as an integer. `starttime`: Suite execution start time. |
| end\_suite | name, attributes | Called when a test suite ends. Contents of the attribute dictionary: `id`: Same as in `start_suite`. `longname`: Same as in `start_suite`. `doc`: Same as in `start_suite`. `metadata`: Same as in `start_suite`. `source`: Same as in `start_suite`. `starttime`: Same as in `start_suite`. `endtime`: Suite execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Suite status as string `PASS`, `FAIL` or `SKIP`. `statistics`: Suite statistics (number of passed and failed tests in the suite) as a string. `message`: Error message if suite setup or teardown has failed, empty otherwise. |
| start\_test | name, attributes | Called when a test case starts. Contents of the attribute dictionary: `id`: Test id in format like `s1-s2-t2`, where the beginning is the parent suite id and the last part shows test index in that suite. `longname`: Test name including parent suites. `originalname`: Test name with possible variables unresolved. New in RF 3.2. `doc`: Test documentation. `tags`: Test tags as a list of strings. `template`: The name of the template used for the test. An empty string if the test not templated. `source`: An absolute path of the test case source file. New in RF 4.0. `lineno`: Line number where the test starts in the source file. New in RF 3.2. `starttime`: Test execution execution start time. |
| end\_test | name, attributes | Called when a test case ends. Contents of the attribute dictionary: `id`: Same as in `start_test`. `longname`: Same as in `start_test`. `originalname`: Same as in `start_test`. `doc`: Same as in `start_test`. `tags`: Same as in `start_test`. `template`: Same as in `start_test`. `source`: Same as in `start_test`. `lineno`: Same as in `start_test`. `starttime`: Same as in `start_test`. `endtime`: Test execution execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Test status as string `PASS`, `FAIL` or `SKIP`. `message`: Status message. Normally an error message or an empty string. |
| start\_keyword | name, attributes | Called when a keyword or a control structure such as `IF/ELSE` or `TRY/EXCEPT` starts. With keywords `name` is the full keyword name containing possible library or resource name as a prefix like `MyLibrary.Example Keyword`. With control structures `name` contains string representation of parameters. Keywords and control structures share most of attributes, but control structures can have additional attributes depending on their `type`. Shared attributes: `type`: String specifying type of the started item. Possible values are: `KEYWORD`, `SETUP`, `TEARDOWN`, `FOR`, `WHILE`, `ITERATION`, `IF`, `ELSE IF`, `ELSE`, `TRY`, `EXCEPT`, `FINALLY`, `VAR`, `RETURN`, `BREAK`, `CONTINUE` and `ERROR`. All type values were changed in RF 4.0 and in RF 5.0 `FOR ITERATION` was changed to `ITERATION`. `kwname`: Name of the keyword without library or resource prefix. String representation of parameters with control structures. `libname`: Name of the library or resource file the keyword belongs to. An empty string with user keywords in a test case file and with control structures. `doc`: Keyword documentation. `args`: Keyword's arguments as a list of strings. `assign`: A list of variable names that keyword's return value is assigned to. `tags`: [Keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags) as a list of strings. `source`: An absolute path of the file where the keyword was used. New in RF 4.0. `lineno`: Line where the keyword was used. Typically an integer, but can be `None` if a keyword has been executed by a listener. New in RF 4.0. `status`: Initial keyword status. `NOT RUN` if keyword is not executed (e.g. due to an earlier failure), `NOT SET` otherwise. New in RF 4.0. `starttime`: Keyword execution start time. Additional attributes for `FOR` types: `variables`: Assigned variables for each loop iteration as a list or strings. `flavor`: Type of loop (e.g. `IN RANGE`). `values`: List of values being looped over as a list or strings. `start`: Start configuration. Only used with `IN ENUMERATE` loops. New in RF 6.1. `mode`: Mode configuration. Only used with `IN ZIP` loops. New in RF 6.1. `fill`: Fill value configuration. Only used with `IN ZIP` loops. New in RF 6.1. Additional attributes for `ITERATION` types with `FOR` loops: `variables`: Variables and string representations of their contents for one `FOR` loop iteration as a dictionary. Additional attributes for `WHILE` types: `condition`: The looping condition. `limit`: The maximum iteration limit. `on_limit`: What to do if the limit is exceeded. Valid values are `pass` and `fail`. New in RF 7.0. `on_limit_message`: The custom error raised when the limit of the WHILE loop is reached. New in RF 6.1. Additional attributes for `IF` and `ELSE IF` types: `condition`: The conditional expression being evaluated. With `ELSE IF` new in RF 6.1. Additional attributes for `EXCEPT` types: `patterns`: The exception patterns being matched as a list or strings. `pattern_type`: The type of pattern match (e.g. `GLOB`). `variable`: The variable containing the captured exception. Additional attributes for `RETURN` types: `values`: Return values from a keyword as a list or strings. Additional attributes for `VAR` types: `name`: Variable name. `value`: Variable value. A string with scalar variables and a list otherwise. `scope`: Variable scope (e.g. `GLOBAL`) as a string. Additional attributes for control structures are in general new in RF 6.0. `VAR` is new in RF 7.0. |
| end\_keyword | name, attributes | Called when a keyword or a control structure ends. `name` is the full keyword name containing possible library or resource name as a prefix. For example, `MyLibrary.Example Keyword`. Control structures have additional attributes, which change based on the `type` attribute. For descriptions of all possible attributes, see the `start_keyword` section. Contents of the attribute dictionary: `type`: Same as with `start_keyword`. `kwname`: Same as with `start_keyword`. `libname`: Same as with `start_keyword`. `doc`: Same as with `start_keyword`. `args`: Same as with `start_keyword`. `assign`: Same as with `start_keyword`. `tags`: Same as with `start_keyword`. `source`: Same as with `start_keyword`. `lineno`: Same as with `start_keyword`. `starttime`: Same as with `start_keyword`. `endtime`: Keyword execution end time. `elapsedtime`: Total execution time in milliseconds as an integer `status`: Keyword status as string `PASS`, `FAIL`, `SKIP` or `NOT RUN`. `SKIP` and `NOT RUN` are new in RF 4.0. |
| log\_message | message | Called when an executed keyword writes a log message. `message` is a dictionary with the following contents: `message`: The content of the message. `level`: [Log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels) used in logging the message. `timestamp`: Message creation time in format `YYYY-MM-DD hh:mm:ss.mil`. `html`: String `yes` or `no` denoting whether the message should be interpreted as HTML or not. Not called if the message level is below the current [threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). |
| message | message | Called when the framework itself writes a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) message. `message` is a dictionary with the same contents as with `log_message` method. |
| library\_import | name, attributes | Called when a library has been imported. `name` is the name of the imported library. If the library has been given a custom name when imported it using `AS`, `name` is the specified alias. Contents of the attribute dictionary: `args`: Arguments passed to the library as a list. `originalname`: The original library name if the library has been given an alias using `AS`, otherwise same as `name`. `source`: An absolute path to the library source. An empty string if getting the source of the library failed for some reason. `importer`: An absolute path to the file importing the library. `None` when [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) is imported as well as when using the Import Library keyword. |
| resource\_import | name, attributes | Called when a resource file has been imported. `name` is the name of the imported resource file without the file extension. Contents of the attribute dictionary: `source`: An absolute path to the imported resource file. `importer`: An absolute path to the file importing the resource file. `None` when using the Import Resource keyword. |
| variables\_import | name, attributes | Called when a variable file has been imported. `name` is the name of the imported variable file with the file extension. Contents of the attribute dictionary: `args`: Arguments passed to the variable file as a list. `source`: An absolute path to the imported variable file. `importer`: An absolute path to the file importing the resource file. `None` when using the Import Variables keyword. |
| output\_file | path | Called when writing to an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is ready. `path` is an absolute path to the file as a string or a string `None` if creating the output file is disabled. |
| log\_file | path | Called when writing to a [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) is ready. `path` is an absolute path to the file as a string. Not called if creating the log file is disabled. |
| report\_file | path | Called when writing to a [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is ready. `path` is an absolute path to the file as a string. Not called if creating the report file is disabled. |
| xunit\_file | path | Called when writing to an [xunit file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-file) is ready. `path` is an absolute path to the file as a string. Only called if creating the xunit file is enabled. |
| debug\_file | path | Called when writing to a [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) is ready. `path` is an absolute path to the file as a string. Only called if creating the debug file is enabled. |
| close | | Called when the whole test execution ends. With [library listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-listeners) called when the library goes out of scope. |
#### [Listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-599)
Listener version 3 has mostly the same methods as [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2), but arguments of the methods related to test execution are different. These methods get actual running and result model objects that used by Robot Framework itself, and listeners can both query information they need and change the model objects on the fly.
Note
Modifications to the data can also be done using [pre-run modifiers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifiers). The main benefit of using listeners is that changes can be done dynamically based on what happens during the execution. Another difference is that command like options related to [selecting test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-test-cases) affect tests added by pre-run modifiers but not tests added by listeners.
Listener version 3 was enhanced heavily in Robot Framework 7.0 when it got methods related to keywords and control structures. It was enhanced further in Robot Framework 7.1 when it got methods related to library, resource file and variable file imports.
Listener version 3 has separate methods for library keywords, user keywords and all control structures. If there is a need to listen to all keyword related events, it is possible to implement `start_keyword` and `end_keyword`. In addition to that, `start_body_item` and `end_body_item` can be implemented to get notifications related to all keywords and control structures. These higher level listener methods are not called if more specific methods like `start_library_keyword` or `end_if` are implemented.
Listener methods in the API version 3 are listed in the following table and in the API docs of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class.
| Method | Arguments | Documentation |
|---|---|---|
| start\_suite | data, result | Called when a test suite starts. `data` and `result` are model objects representing the [executed test suite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.TestSuite), respectively. |
| end\_suite | data, result | Called when a test suite ends. Same arguments as with `start_suite`. |
| start\_test | data, result | Called when a test case starts. `data` and `result` are model objects representing the [executed test case](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestCase) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.TestCase), respectively. |
| end\_test | data, result | Called when a test case ends. Same arguments as with `start_test`. |
| start\_keyword | data, result | Called when a keyword starts. `data` and `result` are model objects representing the [executed keyword call](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.Keyword) and [its execution results](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.Keyword), respectively. This method is called, by default, with user keywords, library keywords and when a keyword call is invalid. It is not called if a more specific `start_user_keyword`, `start_library_keyword` or `start_invalid_keyword` method is implemented. |
| end\_keyword | data, result | Called when a keyword ends. Same arguments and other semantics as with `start_keyword`. |
| start\_user\_keyword | data, implementation, result | Called when a user keyword starts. `data` and `result` are the same as with `start_keyword` and `implementation` is the actually executed [user keyword](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.resourcemodel.UserKeyword). If this method is implemented, `start_keyword` is not called with user keywords. |
| end\_user\_keyword | data, implementation, result | Called when a user keyword ends. Same arguments and other semantics as with `start_user_keyword`. |
| start\_library\_keyword | data implementation, result | Called when a library keyword starts. `data` and `result` are the same as with `start_keyword` and `implementation` represents the executed [library keyword](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.librarykeyword.LibraryKeyword). If this method is implemented, `start_keyword` is not called with library keywords. |
| end\_library\_keyword | data, implementation, result | Called when a library keyword ends. Same arguments and other semantics as with `start_library_keyword`. |
| start\_invalid\_keyword | data implementation, result | Called when an invalid keyword call starts. `data` and `result` are the same as with `start_keyword` and `implementation` represents the [invalid keyword call](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.invalidkeyword.InvalidKeyword). Keyword may not have been found, there could have been multiple matches, or the keyword call itself could have been invalid. If this method is implemented, `start_keyword` is not called with invalid keyword calls. |
| end\_invalid\_keyword | data, implementation, result | Called when an invalid keyword call ends. Same arguments and other semantics as with `start_invalid_keyword`. |
| start\_for, start\_for\_iteration, start\_while, start\_while\_iteration, start\_if, start\_if\_branch, start\_try, start\_try\_branch, start\_group, start\_var, start\_continue, start\_break, start\_return | data, result | Called when control structures start. See the documentation and type hints of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class for more information. |
| end\_for, end\_for\_iteration, end\_while, end\_while\_iteration, end\_if, end\_if\_branch, end\_try, end\_try\_branch, end\_group, end\_var, end\_continue, end\_break, end\_return | data, result | Called when control structures end. See the documentation and type hints of the optional [ListenerV3](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.ListenerV3) base class for more information. |
| start\_error | data, result | Called when invalid syntax starts. |
| end\_error | data, result | Called when invalid syntax ends. |
| start\_body\_item | data, result | Called when a keyword or a control structure starts, unless a more specific method such as `start_keyword` or `start_if` is implemented. |
| end\_body\_item | data, result | Called when a keyword or a control structure ends, unless a more specific method such as `end_keyword` or `end_if` is implemented. |
| log\_message | message | Called when an executed keyword writes a log message. `message` is a model object representing the [logged message](http://robot-framework.readthedocs.org/en/master/autodoc/robot.result.html#robot.result.model.Message). This method is not called if the message has level below the current [threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-levels). |
| message | message | Called when the framework itself writes a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) message. `message` is same object as with `log_message`. |
| library\_import | library, importer | Called after a library has been imported. [library](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.testlibraries.TestLibrary) represents the imported library. It can be inspected and also modified. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the library was imported. |
| resource\_import | resource, importer | Called after a resource file has been imported. [resource](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.ResourceFile) represents the imported resource file. It can be inspected and also modified. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the resource was imported. |
| variables\_import | attrs, importer | Called after a variable file has been imported. `attrs` contains information about the imported variable file as a dictionary. It can be inspected, but modifications to it have no effect. [importer](https://robot-framework.readthedocs.io/en/stable/autodoc/robot.running.html#robot.running.resourcemodel.Import) contains information about the location where the variable file was imported. This method will be changed in the future so that the `attrs` dictionary is replaced with an object representing the imported variable file. |
| output\_file | path | Called when writing to an [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object or the `None` object if creating the output file is disabled. |
| log\_file | path | Called when writing to a [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Not called if creating the log file is disabled. |
| report\_file | path | Called when writing to a [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Not called if creating the report file is disabled. |
| xunit\_file | path | Called when writing to an [xunit file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Only called if creating the xunit file is enabled. |
| debug\_file | path | Called when writing to a [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) is ready. `path` is an absolute path to the file as a `pathlib.Path` object. Only called if creating the debug file is enabled. |
| close | | Called when the whole test execution ends. With [library listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-listeners) called when the library goes out of scope. |
Note
Methods related to keywords and control structures are new in Robot Framework 7.0.
Note
Methods related to library, resource file and variable file imports are new in Robot Framework 7.1.
Note
Prior to Robot Framework 7.0, paths passed to result file related listener version 3 methods were strings.
### [4\.3.3 Taking listeners into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-600)
#### [Registering listeners from command line](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-601)
Listeners that need to be active during the whole execution must be taken into use from the command line. That is done using 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, similarly as [library name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-name) is got from the class or module implementing the library. The specified listeners must be in the same [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) where test libraries are searched from when they are imported. In addition to registering a listener by using a name, it is possible to give an absolute or a relative path to the listener file [similarly as with test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-physical-path-to-library). It is possible to take multiple listeners into use by using this option several times:
```
robot --listener MyListener tests.robot
robot --listener path/to/MyListener.py tests.robot
robot --listener module.Listener --listener AnotherListener tests.robot
```
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. If a listener is given as an absolute Windows path, the colon after the drive letter is not considered a separator. Additionally, it is possible to use a semicolon (`;`) as an alternative argument separator. This is useful if listener arguments themselves contain colons, but requires surrounding the whole value with quotes on UNIX-like operating systems:
```
robot --listener listener.py:arg1:arg2 tests.robot
robot --listener "listener.py;arg:with:colons" tests.robot
robot --listener c:\path\listener.py;d:\first\arg;e:\second\arg tests.robot
```
In addition to passing arguments one-by-one as positional arguments, it is possible to pass them using the [named argument syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#named-argument-syntax) similarly as when using keywords:
```
robot --listener listener.py:name=value tests.robot
robot --listener "listener.py;name=value:with:colons;second=argument" tests.robot
```
Listener arguments are automatically converted using [same rules as with keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) based on [type hints](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-argument-types-using-function-annotations) and [default values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#implicit-argument-types-based-on-default-values). For example, this listener
```
class Listener:
def __init__(self, port: int, log=True):
self.port = post
self.log = log
```
could be used like
```
robot --listener Listener:8270:false
```
and the first argument would be converted to an integer based on the type hint and the second to a Boolean based on the default value.
Note
Both the named argument syntax and argument conversion are new in Robot Framework 4.0.
#### [Libraries as listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-602)
Sometimes it is useful also for [test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries) to get notifications about test execution. This allows them, for example, to perform certain clean-up activities automatically when a test suite or the whole test execution ends.
##### Registering listener
A test library can register a listener by using the `ROBOT_LIBRARY_LISTENER` attribute. The value of this attribute should be an instance of the listener to use. It may be a totally independent listener or the library itself can act as a listener. To avoid listener methods to be exposed as keywords in the latter case, it is possible to prefix them with an underscore. For example, instead of using `end_suite` it is possible to use `_end_suite`.
Following examples illustrates using an external listener as well as a library acting as a listener itself:
```
from listener import Listener
class LibraryWithExternalListener:
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
ROBOT_LIBRARY_LISTENER = Listener()
def example_keyword(self):
...
```
```
class LibraryItselfAsListener:
ROBOT_LIBRARY_SCOPE = 'SUITE'
ROBOT_LISTENER_API_VERSION = 2
def __init__(self):
self.ROBOT_LIBRARY_LISTENER = self
# Use the '_' prefix to avoid listener method becoming a keyword.
def _end_suite(self, name, attrs):
print(f"Suite '{name}' ending with status {attrs['id']}.")
def example_keyword(self):
...
```
As the second example above already demonstrated, library listeners can specify [listener interface versions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-interface-versions) using the `ROBOT_LISTENER_API_VERSION` attribute exactly like any other listener.
Starting from Robot Framework 7.0, a listener can register itself to be a listener also by using a string `SELF` (case-insensitive) as a listener. This is especially convenient when using the [@library decorator](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-decorator):
```
from robot.api.deco import keyword, library
@library(scope='SUITE', listener='SELF')
class LibraryItselfAsListener:
# Listener version is not specified, so uses the listener version 3 by default.
# When using the @library decorator, keywords must use the @keyword decorator,
# so there is no need to use the '_' prefix here.
def end_suite(self, data, result):
print(f"Suite '{data.name}' ending with status {result.status}.")
@keyword
def example_keyword(self):
...
```
It is also possible to specify multiple listeners for a single library by giving `ROBOT_LIBRARY_LISTENER` a value as a list:
```
from listeners import Listener1, Listener2, Listener3
class LibraryWithMultipleListeners:
ROBOT_LIBRARY_LISTENER = [Listener1(), Listener2(), Listener3()]
def example_keyword(self):
...
```
##### Called listener methods
Library listeners get notifications about all events in suites where libraries using them are imported. In practice this means that suite, test, keyword, control structure and log message related methods are called. In addition to them, the `close` method is called when the library goes out of the scope.
If library creates a new listener instance every time when the library itself is instantiated, the actual listener instance to use will change according to the [library scope](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-scope).
### [4\.3.4 Listener calling order](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-603)
By default, listeners are called in the order they are taken into use so that listeners registered from the command line are called before library listeners. It is, however, possible to control the calling order by setting the special `ROBOT_LISTENER_PRIORITY` attribute to an integer or a floating point value. The bigger the number, the higher precedence the listener has and the earlier it is called. The number can be positive or negative and it is zero by default.
The custom order does not affect the `close` method of library listeners, though. That method is always called when the library goes out of its scope.
Note
Controlling listener calling order is new in Robot Framework 7.1.
### [4\.3.5 Listener examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-604)
This section contains examples using the listener interface. First examples illustrate getting notifications during execution and latter examples modify executed tests and created results.
#### [Getting information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-605)
The first example is implemented as a Python module. It uses the [listener version 2](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-2), but could equally well be implemented by using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
```
"""Listener that stops execution if a test fails."""
ROBOT_LISTENER_API_VERSION = 2
def end_test(name, attrs):
if attrs['status'] == 'FAIL':
print(f"Test '{name}'" failed: {attrs['message']}")
input("Press enter to continue.")
```
If the above example would be saved to, for example, PauseExecution.py file, it could be used from the command line like this:
```
robot --listener path/to/PauseExecution.py tests.robot
```
The next example, which still uses the listener version 2, 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 it also has a default value. Note that in real usage, the [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) functionality available through the command line option \--debugfile is probably more useful than this example.
```
import os.path
import tempfile
class Example:
ROBOT_LISTENER_API_VERSION = 2
def __init__(self, file_name='listen.txt'):
path = os.path.join(tempfile.gettempdir(), file_name)
self.file = open(path, 'w')
def start_suite(self, name, attrs):
self.file.write("%s '%s'\n" % (name, attrs['doc']))
def start_test(self, name, attrs):
tags = ' '.join(attrs['tags'])
self.file.write("- %s '%s' [ %s ] :: " % (name, attrs['doc'], tags))
def end_test(self, name, attrs):
if attrs['status'] == 'PASS':
self.file.write('PASS\n')
else:
self.file.write('FAIL: %s\n' % attrs['message'])
def end_suite(self, name, attrs):
self.file.write('%s\n%s\n' % (attrs['status'], attrs['message']))
def close(self):
self.file.close()
```
#### [Modifying data and results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-606)
The following examples illustrate how to modify the executed tests and suites as well as the execution results. All these examples require using the [listener version 3](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#listener-version-3).
##### Modifying executed suites and tests
Changing what is executed is as easy as modifying the model objects representing executed data passed to listener methods. This is illustrated by the example below that adds a new test to each executed suite and a new keyword call to each test.
```
def start_suite(data, result):
data.tests.create(name='New test')
def start_test(data, result):
data.body.create_keyword(name='Log', args=['Keyword added by listener!'])
```
This API is very similar to the [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) API that can be used to modify suites and tests before the whole test execution starts. The main benefit of using the listener API is that modifications can be done dynamically based on execution results or otherwise. This allows, for example, interesting possibilities for model based testing.
Although the listener interface is not built on top of Robot Framework's internal [visitor interface](http://robot-framework.readthedocs.org/en/master/autodoc/robot.model.html#module-robot.model.visitor) similarly as the pre-run modifier API, listeners can still use the visitors interface themselves. For example, the `SelectEveryXthTest` visitor used in [pre-run modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-run-modifier) examples could be used like this:
```
from SelectEveryXthTest import SelectEveryXthTest
def start_suite(suite, result):
selector = SelectEveryXthTest(x=2)
suite.visit(selector)
```
##### Accessing library or resource file
It is possible to get more information about the actually executed keyword and the library or resource file it belongs to:
```
from robot.running import Keyword as KeywordData, LibraryKeyword
from robot.result import Keyword as KeywordResult
def start_library_keyword(data: KeywordData,
implementation: LibraryKeyword,
result: KeywordResult):
library = implementation.owner
print(f"Keyword '{implementation.name}' is implemented in library "
f"'{library.name}' at '{implementation.source}' on line "
f"{implementation.lineno}. The library has {library.scope.name} "
f"scope and the current instance is {library.instance}.")
```
As the above example illustrates, it is possible to get an access to the actual library instance. This means that listeners can inspect the library state and also modify it. With user keywords it is even possible to modify the keyword itself or, via the `owner` resource file, any other keyword in the resource file.
##### Modifying results
Test execution results can be altered by modifying the result objects passed to listener methods. This is demonstrated by the following listener that is implemented as a class and also uses type hints:
```
from robot import result, running
class ResultModifier:
def __init__(self, max_seconds: float = 10.0):
self.max_seconds = max_seconds
def start_suite(self, data: running.TestSuite, result: result.TestSuite):
result.doc = 'Documentation set by listener.'
# Information about tests only available via data at this point.
smoke_tests = [test for test in data.tests if 'smoke' in test.tags]
result.metadata['Smoke tests'] = len(smoke_tests)
def end_test(self, data: running.TestCase, result: result.TestCase):
elapsed_seconds = result.elapsed_time.total_seconds()
if result.status == 'PASS' and elapsed_seconds > self.max_seconds:
result.status = 'FAIL'
result.message = 'Test execution took too long.'
def log_message(self, msg: result.Message):
if msg.level == 'WARN' and not msg.html:
msg.message = f'<b style="font-size: 1.5em">{msg.message}</b>'
msg.html = True
if self._message_is_not_relevant(msg.message):
msg.message = None
def _message_is_not_relevant(self, message: str) -> bool:
...
```
A limitation is that modifying the name of the current test suite or test case is not possible because it has already been written to the [output.xml](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-xml) file when listeners are called. Due to the same reason modifying already finished tests in the `end_suite` method has no effect either.
When modifying logged messages, it is possible to remove a message altogether by setting `message` to `None` as the above example demonstrates. This can be used for removing sensitive or non-relevant messages so that there is nothing visible in the log file.
This API is very similar to the [pre-Rebot modifier](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#pre-rebot-modifier) API that can be used to modify results before report and log are generated. The main difference is that listeners modify also the created output.xml file.
Note
Removing messages altogether by setting them to `None` is new in Robot Framework 7.2.
##### Changing keyword and control structure status
Listeners can also affect the execution flow by changing statuses of the executed keywords and control structures. For example, if a listener changes the status of a passed keyword to FAIL, the keyword is considered failed exactly as if it had failed normally. Similarly, it is possible to change the status of a passed or failed keyword to SKIP to get the keyword and the whole test skipped. It is also possible to silence failures by changing the status to PASS, but this should be done only in special cases and with great care to avoid hiding real failures.
The following example demonstrates changing the status by failing keywords that take too long time to execute. The previous example had similar logic with tests, but this listener also stops the execution immediately if there is a keyword that is too slow. As the example shows, listeners can also change the error message, not only the status.
```
from robot import result, running
class KeywordPerformanceMonitor:
def __init__(self, max_seconds: float = 0.1):
self.max_seconds = max_seconds
def end_keyword(self, data: running.Keyword, result: result.Keyword):
elapsed_seconds = result.elapsed_time.total_seconds()
if result.status == 'PASS' and elapsed_seconds > self.max_seconds:
result.status = 'FAIL'
result.message = 'Keyword execution took too long.'
```
Note
Changes to status only affect the execution flow starting from Robot Framework 7.1.
#### [More examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-607)
Keyword and control structure related listener version 3 methods are so versatile that covering them fully here in the User Guide is not possible. For more examples, you can see the [acceptance tests](https://github.com/robotframework/robotframework/tree/master/atest/testdata/output/listener_interface/body_items_v3) using theses methods in various ways.
## [4\.4 Parser interface](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-584)
Robot Framework supports external parsers that can handle custom data formats or even override Robot Framework's own parser.
Note
Custom parsers are new in Robot Framework 6.1.
- [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-parsers-into-use)
- [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-api)
- [`EXTENSION` or `extension` attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#extension-or-extension-attribute)
- [`parse` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parse-method)
- [`parse_init` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parse-init-method)
- [Optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#optional-base-class)
- [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#examples-2)
- [Parser implemented as module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-implemented-as-module)
- [Parser implemented as class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-implemented-as-class)
- [Parser extending optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-extending-optional-base-class)
- [Parser as preprocessor](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#parser-as-preprocessor)
### [4\.4.1 Taking parsers into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-608)
Parsers are taken into use from the command line with the \--parser option using exactly the same semantics as with [listeners](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registering-listeners-from-command-line). This includes specifying parsers as names or paths, giving arguments to parser classes, and so on:
```
robot --parser MyParser tests.custom
robot --parser path/to/MyParser.py tests.custom
robot --parser Parser1:arg --parser Parser2:a1:a2 path/to/tests
```
### [4\.4.2 Parser API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-609)
Parsers can be implemented both as modules and classes. This section explains what attributes and methods they must contain.
#### [`EXTENSION` or `extension` attribute](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-610)
This attribute specifies what file extension or extensions the parser supports. Both `EXTENSION` and `extension` names are accepted, and the former has precedence if both exist. The attribute can be either a string or a sequence of strings. Extensions are case-insensitive and can be specified with or without the leading dot. If a parser is implemented as a class, it is possible to set this attribute either as a class attribute or as an instance attribute.
Also extensions containing multiple parts like .example.ext or .robot.zip are supported.
Note
If a parser supports the .robot extension, it will be used for parsing these files instead of the standard parser.
#### [`parse` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-611)
The mandatory `parse` method is responsible for parsing [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files). It is called with each parsed file that has an extension that the parser supports. The method must return a [TestSuite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) object.
In simple cases `parse` can be implemented so that it accepts just a single argument that is a [pathlib.Path](https://docs.python.org/library/pathlib.html) object pointing to the file to parse. If the parser is interested in defaults for Test Setup, Test Teardown, Test Tags and Test Timeout set in higher level [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files), the `parse` method must accept two arguments. In that case the second argument is a [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) object.
#### [`parse_init` method](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-612)
The optional `parse_init` method is responsible for parsing [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files) i.e. files in format `__init__.ext` where `.ext` is an extension supported by the parser. The method must return a [TestSuite](http://robot-framework.readthedocs.org/en/master/autodoc/robot.running.html#robot.running.model.TestSuite) object representing the whole directory. Suites created from child suite files and directories will be added to its child suites.
Also `parse_init` can be implemented so that it accepts one or two arguments, depending on is it interested in test related default values or not. If it accepts defaults, it can manipulate the passed [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) object and changes are seen when parsing child suite files.
This method is only needed if a parser needs to support suite initialization files.
#### [Optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-613)
Parsers do not need to implement any explicit interface, but it may be helpful to extend the optional [Parser](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.Parser) base class. The main benefit is that the base class has documentation and type hints. It also works as a bit more formal API specification.
### [4\.4.3 Examples](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-614)
#### [Parser implemented as module](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-615)
The first example demonstrates a simple parser implemented as a module and supporting one hard-coded extension. It just creates a dummy suite and does not actually parse anything.
```
from robot.api import TestSuite
EXTENSION = '.example'
def parse(source):
suite = TestSuite(name='Example', source=source)
test = suite.tests.create(name='Test')
test.body.create_keyword(name='Log', args=['Hello!'])
return suite
```
#### [Parser implemented as class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-616)
The second parser is implemented as a class that accepts the extension to use as an argument. The parser reads the given source file and creates dummy tests from each line it contains.
```
from pathlib import Path
from robot.api import TestSuite
class ExampleParser:
def __init__(self, extension: str):
self.extension = extension
def parse(self, source: Path) -> TestSuite:
name = TestSuite.name_from_source(source, self.extension)
suite = TestSuite(name, source=source)
for line in source.read_text().splitlines():
test = suite.tests.create(name=line)
test.body.create_keyword(name='Log', args=['Hello!'])
return suite
```
#### [Parser extending optional base class](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-617)
This parser extends the optional [Parser](https://robot-framework.readthedocs.io/en/master/autodoc/robot.api.html#robot.api.interfaces.Parser) base class. It supports parsing suite initialization files, uses [TestDefaults](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.builder.html#robot.running.builder.settings.TestDefaults) and registers multiple extensions.
```
from pathlib import Path
from robot.api import TestSuite
from robot.api.interfaces import Parser, TestDefaults
class ExampleParser(Parser):
extension = ('example', 'another')
def parse(self, source: Path, defaults: TestDefaults) -> TestSuite:
"""Create a suite and set possible defaults from init files to tests."""
suite = TestSuite(TestSuite.name_from_source(source), source=source)
for line in source.read_text().splitlines():
test = suite.tests.create(name=line, doc='Example')
test.body.create_keyword(name='Log', args=['Hello!'])
defaults.set_to(test)
return suite
def parse_init(self, source: Path, defaults: TestDefaults) -> TestSuite:
"""Create a dummy suite and set some defaults.
This method is called only if there is an initialization file with
a supported extension.
"""
defaults.tags = ('tags', 'from init')
defaults.setup = {'name': 'Log', 'args': ['Hello from init!']}
return TestSuite(TestSuite.name_from_source(source.parent), doc='Example',
source=source, metadata={'Example': 'Value'})
```
#### [Parser as preprocessor](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-618)
The final example parser acts as a preprocessor for Robot Framework data files that supports headers in format `=== Test Cases ===` in addition to `*** Test Cases ***`. In this kind of usage it is convenient to use [TestSuite.from\_string](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_string), [TestSuite.from\_model](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_model) and [TestSuite.from\_file\_system](https://robot-framework.readthedocs.io/en/master/autodoc/robot.running.html#robot.running.model.TestSuite.from_file_system) factory methods for constructing the returned suite.
```
from pathlib import Path
from robot.running import TestDefaults, TestSuite
class RobotPreprocessor:
extension = '.robot'
def parse(self, source: Path, defaults: TestDefaults) -> TestSuite:
data = source.read_text()
for header in 'Settings', 'Variables', 'Test Cases', 'Keywords':
data = data.replace(f'=== {header} ===', f'*** {header} ***')
suite = TestSuite.from_string(data, defaults=defaults)
return suite.config(name=TestSuite.name_from_source(source), source=source)
```
## [5 Supporting Tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-153)
- [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-documentation-tool-libdoc)
- [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-documentation-tool-testdoc)
- [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-clean-up-tool-tidy)
- [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#external-tools)
## [5\.1 Library documentation tool (Libdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-619)
- [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage)
- [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#writing-documentation)
- [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax)
- [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking-1)
- [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#representing-arguments)
- [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example)
Libdoc is Robot Framework's built-in tool that can generate documentation for Robot Framework libraries and resource files. It can generate HTML documentation for humans as well as machine readable spec files in XML and JSON formats. Libdoc also has few special commands to show library or resource information on the console.
Documentation can be created for:
- libraries implemented using the normal static library [API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries),
- libraries using the [dynamic API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-libraries), including remote libraries,
- [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files),
- [suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files), and
- [suite initialization files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-initialization-files).
Additionally it is possible to use XML and JSON spec files created by Libdoc earlier as an input.
Note
Support for generating documentation for suite files and suite initialization files is new in Robot Framework 6.0.
### [5\.1.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-623)
#### Synopsis
```
libdoc [options] library_or_resource output_file
libdoc [options] library_or_resource list|show|version [names]
```
#### Options
> | | |
> |---|---|
> | `-f, --format <html|xml|json|libspec>` | |
> | | Specifies whether to generate an HTML output for humans or a machine readable spec file in XML or JSON format. The `libspec` format means XML spec with documentations converted to HTML. The default format is got from the output file extension. |
> | `-s, --specdocformat <raw|html>` | |
> | | Specifies the documentation format used with XML and JSON spec files. `raw` means preserving the original documentation format and `html` means converting documentation to HTML. The default is `raw` with XML spec files and `html` with JSON specs and when using the special `libspec` format. |
> | `-F, --docformat <robot|html|text|rest>` | |
> | | Specifies the source documentation format. Possible values are Robot Framework's documentation format, HTML, plain text, and reStructuredText. Default value can be specified in test library source code and the initial default value is `robot`. |
> | `--theme <dark|light|none>` | |
> | | Use dark or light HTML theme. If this option is not used, or the value is `none`, the theme is selected based on the browser color scheme. Only applicable with HTML outputs. New in Robot Framework 6.0. |
> | `--language <lang>` | |
> | | Set the default language in documentation. `lang` must be a code of a built-in language, which are `en` and `fi`. New in Robot Framework 7.2. |
> | `-N, --name <newname>` | |
> | | Sets the name of the documented library or resource. |
> | `-V, --version <newversion>` | |
> | | Sets the version of the documented library or resource. The default value for test libraries is [defined in the source code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#library-version). |
> | `-P, --pythonpath <path>` | |
> | | Additional locations where to search for libraries and resources similarly as when [running tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-pythonpath-option). |
> | `--quiet` | Do not print the path of the generated output file to the console. |
> | `-h, --help` | Prints this help. |
#### Executing Libdoc
The easiest way to run Libdoc is using the `libdoc` command created as part of the normal installation:
```
libdoc ExampleLibrary ExampleLibrary.html
```
Alternatively it is possible to execute the `robot.libdoc` module directly. This approach is especially useful if you have installed Robot Framework using multiple Python versions and want to use a specific version with Libdoc:
```
python -m robot.libdoc ExampleLibrary ExampleLibrary.html
python3.9 -m robot.libdoc ExampleLibrary ExampleLibrary.html
```
Yet another alternative is running the `robot.libdoc` module as a script:
```
python path/to/robot/libdoc.py ExampleLibrary ExampleLibrary.html
```
Note
The separate `libdoc` command is new in Robot Framework 4.0.
#### Specifying library or resource file
##### Python libraries and dynamic libraries with name or path
When documenting libraries implemented with Python or that use the [dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api), it is possible to specify the library either by using just the library name or path to the library source code:
```
libdoc ExampleLibrary ExampleLibrary.html
libdoc src/ExampleLibrary.py docs/ExampleLibrary.html
```
In the former case the library is searched using the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) and its name must be in the same format as when [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries) in Robot Framework test data.
If these libraries require arguments when they are imported, the arguments must be catenated with the library name or path using two colons like `MyLibrary::arg1::arg2`. If arguments change what keywords the library provides or otherwise alter its documentation, it might be a good idea to use \--name option to also change the library name accordingly.
##### Resource files with path
Resource files must always be specified using a path:
```
libdoc example.resource example.html
```
If the path does not exist, resource files are also searched from all directories in the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path) similarly as when executing test cases.
##### Libdoc spec files
Earlier generated Libdoc XML or JSON spec files can also be used as inputs. This works if spec files use either \*.xml, \*.libspec or \*.json extension:
```
libdoc Example.xml Example.html
libdoc Example.libspec Example.html
libdoc Example.json Example.html
```
Note
Support for the \*.libspec extension is new in Robot Framework 3.2.
Note
Support for the \*.json extension is new in Robot Framework 4.0.
#### Generating documentation
Libdoc can generate documentation in HTML (for humans) and XML or JSON (for tools) formats. The file where to write the documentation is specified as the second argument after the library/resource name or path, and the output format is got from the output file extension by default.
##### Libdoc HTML documentation
Most Robot Framework libraries use Libdoc to generate library documentation in HTML format. This format is thus familiar for most people who have used Robot Framework. A simple example can be seen below, and it has been generated based on the example found a [bit later in this section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries).
[](https://robotframework.org/robotframework/latest/images/ExampleLibrary.html)
The HTML documentation starts with general library introduction, continues with a section about configuring the library when it is imported (when applicable), and finally has shortcuts to all keywords and the keywords themselves. The magnifying glass icon on the lower right corner opens the keyword search dialog that can also be opened by simply pressing the `s` key.
Libdoc automatically creates HTML documentation if the output file extension is \*.html. If there is a need to use some other extension, the format can be specified explicitly with the \--format option.
Starting from Robot Framework 7.2, it is possible to localise the static texts in the HTML documentation by using the \--language option.
See the `README.rst` file in `src/web/libodc` directory in the project repository for up to date information about how to add new languages for the localisation.
```
libdoc OperatingSystem OperatingSystem.html
libdoc --name MyLibrary Remote::http://10.0.0.42:8270 MyLibrary.html
libdoc --format HTML test/resource.robot doc/resource.htm
```
##### Libdoc XML spec files
Libdoc can also generate documentation in XML format that is suitable for external tools such as editors. It contains all the same information as the HTML format but in a machine readable format.
XML spec files also contain library and keyword source information so that the library and each keyword can have source path (`source` attribute) and line number (`lineno` attribute). The source path is relative to the directory where the spec file is generated thus does not refer to a correct file if the spec is moved. The source path is omitted with keywords if it is the same as with the library, and both the source path and the line number are omitted if getting them from the library fails for whatever reason.
Libdoc automatically uses the XML format if the output file extension is \*.xml or \*.libspec. When using the special \*.libspec extension, Libdoc automatically enables the options `-f XML -s HTML` which means creating an XML output file where keyword documentation is converted to HTML. If needed, the format can be explicitly set with the \--format option.
```
libdoc OperatingSystem OperatingSystem.xml
libdoc test/resource.robot doc/resource.libspec
libdoc --format xml MyLibrary MyLibrary.spec
libdoc --format xml -s html MyLibrary MyLibrary.xml
```
The exact Libdoc spec file format is documented with an [XML schema](https://en.wikipedia.org/wiki/XML_Schema_\(W3C\)) (XSD) at <https://github.com/robotframework/robotframework/tree/master/doc/schema>. The spec file format may change between Robot Framework major releases.
To make it easier for external tools to know how to parse a certain spec file, the spec file root element has a dedicated `specversion` attribute. It was added in Robot Framework 3.2 with value `2` and earlier spec files can be considered to have version `1`. The spec version will be incremented in the future if and when changes are made. Robot Framework 4.0 introduced new spec version `3` which is incompatible with earlier versions.
Note
The `XML:HTML` format introduced in Robot Framework 3.2. has been replaced by the format `LIBSPEC` ot the option combination `--format XML --specdocformat HTML`.
Note
Including source information and spec version are new in Robot Framework 3.2.
##### Libdoc JSON spec files
Since Robot Framework 4.0 Libdoc can also generate documentation in JSON format that is suitable for external tools such as editors or web pages. It contains all the same information as the HTML format but in a machine readable format.
Similar to XML spec files the JSON spec files contain all information and can also be used as input to Libdoc. From that format any other output format can be created. By default the library documentation strings are converted to HTML format within the JSON output file.
The exact JSON spec file format is documented with an [JSON schema](https://json-schema.org/) at <https://github.com/robotframework/robotframework/tree/master/doc/schema>. The spec file format may change between Robot Framework major releases.
#### Viewing information on console
Libdoc has three special commands to show information on the console. These commands are used instead of the name of the output file, and they can also take additional arguments.
`list`
List names of the keywords the library/resource contains. Can be limited to show only certain keywords by passing optional patterns as arguments. Keyword is listed if its name contains given pattern.
`show`
Show library/resource documentation. Can be limited to show only certain keywords by passing names as arguments. Keyword is shown if its name matches any given name. Special argument `intro` will show only the library introduction and importing sections.
`version`
Show library version
Optional patterns given to `list` and `show` are case and space insensitive. Both also accept `*` and `?` as wildcards.
Examples:
```
libdoc Dialogs list
libdoc SeleniumLibrary list browser
libdoc Remote::10.0.0.42:8270 show
libdoc Dialogs show PauseExecution execute*
libdoc SeleniumLibrary show intro
libdoc SeleniumLibrary version
```
### [5\.1.2 Writing documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-624)
This section discusses writing documentation for [Python](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#python-libraries) based test libraries that use the static library API as well as for [dynamic libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-libraries) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-file-documentation). [Creating test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-test-libraries) and [resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) is described in more details elsewhere in the User Guide.
#### Python libraries
The documentation for Python libraries that use the [static library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-keywords) is written simply as doc strings for the library class or module and for methods implementing keywords. The first line of the method documentation is considered as a short documentation for the keyword (used, for example, as a tool tip in links in the generated HTML documentation), and it should thus be as describing as possible, but not too long.
The simple example below illustrates how to write the documentation in general. How the HTML documentation generated based on this example looks like can be seen [above](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-html-documentation), and there is also a [bit longer example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example) at the end of this chapter.
```
class ExampleLibrary:
"""Library for demo purposes.
This library is only used in an example and it doesn't do anything useful.
"""
def my_keyword(self):
"""Does nothing."""
pass
def your_keyword(self, arg):
"""Takes one argument and *does nothing* with it.
Examples:
| Your Keyword | xxx |
| Your Keyword | yyy |
"""
pass
```
Tip
If you library does some initialization work that should not be done when using Libdoc, you can [easily detect is Robot Framework running](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#detecting-is-robot-framework-running)
Tip
For more information on Python documentation strings, see [PEP-257](http://www.python.org/dev/peps/pep-0257).
#### Dynamic libraries
To be able to generate meaningful documentation for dynamic libraries, the libraries must return keyword argument names and documentation using `get_keyword_arguments` and `get_keyword_documentation` methods (or using their camelCase variants `getKeywordArguments` and `getKeywordDocumentation`). Libraries can also support general library documentation via special `__intro__` and `__init__` values to the `get_keyword_documentation` method.
See the [Dynamic library API](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dynamic-library-api) section for more information about how to create these methods.
#### Importing section
A separate section about how the library is imported is created based on its initialization methods. If the library has an `__init__` method that takes arguments in addition to `self`, its documentation and arguments are shown.
```
class TestLibrary:
def __init__(self, mode='default')
"""Creates new TestLibrary. `mode` argument is used to determine mode."""
self.mode = mode
def some_keyword(self, arg):
"""Does something based on given `arg`.
What is done depends on the `mode` specified when `importing` the library.
"""
if self.mode == 'secret':
# ...
```
#### Resource file documentation
Keywords in resource files can have documentation using \[Documentation\] setting, and this documentation is also used by Libdoc. First line of the documentation (until the first [implicit newline](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines) or explicit `\n`) is considered to be the short documentation similarly as with test libraries.
Also the resource file itself can have Documentation in the Setting section for documenting the whole resource file.
Possible variables in resource files can not be documented.
```
*** Settings ***
Documentation Resource file for demo purposes.
... This resource is only used in an example and it doesn't do anything useful.
*** Keywords ***
My Keyword
[Documentation] Does nothing
No Operation
Your Keyword
[Arguments] ${arg}
[Documentation] Takes one argument and *does nothing* with it.
...
... Examples:
... | Your Keyword | xxx |
... | Your Keyword | yyy |
No Operation
```
### [5\.1.3 Documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-625)
Libdoc supports documentation in Robot Framework's own [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1), HTML, plain text, and [reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText). The format to use can be specified in [library source code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-format) using `ROBOT_LIBRARY_DOC_FORMAT` attribute or given from the command line using \--docformat (-F) option. In both cases the possible case-insensitive values are `ROBOT` (default), `HTML`, `TEXT` and `reST`.
Robot Framework's own documentation format is the default and generally recommended format. Other formats are especially useful when using existing code with existing documentation in test libraries.
#### Robot Framework documentation syntax
Most important features in Robot Framework's [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1) are formatting using `*bold*` and `_italic_`, custom links and automatic conversion of URLs to links, and the possibility to create tables and pre-formatted text blocks (useful for examples) simply with pipe character. If documentation gets longer, support for section titles can also be handy.
Some of the most important formatting features are illustrated in the example below. Notice that since this is the default format, there is no need to use `ROBOT_LIBRARY_DOC_FORMAT` attribute nor give the format from the command line.
```
"""Example library in Robot Framework format.
- Formatting with *bold* and _italic_.
- URLs like http://example.com are turned to links.
- Custom links like [http://robotframework.org|Robot Framework] are supported.
- Linking to `My Keyword` works.
"""
def my_keyword():
"""Nothing more to see here."""
```
##### Creating table of contents automatically
With bigger libraries it is often useful to add a table of contents to the library introduction. When using the Robot Framework documentation format, this can be done automatically by adding a special `%TOC%` marker into a line on its own. The table of contents is created based on the top-level [section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles) (e.g. `= Section =`) used in the introduction. In addition to them, the TOC also gets links to the [automatically created sections](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-automatic-sections) for shortcuts and keywords as well as for importing and tags sections when applicable.
```
"""Example library demonstrating TOC generation.
The %TOC% marker only creates the actual table of contents and possible
header or other explanation needs to be added separately like done below.
== Table of contents ==
%TOC%
= Section title =
The top-level section titles are automatically added to the TOC.
= Second section =
== Sub section ==
Sub section titles are not added to the TOC.
"""
def my_keyword():
"""Nothing more to see here."""
```
Note
Automatic TOC generation is a new feature in Robot Framework 3.2.
#### HTML documentation syntax
When using HTML format, you can create documentation pretty much freely using any syntax. The main drawback is that HTML markup is not that human friendly, and that can make the documentation in the source code hard to maintain and read. Documentation in HTML format is used by Libdoc directly without any transformation or escaping. The special syntax for [linking to keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-keywords) using syntax like \`My Keyword\` is supported, however.
Example below contains the same formatting examples as the previous example. Now `ROBOT_LIBRARY_DOC_FORMAT` attribute must be used or format given on the command line like `--docformat HTML`.
```
"""Example library in HTML format.
<ul>
<li>Formatting with <b>bold</b> and <i>italic</i>.
<li>URLs are not turned to links automatically.
<li>Custom links like <a href="http://www.w3.org/html">HTML</a> are supported.
<li>Linking to `My Keyword` works.
</ul>
"""
ROBOT_LIBRARY_DOC_FORMAT = 'HTML'
def my_keyword():
"""Nothing more to see here."""
```
#### Plain text documentation syntax
When the plain text format is used, Libdoc uses the documentation as-is. Newlines and other whitespace are preserved except for indentation, and HTML special characters (`<>&`) escaped. The only formatting done is turning URLs into clickable links and supporting [internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking) like \`My Keyword\`.
```
"""Example library in plain text format.
- Formatting is not supported.
- URLs like http://example.com are turned to links.
- Custom links are not supported.
- Linking to `My Keyword` works.
"""
ROBOT_LIBRARY_DOC_FORMAT = 'text'
def my_keyword():
"""Nothing more to see here."""
```
#### reStructuredText documentation syntax
[reStructuredText](https://en.wikipedia.org/wiki/ReStructuredText) is simple yet powerful markup syntax used widely in Python projects (including this User Guide) and elsewhere. The main limitation is that you need to have the [docutils](https://pypi.python.org/pypi/docutils) module installed to be able to generate documentation using it. Because backtick characters have special meaning in reStructuredText, [linking to keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#linking-to-keywords) requires them to be escaped like \\\`My Keyword\\\`.
One of the nice features that reStructured supports is the ability to mark code blocks that can be syntax highlighted. Syntax highlight requires additional [Pygments](http://pygments.org/) module and supports all the languages that Pygments supports.
```
"""Example library in reStructuredText format.
- Formatting with **bold** and *italic*.
- URLs like http://example.com are turned to links.
- Custom links like reStructuredText__ are supported.
- Linking to \`My Keyword\` works but requires backtics to be escaped.
__ http://docutils.sourceforge.net
.. code:: robotframework
*** Test Cases ***
Example
My keyword # How cool is this!!?!!?!1!!
"""
ROBOT_LIBRARY_DOC_FORMAT = 'reST'
def my_keyword():
"""Nothing more to see here."""
```
### [5\.1.4 Internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-626)
Libdoc supports internal linking to keywords and different sections in the documentation. Linking is done by surrounding the target name with backtick characters like \`target\`. Target names are case-insensitive and possible targets are explained in the subsequent sections.
There is no error or warning if a link target is not found, but instead Libdoc just formats the text in italics. Earlier this formatting was recommended to be used when referring to keyword arguments, but that was problematic because it could accidentally create internal links. Nowadays it is recommended to use [inline code style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles) with double backticks like \``argument\`` instead. The old formatting of single backticks may even be removed in the future in favor of giving an error when a link target is not found.
In addition to the examples in the following sections, internal linking and argument formatting is shown also in the [longer example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#libdoc-example) at the end of this chapter.
#### Linking to keywords
All keywords the library have automatically create link targets and they can be linked using syntax \`Keyword Name\`. This is illustrated with the example below where both keywords have links to each others.
```
def keyword(log_level="INFO"):
"""Does something and logs the output using the given level.
Valid values for log level` are "INFO" (default) "DEBUG" and "TRACE".
See also `Another Keyword`.
"""
# ...
def another_keyword(argument, log_level="INFO"):
"""Does something with the given argument else and logs the output.
See `Keyword` for information about valid log levels.
"""
# ...
```
Note
When using [reStructuredText documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-documentation-syntax), backticks must be escaped like \\\`Keyword Name\\\`.
#### Linking to automatic sections
The documentation generated by Libdoc always contains sections for overall library introduction and for keywords. If a library itself takes arguments, there is also separate [importing section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-section). If any of the keywords has [tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-tags), a separate selector for them is also shown in the overview.
All the sections act as targets that can be linked, and the possible target names are listed in the table below. Using these targets is shown in the example of the next section.
| Section | Target |
|---|---|
| Introduction | \`introduction\` and \`library introduction\` |
| Importing | \`importing\` and \`library importing\` |
| Keywords | \`keywords\` |
Note
Before Robot Framework 4.0 there were also sections for tags and shortcuts. In Robot Framework 4.0 these have been removed in favor of the overview menu. This means that prior linking to shortcuts or tags sections does not work.
#### Linking to custom sections
Robot Framework's [documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-syntax-1) supports custom [section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles), and the titles used in the library or resource file introduction automatically create link targets. The example below illustrates linking both to automatic and custom sections:
```
"""Library for Libdoc demonstration purposes.
This library does not do anything useful.
= My section =
We do have a custom section in the documentation, though.
"""
def keyword():
"""Does nothing.
See `introduction` for more information and `My section` to test how
linking to custom sections works.
"""
pass
```
Note
Linking to custom sections works only when using [Robot Framework documentation syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-framework-documentation-syntax).
### [5\.1.5 Representing arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-627)
Libdoc shows information about keywords' arguments automatically.
#### Included information
The following information is shown for all keywords regardless are they implemented in libraries or in resource files:
- Argument name. User keyword arguments are shown without the `${}` decoration to make arguments look the same regardless where keywords originate from.
- Marker telling is the argument [positional-only](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#positional-only-arguments), [named-only](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-only-arguments), [free positional](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#varargs-library), [free named](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#kwargs-library), or [normal argument](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-arguments) that can be given either by position or by name.
- Possible default value. Shown like `= 42`.
- Possible type. Shown like `<int>`. Can be a link to type documentation as explained in the next section.
When referring to arguments in keyword documentation, it is recommended to use [inline code style](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles) like \``argument\``.
#### Automatically listing type documentation
As mentioned above, Libdoc automatically shows possible type information when listing arguments. If the type is a custom type based on [Enum](https://docs.python.org/library/enum.html#enum.Enum) or [TypedDict](https://docs.python.org/library/typing.html#typing.TypedDict), the type is [automatically converted](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions), or the type has [custom converter](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-argument-converters), also the type itself is listed separately to show more information about it. When these types are used in arguments, the type name also becomes a link to the type information.
All listed data types show possible type documentation as well as what argument types are supported. In addition to that, types based on `Enum` list available members and types based on `TypedDict` show the dictionary structure.
Note
Automatically listing types based on `Enum` and `TypedDict` is new in Robot Framework 4.0. Listing other types is new in Robot Framework 5.0.
### [5\.1.6 Libdoc example](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-628)
The following example illustrates how to use the most important [documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting) possibilities, [internal linking](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#internal-linking), and so on. [Click here](https://robotframework.org/robotframework/latest/images/LoggingLibrary.html) to see how the generated documentation looks like.
```
class LoggingLibrary:
"""Library for logging messages.
= Table of contents =
%TOC%
= Usage =
This library has several keyword, for example `Log Message`, for logging
messages. In reality the library is used only for _Libdoc_ demonstration
purposes.
= Valid log levels =
Valid log levels are ``INFO``, ``DEBUG``, and ``TRACE``. The default log
level can be set during `importing`.
= Examples =
Notice how keywords are linked from examples.
| `Log Message` | My message | | |
| `Log Two Messages` | My message | Second message | level=DEBUG |
| `Log Messages` | First message | Second message | Third message |
"""
ROBOT_LIBRARY_VERSION = '0.1'
def __init__(self, default_level='INFO'):
"""The default log level can be given at library import time.
See `Valid log levels` section for information about available log
levels.
Examples:
| =Setting= | =Value= | =Value= | =Comment= |
| Library | LoggingLibrary | | # Use default level (INFO) |
| Library | LoggingLibrary | DEBUG | # Use the given level |
"""
self.default_level = self._verify_level(default_level)
def _verify_level(self, level):
level = level.upper()
if level not in ['INFO', 'DEBUG', 'TRACE']:
raise RuntimeError("Invalid log level'%s'. Valid levels are "
"'INFO', 'DEBUG', and 'TRACE'")
return level
def log_message(self, message, level=None):
"""Writes given message to the log file using the specified log level.
The message to log and the log level to use are defined using
``message`` and ``level`` arguments, respectively.
If no log level is given, the default level given during `library
importing` is used.
"""
level = self._verify_level(level) if level else self.default_level
print("*%s* %s" % (level, message))
def log_two_messages(self, message1, message2, level=None):
"""Writes given messages to the log file using the specified log level.
See `Log Message` keyword for more information.
"""
self.log_message(message1, level)
self.log_message(message2, level)
def log_messages(self, *messages):
"""Logs given messages using the log level set during `importing`.
See also `Log Message` and `Log Two Messages`.
"""
for msg in messages:
self.log_message(msg)
```
All [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) have documentation generated by Libdoc and their documentation (and source code) act as a more realistic examples.
## [5\.2 Test data documentation tool (Testdoc)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-620)
- [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#general-usage-1)
- [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-documentation-1)
Testdoc is Robot Framework's built-in tool for generating high level documentation based on test cases. The created documentation is in HTML format and it includes name, documentation and other metadata of each test suite and test case, as well as the top-level keywords and their arguments.
Note
The built-in Testdoc tool is deprecated and will be removed in Robot Framework 8.0. Use the new and enhanced [external Testdoc](https://github.com/MarvKler/robotframework-testdoc) instead.
### [5\.2.1 General usage](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-629)
#### Synopsis
```
python -m robot.testdoc [options] data_sources output_file
```
#### Options
> | | |
> |---|---|
> | `-T, --title <title>` | |
> | | Set the title of the generated documentation. Underscores in the title are converted to spaces. The default title is the name of the top level suite. |
> | `-N, --name <name>` | |
> | | Override the name of the top level test suite. |
> | `-D, --doc <doc>` | |
> | | Override the documentation of the top level test suite. |
> | `-M, --metadata <name:value>` | |
> | | Set/override free metadata of the top level test suite. |
> | `-G, --settag <tag>` | |
> | | Set given tag(s) to all test cases. |
> | `-t, --test <name>` | |
> | | Include tests by name. |
> | `-s, --suite <name>` | |
> | | Include suites by name. |
> | `-i, --include <tag>` | |
> | | Include tests by tags. |
> | `-e, --exclude <tag>` | |
> | | Exclude tests by tags. |
> | `-A, --argumentfile <path>` | |
> | | Text file to read more arguments from. Works exactly like [argument files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) when running tests. |
> | `-h, --help` | Print this help in the console. |
All options except \--title have exactly the same semantics as same options have when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-execution).
### [5\.2.2 Generating documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-630)
Data can be given as a single file, directory, or as multiple files and directories. In all these cases, the last argument must be the file where to write the output.
Testdoc can be executed as an installed module like `python -m robot.testdoc` or as a script like `python path/robot/testdoc.py`.
Examples:
```
python -m robot.testdoc my_test.robot testdoc.html
python path/to/robot/testdoc.py --name "Smoke tests" --include smoke path/to/tests smoke.html
```
## [5\.3 Test data clean-up tool (Tidy)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-621)
The built-in Tidy tool was deprecated in Robot Framework 4.1 in favor of the new and enhanced external [Robotidy](https://robotidy.readthedocs.io/) tool. It was removed altogether in Robot Framework 5.0.
## [5\.4 External tools](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-622)
There are plenty of external tools that can be used with Robot Framework. These tools include plugins for various IDEs and text editors, tools for parallel execution and data-driven testing, plugins for continuous integration systems, and so on.
These tools are developed as separate projects independently from Robot Framework itself. For a list of the available tools see <http://robotframework.org/>.
## [6 Appendices](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-166)
- [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings)
- [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options)
- [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations)
- [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documentation-formatting)
- [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-format)
- [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#boolean-arguments)
- [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluating-expressions)
- [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#registrations)
## [6\.1 Available settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-631)
This appendix lists all settings that can be used in different sections.
Note
Settings can be [localized](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). See the [Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations) appendix for supported translations.
- [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-section-1)
- [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-section)
- [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#keyword-section-1)
### [6\.1.1 Setting section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-639)
The Setting section is used to import 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 section can only include settings for importing libraries, resources, and variables.
| Name | Description |
|---|---|
| Library | Used for [importing libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#importing-libraries). |
| Resource | Used for [taking resource files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-resource-files-into-use). |
| Variables | Used for [taking variable files into use](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#taking-variable-files-into-use). |
| Name | Used for setting a custom [suite name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-name). |
| Documentation | Used for specifying a [suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation) or [resource file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-resource-files) documentation. |
| Metadata | Used for setting [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata). |
| Suite Setup | Used for specifying the [suite setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). |
| Suite Teardown | Used for specifying the [suite teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-setup-and-teardown). |
| Test Tags | Used for specifying [test case tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-tags) for all tests in a suite. |
| Force Tags, Default Tags | [Deprecated settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#deprecation-of-force-tags-and-default-tags) for specifying test case tags. |
| Keyword Tags | Used for specifying [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags) for all keywords in a certain file. |
| Test Setup | Used for specifying a default [test setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| Test Teardown | Used for specifying a default [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| Test Template | Used for specifying a default [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates) for test cases. |
| Test Timeout | Used for specifying a default [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). |
| Task Setup, Task Teardown, Task Template, Task Timeout | Aliases for Test Setup, Test Teardown, Test Template and Test Timeout, respectively, that can be used when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks). |
### [6\.1.2 Test Case section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-640)
The settings in the Test Case section are always specific to the test case for which they are defined. Some of these settings override the default values defined in the Settings section.
Exactly same settings are available when [creating tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-tasks) in the Task section.
| Name | Description |
|---|---|
| \[Documentation\] | Used for specifying a [test case documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation). |
| \[Tags\] | Used for [tagging test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tagging-test-cases). |
| \[Setup\] | Used for specifying a [test setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| \[Teardown\] | Used for specifying a [test teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-setup-and-teardown). |
| \[Template\] | Used for specifying a [template keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates). |
| \[Timeout\] | Used for specifying a [test case timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-timeout). |
### [6\.1.3 Keyword section](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-641)
Settings in the Keyword section are specific to the user keyword for which they are defined.
| Name | Description |
|---|---|
| \[Documentation\] | Used for specifying a [user keyword documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation). |
| \[Tags\] | Used for specifying [user keyword tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-tags). |
| \[Arguments\] | Used for specifying [user keyword arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-arguments). |
| \[Setup\] | Used for specifying a [user keyword setup](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-setup). New in Robot Framework 7.0. |
| \[Teardown\] | Used for specifying [user keyword teardown](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-teardown). |
| \[Timeout\] | Used for specifying a [user keyword timeout](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-timeout). |
| \[Return\] | Used for specifying [user keyword return values](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-return-values). Deprecated in Robot Framework 7.0. Use the [RETURN](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return) statement instead. |
## [6\.2 Command line options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-632)
This appendix lists all the command line options that are available when [executing test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-test-cases-1) and when [post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#post-processing-outputs). Also environment variables affecting execution and post-processing are listed.
- [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-test-execution)
- [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-options-for-post-processing-outputs)
- [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#environment-variables-for-execution-and-post-processing)
### [6\.2.1 Command line options for test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-642)
> | | |
> |---|---|
> | `--rpa` | Turn on [generic automation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) mode. |
> | `--language <lang>` | |
> | | Activate [localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization). `lang` can be a name or a code of a [built-in language](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#translations), or a path or a module name of a custom language file. |
> | `-F, --extension <value>` | |
> | | [Parse only these files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) when executing a directory. |
> | `-I, --parseinclude <pattern>` | |
> | | [Parse only matching files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse) when executing a directory. |
> | `-N, --name <name>` | |
> | | [Sets the name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) of the top-level test suite. |
> | `-D, --doc <document>` | |
> | | [Sets the documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) of the top-level test suite. |
> | `-M, --metadata <name:value>` | |
> | | [Sets free metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata) for the top level test suite. |
> | `-G, --settag <tag>` | |
> | | [Sets the tag(s)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags) to all executed test cases. |
> | `-t, --test <name>` | |
> | | [Selects the test cases by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names). |
> | `--task <name>` | Alias for \--test that can be used when [executing tasks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#executing-tasks). |
> | `-s, --suite <name>` | |
> | | [Selects the test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) by name. |
> | `-R, --rerunfailed <file>` | |
> | | [Selects failed tests](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-cases) from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) to be re-executed. |
> | `-S, --rerunfailedsuites <file>` | |
> | | [Selects failed test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#re-executing-failed-test-suites) from an earlier [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) to be re-executed. |
> | `-i, --include <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-e, --exclude <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `--skip <tag>` | Tests having given tag will be [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped). Tag can be a pattern. |
> | `--skiponfailure <tag>` | |
> | | Tests having given tag will be [skipped](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#skipped) if they fail. |
> | `-v, --variable <name:value>` | |
> | | Sets [individual variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#command-line-variables). |
> | `-V, --variablefile <path:args>` | |
> | | Sets variables using [variable files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#variable-files). |
> | `-d, --outputdir <dir>` | |
> | | Defines where to [create output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory). |
> | `-o, --output <file>` | |
> | | Sets the path to the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file). |
> | `--legacyoutput` | Creates output file in [Robot Framework 6.x compatible format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#legacy-xml-format). |
> | `-l, --log <file>` | |
> | | Sets the path to the generated [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). |
> | `-r, --report <file>` | |
> | | Sets the path to the generated [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file). |
> | `-x, --xunit <file>` | |
> | | Sets the path to the generated [xUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file). |
> | `-b, --debugfile <file>` | |
> | | A [debug file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debug-file) that is written during execution. |
> | `-T, --timestampoutputs` | |
> | | [Adds a timestamp](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files) to [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) listed above. |
> | `--splitlog` | [Split log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs) into smaller pieces that open in browser transparently. |
> | `--logtitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test log. |
> | `--reporttitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test report. |
> | `--reportbackground <colors>` | |
> | | [Sets background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors) of the generated report. |
> | `--maxerrorlines <lines>` | |
> | | Sets the number of [error lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-error-message-length-in-reports) shown in report when tests fail. |
> | `--maxassignlength <characters>` | |
> | | Sets the number of characters shown in log when [variables are assigned](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-logging-assigned-variable-value). |
> | `-L, --loglevel <level>` | |
> | | [Sets the threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level) for logging. Optionally the default [visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level) can be given separated with a colon (:). |
> | `--suitestatlevel <level>` | |
> | | Defines how many [levels to show](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics) in the *Statistics by Suite* table in outputs. |
> | `--tagstatinclude <tag>` | |
> | | [Includes only these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) in the *Statistics by Tag* table. |
> | `--tagstatexclude <tag>` | |
> | | [Excludes these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) from the *Statistics by Tag* table. |
> | `--tagstatcombine <tags:title>` | |
> | | Creates [combined statistics based on tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics). |
> | `--tagdoc <pattern:doc>` | |
> | | Adds [documentation to the specified tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags). |
> | `--tagstatlink <pattern:link:title>` | |
> | | Adds [external links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names) to the *Statistics by Tag* table. |
> | `--expandkeywords <name:pattern|tag:pattern>` | |
> | | Automatically [expand keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords) in the generated log file. |
> | `--removekeywords <all|passed|name:pattern|tag:pattern|for|while|wuks>` | |
> | | [Removes keyword data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) from the generated log file. |
> | `--flattenkeywords <for|while|iteration|name:pattern|tag:pattern>` | |
> | | [Flattens keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) in the generated log file. |
> | `--listener <name:args>` | |
> | | [Sets a listener](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-listeners) for monitoring test execution. |
> | `--nostatusrc` | Sets the [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) to zero regardless of failures in test cases. Error codes are returned normally. |
> | `--runemptysuite` | |
> | | Executes tests also if the selected [test suites are empty](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). |
> | `--dryrun` | In the [dry run](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dry-run) mode tests are run without executing keywords originating from test libraries. Useful for validating test data syntax. |
> | `-X, --exitonfailure` | |
> | | [Stops test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-when-first-test-case-fails) if any test fails. |
> | `--exitonerror` | [Stops test execution](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#stopping-on-parsing-or-execution-error) if any error occurs when parsing test data, importing libraries, and so on. |
> | `--skipteardownonexit` | |
> | | [Skips teardowns](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-teardowns) if test execution is prematurely stopped. |
> | `--prerunmodifier <name:args>` | |
> | | Activate [programmatic modification of test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-test-data). |
> | `--prerebotmodifier <name:args>` | |
> | | Activate [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results). |
> | `--randomize <all|suites|tests|none>` | |
> | | [Randomizes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#randomizing-execution-order) test execution order. |
> | `--console <verbose|dotted|quiet|none>` | |
> | | [Console output type](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-output-type). |
> | `--dotted` | Shortcut for `--console dotted`. |
> | `--quiet` | Shortcut for `--console quiet`. |
> | `-W, --consolewidth <width>` | |
> | | [Sets the width](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-width) of the console output. |
> | `-C, --consolecolors <auto|on|ansi|off>` | |
> | | [Specifies are colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) used on the console. |
> | `--consolelinks <auto|off>` | |
> | | Controls [making paths to results files hyperlinks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links). |
> | `-K, --consolemarkers <auto|on|off>` | |
> | | Show [markers on the console](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-markers) when top level keywords in a test case end. |
> | `-P, --pythonpath <path>` | |
> | | Additional locations to add to the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). |
> | `-A, --argumentfile <path>` | |
> | | A text file to [read more arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) from. |
> | `-h, --help` | Prints [usage instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
> | `--version` | Prints the [version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
### [6\.2.2 Command line options for post-processing outputs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-643)
> | | |
> |---|---|
> | `--rpa` | Turn on [generic automation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#task-execution) mode. |
> | `-R, --merge` | Changes result combining behavior to [merging](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#merging-outputs). |
> | `-N, --name <name>` | |
> | | [Sets the name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-name) of the top level test suite. |
> | `-D, --doc <document>` | |
> | | [Sets the documentation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-suite-documentation) of the top-level test suite. |
> | `-M, --metadata <name:value>` | |
> | | [Sets free metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-free-suite-metadata) for the top-level test suite. |
> | `-G, --settag <tag>` | |
> | | [Sets the tag(s)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-test-tags) to all processed test cases. |
> | `-t, --test <name>` | |
> | | [Selects the test cases by name](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-test-names). |
> | `--task <name>` | Alias for \--test. |
> | `-s, --suite <name>` | |
> | | [Selects the test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-suite-names) by name. |
> | `-i, --include <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-e, --exclude <tag>` | |
> | | [Selects the test cases](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#by-tag-names) by tag. |
> | `-d, --outputdir <dir>` | |
> | | Defines where to [create output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-directory). |
> | `-o, --output <file>` | |
> | | Sets the path to the generated [output file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file). |
> | `--legacyoutput` | Creates output file in [Robot Framework 6.x compatible format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#legacy-xml-format). |
> | `-l, --log <file>` | |
> | | Sets the path to the generated [log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#log-file). |
> | `-r, --report <file>` | |
> | | Sets the path to the generated [report file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#report-file). |
> | `-x, --xunit <file>` | |
> | | Sets the path to the generated [xUnit compatible result file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#xunit-compatible-result-file). |
> | `-T, --timestampoutputs` | |
> | | [Adds a timestamp](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timestamping-output-files) to [output files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#output-file) listed above. |
> | `--splitlog` | [Split log file](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#splitting-logs) into smaller pieces that open in browser transparently. |
> | `--logtitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test log. |
> | `--reporttitle <title>` | |
> | | [Sets a title](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-titles) for the generated test report. |
> | `--reportbackground <colors>` | |
> | | [Sets background colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-background-colors) of the generated report. |
> | `-L, --loglevel <level>` | |
> | | [Sets the threshold level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-log-level) to select log messages. Optionally the default [visible log level](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#visible-log-level) can be given separated with a colon (:). |
> | `--suitestatlevel <level>` | |
> | | Defines how many [levels to show](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#configuring-displayed-suite-statistics) in the *Statistics by Suite* table in outputs. |
> | `--tagstatinclude <tag>` | |
> | | [Includes only these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) in the *Statistics by Tag* table. |
> | `--tagstatexclude <tag>` | |
> | | [Excludes these tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#including-and-excluding-tag-statistics) from the *Statistics by Tag* table. |
> | `--tagstatcombine <tags:title>` | |
> | | Creates [combined statistics based on tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#generating-combined-tag-statistics). |
> | `--tagdoc <pattern:doc>` | |
> | | Adds [documentation to the specified tags](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#adding-documentation-to-tags). |
> | `--tagstatlink <pattern:link:title>` | |
> | | Adds [external links](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#creating-links-from-tag-names) to the *Statistics by Tag* table. |
> | `--expandkeywords <name:pattern|tag:pattern>` | |
> | | Automatically [expand keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#automatically-expanding-keywords) in the generated log file. |
> | `--removekeywords <all|passed|name:pattern|tag:pattern|for|wuks>` | |
> | | [Removes keyword data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) from the generated outputs. |
> | `--flattenkeywords <for|foritem|name:pattern|tag:pattern>` | |
> | | [Flattens keywords](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#removing-and-flattening-keywords) in the generated outputs. |
> | `--starttime <timestamp>` | |
> | | Sets the [starting time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution) of test execution when creating reports. |
> | `--endtime <timestamp>` | |
> | | Sets the [ending time](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#setting-start-and-end-time-of-execution) of test execution when creating reports. |
> | `--nostatusrc` | Sets the [return code](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#return-codes) to zero regardless of failures in test cases. Error codes are returned normally. |
> | `--processemptysuite` | |
> | | Processes output files even if files contain [empty test suites](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#when-no-tests-match-selection). |
> | `--prerebotmodifier <name:args>` | |
> | | Activate [programmatic modification of results](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#programmatic-modification-of-results). |
> | `-C, --consolecolors <auto|on|ansi|off>` | |
> | | [Specifies are colors](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-colors) used on the console. |
> | `--consolelinks <auto|off>` | |
> | | Controls [making paths to results files hyperlinks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#console-links). |
> | `-P, --pythonpath <path>` | |
> | | Additional locations to add to the [module search path](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#module-search-path). |
> | `-A, --argumentfile <path>` | |
> | | A text file to [read more arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#argument-files) from. |
> | `-h, --help` | Prints [usage instructions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
> | `--version` | Prints the [version information](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#getting-help-and-version-information). |
### [6\.2.3 Environment variables for execution and post-processing](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-644)
ROBOT\_OPTIONS
and
REBOT\_OPTIONS
Space separated list of default options to be placed [in front of any explicit options](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#robot-options-and-rebot-options-environment-variables) on the command line.
ROBOT\_SYSLOG\_FILE
Path to a [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) file where Robot Framework writes internal information about parsing test case files and running tests.
ROBOT\_SYSLOG\_LEVEL
Log level to use when writing to the [syslog](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#system-log) file.
ROBOT\_INTERNAL\_TRACES
When set to any non-empty value, Robot Framework's internal methods are included in [error tracebacks](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#debugging-problems).
## [6\.3 Translations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-633)
Robot Framework supports translating [section headers](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-data-sections), [settings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#available-settings), [Given/When/Then prefixes](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#behavior-driven-style) used in Behavior Driven Development (BDD) as well as [true and false strings](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#supported-conversions) used in automatic Boolean argument conversion. This appendix lists all translations for all languages, excluding English, that Robot Framework supports out-of-the-box.
How to actually activate translations is explained in the [Localization](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#localization) section. That section also explains how to create custom language definitions and how to contribute new translations.
- [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#arabic-ar)
- [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bulgarian-bg)
- [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#bosnian-bs)
- [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#czech-cs)
- [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#german-de)
- [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spanish-es)
- [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#finnish-fi)
- [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#french-fr)
- [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#hindi-hi)
- [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#italian-it)
- [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#japanese-ja)
- [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#korean-ko)
- [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dutch-nl)
- [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#polish-pl)
- [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#portuguese-pt)
- [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#brazilian-portuguese-pt-br)
- [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#romanian-ro)
- [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#russian-ru)
- [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#swedish-sv)
- [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#thai-th)
- [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#turkish-tr)
- [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#ukrainian-uk)
- [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#vietnamese-vi)
- [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-simplified-zh-cn)
- [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#chinese-traditional-zh-tw)
### [6\.3.1 Arabic (ar)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-645)
New in Robot Framework 7.3.
#### Settings
| Setting | Translation |
|---|---|
| Library | المكتبة |
| Resource | المورد |
| Variables | المتغيرات |
| Name | الاسم |
| Documentation | التوثيق |
| Metadata | البيانات الوصفية |
| Suite Setup | إعداد المجموعة |
| Suite Teardown | تفكيك المجموعة |
| Test Setup | تهيئة الاختبار |
| Task Setup | تهيئة المهمة |
| Test Teardown | تفكيك الاختبار |
| Task Teardown | تفكيك المهمة |
| Test Template | قالب الاختبار |
| Task Template | قالب المهمة |
| Test Timeout | مهلة الاختبار |
| Task Timeout | مهلة المهمة |
| Test Tags | علامات الاختبار |
| Task Tags | علامات المهمة |
| Keyword Tags | علامات الأوامر |
| Tags | العلامات |
| Setup | إعداد |
| Teardown | تفكيك |
| Template | قالب |
| Timeout | المهلة الزمنية |
| Arguments | المعطيات |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | بافتراض |
| When | عندما, لما |
| Then | إذن, عندها |
| And | و |
| But | لكن |
#### Boolean strings
| True/False | Values |
|---|---|
| True | نعم, صحيح |
| False | لا, خطأ |
### [6\.3.2 Bulgarian (bg)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-646)
#### Settings
| Setting | Translation |
|---|---|
| Library | Библиотека |
| Resource | Ресурс |
| Variables | Променлива |
| Name | |
| Documentation | Документация |
| Metadata | Метаданни |
| Suite Setup | Първоначални настройки на комплекта |
| Suite Teardown | Приключване на комплекта |
| Test Setup | Първоначални настройки на тестове |
| Task Setup | Първоначални настройки на задачи |
| Test Teardown | Приключване на тестове |
| Task Teardown | Приключване на задачи |
| Test Template | Шаблон за тестове |
| Task Template | Шаблон за задачи |
| Test Timeout | Таймаут за тестове |
| Task Timeout | Таймаут за задачи |
| Test Tags | Етикети за тестове |
| Task Tags | Етикети за задачи |
| Keyword Tags | Етикети за ключови думи |
| Tags | Етикети |
| Setup | Първоначални настройки |
| Teardown | Приключване |
| Template | Шаблон |
| Timeout | Таймаут |
| Arguments | Аргументи |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | В случай че |
| When | Когато |
| Then | Тогава |
| And | И |
| But | Но |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Вярно, Да, Включен |
| False | Невярно, Не, Изключен, Нищо |
### [6\.3.3 Bosnian (bs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-647)
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteka |
| Resource | Resursi |
| Variables | Varijable |
| Name | |
| Documentation | Dokumentacija |
| Metadata | Metadata |
| Suite Setup | Suite Postavke |
| Suite Teardown | Suite Teardown |
| Test Setup | Test Postavke |
| Task Setup | Task Postavke |
| Test Teardown | Test Teardown |
| Task Teardown | Task Teardown |
| Test Template | Test Template |
| Task Template | Task Template |
| Test Timeout | Test Timeout |
| Task Timeout | Task Timeout |
| Test Tags | Test Tagovi |
| Task Tags | Task Tagovi |
| Keyword Tags | Keyword Tagovi |
| Tags | Tagovi |
| Setup | Postavke |
| Teardown | Teardown |
| Template | Template |
| Timeout | Timeout |
| Arguments | Argumenti |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Uslovno |
| When | Kada |
| Then | Tada |
| And | I |
| But | Ali |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.4 Czech (cs)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-648)
#### Settings
| Setting | Translation |
|---|---|
| Library | Knihovna |
| Resource | Zdroj |
| Variables | Proměnná |
| Name | Název |
| Documentation | Dokumentace |
| Metadata | Metadata |
| Suite Setup | Příprava sady |
| Suite Teardown | Ukončení sady |
| Test Setup | Příprava testu |
| Task Setup | Příprava úlohy |
| Test Teardown | Ukončení testu |
| Task Teardown | Ukončení úlohy |
| Test Template | Šablona testu |
| Task Template | Šablona úlohy |
| Test Timeout | Časový limit testu |
| Task Timeout | Časový limit úlohy |
| Test Tags | Štítky testů |
| Task Tags | Štítky úloh |
| Keyword Tags | Štítky klíčových slov |
| Tags | Štítky |
| Setup | Příprava |
| Teardown | Ukončení |
| Template | Šablona |
| Timeout | Časový limit |
| Arguments | Argumenty |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Pokud |
| When | Když |
| Then | Pak |
| And | A |
| But | Ale |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Pravda, Ano, Zapnuto |
| False | Nepravda, Ne, Vypnuto, Nic |
### [6\.3.5 German (de)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-649)
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliothek |
| Resource | Ressource |
| Variables | Variablen |
| Name | Name |
| Documentation | Dokumentation |
| Metadata | Metadaten |
| Suite Setup | Suitevorbereitung |
| Suite Teardown | Suitenachbereitung |
| Test Setup | Testvorbereitung |
| Task Setup | Aufgabenvorbereitung |
| Test Teardown | Testnachbereitung |
| Task Teardown | Aufgabennachbereitung |
| Test Template | Testvorlage |
| Task Template | Aufgabenvorlage |
| Test Timeout | Testzeitlimit |
| Task Timeout | Aufgabenzeitlimit |
| Test Tags | Testmarker |
| Task Tags | Aufgabenmarker |
| Keyword Tags | Schlüsselwortmarker |
| Tags | Marker |
| Setup | Vorbereitung |
| Teardown | Nachbereitung |
| Template | Vorlage |
| Timeout | Zeitlimit |
| Arguments | Argumente |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Angenommen |
| When | Wenn |
| Then | Dann |
| And | Und |
| But | Aber |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Wahr, Ja, An, Ein |
| False | Falsch, Nein, Aus, Unwahr |
### [6\.3.6 Spanish (es)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-650)
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recursos |
| Variables | Variable |
| Name | Nombre |
| Documentation | Documentación |
| Metadata | Metadatos |
| Suite Setup | Configuración de la Suite |
| Suite Teardown | Desmontaje de la Suite |
| Test Setup | Configuración de prueba |
| Task Setup | Configuración de tarea |
| Test Teardown | Desmontaje de la prueba |
| Task Teardown | Desmontaje de tareas |
| Test Template | Plantilla de prueba |
| Task Template | Plantilla de tareas |
| Test Timeout | Tiempo de espera de la prueba |
| Task Timeout | Tiempo de espera de las tareas |
| Test Tags | Etiquetas de la prueba |
| Task Tags | Etiquetas de las tareas |
| Keyword Tags | Etiquetas de palabras clave |
| Tags | Etiquetas |
| Setup | Configuración |
| Teardown | Desmontaje |
| Template | Plantilla |
| Timeout | Tiempo agotado |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Cuando |
| Then | Entonces |
| And | Y |
| But | Pero |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadero, Si, On |
| False | Falso, No, Off, Ninguno |
### [6\.3.7 Finnish (fi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-651)
#### Settings
| Setting | Translation |
|---|---|
| Library | Kirjasto |
| Resource | Resurssi |
| Variables | Muuttujat |
| Name | Nimi |
| Documentation | Dokumentaatio |
| Metadata | Metatiedot |
| Suite Setup | Setin Alustus |
| Suite Teardown | Setin Alasajo |
| Test Setup | Testin Alustus |
| Task Setup | Tehtävän Alustus |
| Test Teardown | Testin Alasajo |
| Task Teardown | Tehtävän Alasajo |
| Test Template | Testin Malli |
| Task Template | Tehtävän Malli |
| Test Timeout | Testin Aikaraja |
| Task Timeout | Tehtävän Aikaraja |
| Test Tags | Testin Tagit |
| Task Tags | Tehtävän Tagit |
| Keyword Tags | Avainsanan Tagit |
| Tags | Tagit |
| Setup | Alustus |
| Teardown | Alasajo |
| Template | Malli |
| Timeout | Aikaraja |
| Arguments | Argumentit |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Oletetaan |
| When | Kun |
| Then | Niin |
| And | Ja |
| But | Mutta |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Tosi, Kyllä, Päällä |
| False | Epätosi, Ei, Pois |
### [6\.3.8 French (fr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-652)
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliothèque |
| Resource | Ressource |
| Variables | Variable |
| Name | Nom |
| Documentation | Documentation |
| Metadata | Méta-donnée |
| Suite Setup | Mise en place de suite |
| Suite Teardown | Démontage de suite |
| Test Setup | Mise en place de test |
| Task Setup | Mise en place de tâche |
| Test Teardown | Démontage de test |
| Task Teardown | Démontage de test |
| Test Template | Modèle de test |
| Task Template | Modèle de tâche |
| Test Timeout | Délai de test |
| Task Timeout | Délai de tâche |
| Test Tags | Étiquette de test |
| Task Tags | Étiquette de tâche |
| Keyword Tags | Etiquette de mot-clé |
| Tags | Étiquette |
| Setup | Mise en place |
| Teardown | Démontage |
| Template | Modèle |
| Timeout | Délai d'attente |
| Arguments | Arguments |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Étant donné, Étant donné que, Étant donné qu', Soit, Sachant que, Sachant qu', Sachant, Etant donné, Etant donné que, Etant donné qu', Etant donnée, Etant données |
| When | Lorsque, Quand, Lorsqu' |
| Then | Alors, Donc |
| And | Et, Et que, Et qu' |
| But | Mais, Mais que, Mais qu' |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Vrai, Oui, Actif |
| False | Faux, Non, Désactivé, Aucun |
### [6\.3.9 Hindi (hi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-653)
#### Settings
| Setting | Translation |
|---|---|
| Library | कोड़ प्रतिबिंब संग्रह |
| Resource | संसाधन |
| Variables | चर |
| Name | |
| Documentation | प्रलेखन |
| Metadata | अधि-आंकड़ा |
| Suite Setup | जांच की शुरुवात |
| Suite Teardown | परीक्षण कार्य अंत |
| Test Setup | परीक्षण कार्य प्रारंभ |
| Task Setup | परीक्षण कार्य प्रारंभ |
| Test Teardown | परीक्षण कार्य अंत |
| Task Teardown | परीक्षण कार्य अंत |
| Test Template | परीक्षण ढांचा |
| Task Template | परीक्षण ढांचा |
| Test Timeout | परीक्षण कार्य समय समाप्त |
| Task Timeout | कार्य समयबाह्य |
| Test Tags | जाँचका उपनाम |
| Task Tags | कार्यका उपनाम |
| Keyword Tags | कुंजीशब्द का उपनाम |
| Tags | निशान |
| Setup | व्यवस्थापना |
| Teardown | विमोचन |
| Template | साँचा |
| Timeout | समय समाप्त |
| Arguments | प्राचल |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | दिया हुआ |
| When | जब |
| Then | तब |
| And | और |
| But | परंतु |
#### Boolean strings
| True/False | Values |
|---|---|
| True | यथार्थ, निश्चित, हां, पर |
| False | गलत, नहीं, हालाँकि, यद्यपि, नहीं, हैं |
### [6\.3.10 Italian (it)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-654)
#### Settings
| Setting | Translation |
|---|---|
| Library | Libreria |
| Resource | Risorsa |
| Variables | Variabile |
| Name | Nome |
| Documentation | Documentazione |
| Metadata | Metadati |
| Suite Setup | Configurazione Suite |
| Suite Teardown | Distruzione Suite |
| Test Setup | Configurazione Test |
| Task Setup | Configurazione Attività |
| Test Teardown | Distruzione Test |
| Task Teardown | Distruzione Attività |
| Test Template | Modello Test |
| Task Template | Modello Attività |
| Test Timeout | Timeout Test |
| Task Timeout | Timeout Attività |
| Test Tags | Tag Del Test |
| Task Tags | Tag Attività |
| Keyword Tags | Tag Parola Chiave |
| Tags | Tag |
| Setup | Configurazione |
| Teardown | Distruzione |
| Template | Template |
| Timeout | Timeout |
| Arguments | Parametri |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dato |
| When | Quando |
| Then | Allora |
| And | E |
| But | Ma |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Vero, Sì, On |
| False | Falso, No, Off, Nessuno |
### [6\.3.11 Japanese (ja)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-655)
New in Robot Framework 7.0.1.
#### Settings
| Setting | Translation |
|---|---|
| Library | ライブラリ |
| Resource | リソース |
| Variables | 変数 |
| Name | 名前 |
| Documentation | ドキュメント |
| Metadata | メタデータ |
| Suite Setup | スイート セットアップ |
| Suite Teardown | スイート ティアダウン |
| Test Setup | テスト セットアップ |
| Task Setup | タスク セットアップ |
| Test Teardown | テスト ティアダウン |
| Task Teardown | タスク ティアダウン |
| Test Template | テスト テンプレート |
| Task Template | タスク テンプレート |
| Test Timeout | テスト タイムアウト |
| Task Timeout | タスク タイムアウト |
| Test Tags | テスト タグ |
| Task Tags | タスク タグ |
| Keyword Tags | キーワード タグ |
| Tags | タグ |
| Setup | セットアップ |
| Teardown | ティアダウン |
| Template | テンプレート |
| Timeout | タイムアウト |
| Arguments | 引数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 仮定, 指定, 前提条件 |
| When | 条件, 次の場合, もし, 実行条件 |
| Then | アクション, その時, 動作 |
| And | および, 及び, かつ, 且つ, ならびに, 並びに, そして, それから |
| But | ただし, 但し |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 有効, はい, オン |
| False | 偽, 無効, いいえ, オフ |
### [6\.3.12 Korean (ko)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-656)
New in Robot Framework 7.1.
#### Settings
| Setting | Translation |
|---|---|
| Library | 라이브러리 |
| Resource | 자료 |
| Variables | 변수 |
| Name | 이름 |
| Documentation | 문서 |
| Metadata | 메타데이터 |
| Suite Setup | 스위트 설정 |
| Suite Teardown | 스위트 중단 |
| Test Setup | 테스트 설정 |
| Task Setup | 작업 설정 |
| Test Teardown | 테스트 중단 |
| Task Teardown | 작업 중단 |
| Test Template | 테스트 템플릿 |
| Task Template | 작업 템플릿 |
| Test Timeout | 테스트 시간 초과 |
| Task Timeout | 작업 시간 초과 |
| Test Tags | 테스트 태그 |
| Task Tags | 작업 태그 |
| Keyword Tags | 키워드 태그 |
| Tags | 태그 |
| Setup | 설정 |
| Teardown | 중단 |
| Template | 템플릿 |
| Timeout | 시간 초과 |
| Arguments | 주장 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 주어진 |
| When | 때 |
| Then | 보다 |
| And | 그리고 |
| But | 하지만 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 참, 네, 켜기 |
| False | 거짓, 아니오, 끄기 |
### [6\.3.13 Dutch (nl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-657)
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliotheek |
| Resource | Resource |
| Variables | Variabele |
| Name | Naam |
| Documentation | Documentatie |
| Metadata | Metadata |
| Suite Setup | Suitevoorbereiding |
| Suite Teardown | Suite-afronding |
| Test Setup | Testvoorbereiding |
| Task Setup | Taakvoorbereiding |
| Test Teardown | Testafronding |
| Task Teardown | Taakafronding |
| Test Template | Testsjabloon |
| Task Template | Taaksjabloon |
| Test Timeout | Testtijdslimiet |
| Task Timeout | Taaktijdslimiet |
| Test Tags | Testlabels |
| Task Tags | Taaklabels |
| Keyword Tags | Actiewoordlabels |
| Tags | Labels |
| Setup | Voorbereiding |
| Teardown | Afronding |
| Template | Sjabloon |
| Timeout | Tijdslimiet |
| Arguments | Parameters |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Stel, Gegeven |
| When | Als |
| Then | Dan |
| And | En |
| But | Maar |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Waar, Ja, Aan |
| False | Onwaar, Nee, Uit, Geen |
### [6\.3.14 Polish (pl)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-658)
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteka |
| Resource | Zasób |
| Variables | Zmienne |
| Name | Nazwa |
| Documentation | Dokumentacja |
| Metadata | Metadane |
| Suite Setup | Inicjalizacja Zestawu |
| Suite Teardown | Ukończenie Zestawu |
| Test Setup | Inicjalizacja Testu |
| Task Setup | Inicjalizacja Zadania |
| Test Teardown | Ukończenie Testu |
| Task Teardown | Ukończenie Zadania |
| Test Template | Szablon Testu |
| Task Template | Szablon Zadania |
| Test Timeout | Limit Czasowy Testu |
| Task Timeout | Limit Czasowy Zadania |
| Test Tags | Znaczniki Testu |
| Task Tags | Znaczniki Zadania |
| Keyword Tags | Znaczniki Słowa Kluczowego |
| Tags | Znaczniki |
| Setup | Inicjalizacja |
| Teardown | Ukończenie |
| Template | Szablon |
| Timeout | Limit Czasowy |
| Arguments | Argumenty |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Zakładając, Zakładając, że, Mając |
| When | Jeżeli, Jeśli, Gdy, Kiedy |
| Then | Wtedy |
| And | Oraz, I |
| But | Ale |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Prawda, Tak, Włączone |
| False | Fałsz, Nie, Wyłączone, Nic |
### [6\.3.15 Portuguese (pt)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-659)
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recurso |
| Variables | Variável |
| Name | Nome |
| Documentation | Documentação |
| Metadata | Metadados |
| Suite Setup | Inicialização de Suíte |
| Suite Teardown | Finalização de Suíte |
| Test Setup | Inicialização de Teste |
| Task Setup | Inicialização de Tarefa |
| Test Teardown | Finalização de Teste |
| Task Teardown | Finalização de Tarefa |
| Test Template | Modelo de Teste |
| Task Template | Modelo de Tarefa |
| Test Timeout | Tempo Limite de Teste |
| Task Timeout | Tempo Limite de Tarefa |
| Test Tags | Etiquetas de Testes |
| Task Tags | Etiquetas de Tarefas |
| Keyword Tags | Etiquetas de Palavras-Chave |
| Tags | Etiquetas |
| Setup | Inicialização |
| Teardown | Finalização |
| Template | Modelo |
| Timeout | Tempo Limite |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Quando |
| Then | Então |
| And | E |
| But | Mas |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadeiro, Verdade, Sim, Ligado |
| False | Falso, Não, Desligado, Desativado, Nada |
### [6\.3.16 Brazilian Portuguese (pt-BR)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-660)
#### Settings
| Setting | Translation |
|---|---|
| Library | Biblioteca |
| Resource | Recurso |
| Variables | Variável |
| Name | Nome |
| Documentation | Documentação |
| Metadata | Metadados |
| Suite Setup | Configuração da Suíte |
| Suite Teardown | Finalização de Suíte |
| Test Setup | Inicialização de Teste |
| Task Setup | Inicialização de Tarefa |
| Test Teardown | Finalização de Teste |
| Task Teardown | Finalização de Tarefa |
| Test Template | Modelo de Teste |
| Task Template | Modelo de Tarefa |
| Test Timeout | Tempo Limite de Teste |
| Task Timeout | Tempo Limite de Tarefa |
| Test Tags | Test Tags |
| Task Tags | Task Tags |
| Keyword Tags | Keyword Tags |
| Tags | Etiquetas |
| Setup | Inicialização |
| Teardown | Finalização |
| Template | Modelo |
| Timeout | Tempo Limite |
| Arguments | Argumentos |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Dado |
| When | Quando |
| Then | Então |
| And | E |
| But | Mas |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Verdadeiro, Verdade, Sim, Ligado |
| False | Falso, Não, Desligado, Desativado, Nada |
### [6\.3.17 Romanian (ro)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-661)
#### Settings
| Setting | Translation |
|---|---|
| Library | Librarie |
| Resource | Resursa |
| Variables | Variabila |
| Name | Nume |
| Documentation | Documentatie |
| Metadata | Metadate |
| Suite Setup | Configurare De Suita |
| Suite Teardown | Configurare De Intrerupere |
| Test Setup | Setare De Test |
| Task Setup | Configuarare activitate |
| Test Teardown | Inrerupere De Test |
| Task Teardown | Intrerupere activitate |
| Test Template | Sablon De Test |
| Task Template | Sablon de activitate |
| Test Timeout | Timp Expirare Test |
| Task Timeout | Timp de expirare activitate |
| Test Tags | Taguri De Test |
| Task Tags | Etichete activitate |
| Keyword Tags | Etichete metode |
| Tags | Etichete |
| Setup | Setare |
| Teardown | Intrerupere |
| Template | Sablon |
| Timeout | Expirare |
| Arguments | Argumente |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Fie ca |
| When | Cand |
| Then | Atunci |
| And | Si |
| But | Dar |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Adevarat, Da, Cand |
| False | Fals, Nu, Oprit, Niciun |
### [6\.3.18 Russian (ru)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-662)
#### Settings
| Setting | Translation |
|---|---|
| Library | Библиотека |
| Resource | Ресурс |
| Variables | Переменные |
| Name | |
| Documentation | Документация |
| Metadata | Метаданные |
| Suite Setup | Инициализация комплекта тестов |
| Suite Teardown | Завершение комплекта тестов |
| Test Setup | Инициализация теста |
| Task Setup | Инициализация задания |
| Test Teardown | Завершение теста |
| Task Teardown | Завершение задания |
| Test Template | Шаблон теста |
| Task Template | Шаблон задания |
| Test Timeout | Лимит выполнения теста |
| Task Timeout | Лимит задания |
| Test Tags | Теги тестов |
| Task Tags | Метки заданий |
| Keyword Tags | Метки ключевых слов |
| Tags | Метки |
| Setup | Инициализация |
| Teardown | Завершение |
| Template | Шаблон |
| Timeout | Лимит |
| Arguments | Аргументы |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Дано |
| When | Когда |
| Then | Тогда |
| And | И |
| But | Но |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.19 Swedish (sv)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-663)
#### Settings
| Setting | Translation |
|---|---|
| Library | Bibliotek |
| Resource | Resurs |
| Variables | Variabel |
| Name | Namn |
| Documentation | Dokumentation |
| Metadata | Metadata |
| Suite Setup | Svit konfigurering |
| Suite Teardown | Svit nedrivning |
| Test Setup | Test konfigurering |
| Task Setup | Task konfigurering |
| Test Teardown | Test nedrivning |
| Task Teardown | Task nedrivning |
| Test Template | Test mall |
| Task Template | Task mall |
| Test Timeout | Test timeout |
| Task Timeout | Task timeout |
| Test Tags | Test taggar |
| Task Tags | Arbetsuppgift taggar |
| Keyword Tags | Nyckelord taggar |
| Tags | Taggar |
| Setup | Konfigurering |
| Teardown | Nedrivning |
| Template | Mall |
| Timeout | Timeout |
| Arguments | Argument |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Givet |
| When | När |
| Then | Då |
| And | Och |
| But | Men |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Sant, Ja, På |
| False | Falskt, Nej, Av, Ingen |
### [6\.3.20 Thai (th)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-664)
#### Settings
| Setting | Translation |
|---|---|
| Library | ชุดคำสั่งที่ใช้ |
| Resource | ไฟล์ที่ใช้ |
| Variables | ชุดตัวแปร |
| Name | |
| Documentation | เอกสาร |
| Metadata | รายละเอียดเพิ่มเติม |
| Suite Setup | กำหนดค่าเริ่มต้นของชุดการทดสอบ |
| Suite Teardown | คืนค่าของชุดการทดสอบ |
| Test Setup | กำหนดค่าเริ่มต้นของการทดสอบ |
| Task Setup | กำหนดค่าเริ่มต้นของงาน |
| Test Teardown | คืนค่าของการทดสอบ |
| Task Teardown | คืนค่าของงาน |
| Test Template | โครงสร้างของการทดสอบ |
| Task Template | โครงสร้างของงาน |
| Test Timeout | เวลารอของการทดสอบ |
| Task Timeout | เวลารอของงาน |
| Test Tags | กลุ่มของการทดสอบ |
| Task Tags | กลุ่มของงาน |
| Keyword Tags | กลุ่มของคำสั่งเพิ่มเติม |
| Tags | กลุ่ม |
| Setup | กำหนดค่าเริ่มต้น |
| Teardown | คืนค่า |
| Template | โครงสร้าง |
| Timeout | หมดเวลา |
| Arguments | ค่าที่ส่งเข้ามา |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | กำหนดให้ |
| When | เมื่อ |
| Then | ดังนั้น |
| And | และ |
| But | แต่ |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.21 Turkish (tr)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-665)
#### Settings
| Setting | Translation |
|---|---|
| Library | Kütüphane |
| Resource | Kaynak |
| Variables | Değişkenler |
| Name | |
| Documentation | Dokümantasyon |
| Metadata | Üstveri |
| Suite Setup | Takım Kurulumu |
| Suite Teardown | Takım Bitişi |
| Test Setup | Test Kurulumu |
| Task Setup | Görev Kurulumu |
| Test Teardown | Test Bitişi |
| Task Teardown | Görev Bitişi |
| Test Template | Test Taslağı |
| Task Template | Görev Taslağı |
| Test Timeout | Test Zaman Aşımı |
| Task Timeout | Görev Zaman Aşımı |
| Test Tags | Test Etiketleri |
| Task Tags | Görev Etiketleri |
| Keyword Tags | Anahtar Kelime Etiketleri |
| Tags | Etiketler |
| Setup | Kurulum |
| Teardown | Bitiş |
| Template | Taslak |
| Timeout | Zaman Aşımı |
| Arguments | Argümanlar |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Diyelim ki |
| When | Eğer ki |
| Then | O zaman |
| And | Ve |
| But | Ancak |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Doğru, Evet, Açik |
| False | Yanliş, Hayir, Kapali |
### [6\.3.22 Ukrainian (uk)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-666)
#### Settings
| Setting | Translation |
|---|---|
| Library | Бібліотека |
| Resource | Ресурс |
| Variables | Змінна |
| Name | |
| Documentation | Документація |
| Metadata | Метадані |
| Suite Setup | Налаштування Suite |
| Suite Teardown | Розбірка Suite |
| Test Setup | Налаштування тесту |
| Task Setup | Налаштування завдання |
| Test Teardown | Розбирання тестy |
| Task Teardown | Розбір завдання |
| Test Template | Тестовий шаблон |
| Task Template | Шаблон завдання |
| Test Timeout | Час тестування |
| Task Timeout | Час очікування завдання |
| Test Tags | Тестові теги |
| Task Tags | Теги завдань |
| Keyword Tags | Теги ключових слів |
| Tags | Теги |
| Setup | Встановлення |
| Teardown | Cпростовувати пункт за пунктом |
| Template | Шаблон |
| Timeout | Час вийшов |
| Arguments | Аргументи |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Дано |
| When | Коли |
| Then | Тоді |
| And | Та |
| But | Але |
#### Boolean strings
| True/False | Values |
|---|---|
| True | |
| False | |
### [6\.3.23 Vietnamese (vi)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-667)
New in Robot Framework 6.1.
#### Settings
| Setting | Translation |
|---|---|
| Library | Thư viện |
| Resource | Tài nguyên |
| Variables | Biến số |
| Name | Tên |
| Documentation | Tài liệu hướng dẫn |
| Metadata | Dữ liệu tham chiếu |
| Suite Setup | Tiền thiết lập bộ kịch bản kiểm thử |
| Suite Teardown | Hậu thiết lập bộ kịch bản kiểm thử |
| Test Setup | Tiền thiết lập kịch bản kiểm thử |
| Task Setup | Tiền thiểt lập nhiệm vụ |
| Test Teardown | Hậu thiết lập kịch bản kiểm thử |
| Task Teardown | Hậu thiết lập nhiệm vụ |
| Test Template | Mẫu kịch bản kiểm thử |
| Task Template | Mẫu nhiễm vụ |
| Test Timeout | Thời gian chờ kịch bản kiểm thử |
| Task Timeout | Thời gian chờ nhiệm vụ |
| Test Tags | Các nhãn kịch bản kiểm thử |
| Task Tags | Các nhãn nhiệm vụ |
| Keyword Tags | Các từ khóa nhãn |
| Tags | Các thẻ |
| Setup | Tiền thiết lập |
| Teardown | Hậu thiết lập |
| Template | Mẫu |
| Timeout | Thời gian chờ |
| Arguments | Các đối số |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | Đã cho |
| When | Khi |
| Then | Thì |
| And | Và |
| But | Nhưng |
#### Boolean strings
| True/False | Values |
|---|---|
| True | Đúng, Vâng, Mở |
| False | Sai, Không, Tắt, Không Có Gì |
### [6\.3.24 Chinese Simplified (zh-CN)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-668)
#### Settings
| Setting | Translation |
|---|---|
| Library | 程序库 |
| Resource | 资源文件 |
| Variables | 变量文件 |
| Name | |
| Documentation | 说明 |
| Metadata | 元数据 |
| Suite Setup | 用例集启程 |
| Suite Teardown | 用例集终程 |
| Test Setup | 用例启程 |
| Task Setup | 任务启程 |
| Test Teardown | 用例终程 |
| Task Teardown | 任务终程 |
| Test Template | 用例模板 |
| Task Template | 任务模板 |
| Test Timeout | 用例超时 |
| Task Timeout | 任务超时 |
| Test Tags | 用例标签 |
| Task Tags | 任务标签 |
| Keyword Tags | 关键字标签 |
| Tags | 标签 |
| Setup | 启程 |
| Teardown | 终程 |
| Template | 模板 |
| Timeout | 超时 |
| Arguments | 参数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 假定 |
| When | 当 |
| Then | 那么 |
| And | 并且 |
| But | 但是 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 是, 开 |
| False | 假, 否, 关, 空 |
### [6\.3.25 Chinese Traditional (zh-TW)](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-669)
#### Settings
| Setting | Translation |
|---|---|
| Library | 函式庫 |
| Resource | 資源文件 |
| Variables | 變量文件 |
| Name | |
| Documentation | 說明 |
| Metadata | 元數據 |
| Suite Setup | 測試套啟程 |
| Suite Teardown | 測試套終程 |
| Test Setup | 測試啟程 |
| Task Setup | 任務啟程 |
| Test Teardown | 測試終程 |
| Task Teardown | 任務終程 |
| Test Template | 測試模板 |
| Task Template | 任務模板 |
| Test Timeout | 測試逾時 |
| Task Timeout | 任務逾時 |
| Test Tags | 測試標籤 |
| Task Tags | 任務標籤 |
| Keyword Tags | 關鍵字標籤 |
| Tags | 標籤 |
| Setup | 啟程 |
| Teardown | 終程 |
| Template | 模板 |
| Timeout | 逾時 |
| Arguments | 参数 |
#### BDD prefixes
| Prefix | Translation |
|---|---|
| Given | 假定 |
| When | 當 |
| Then | 那麼 |
| And | 並且 |
| But | 但是 |
#### Boolean strings
| True/False | Values |
|---|---|
| True | 真, 是, 開 |
| False | 假, 否, 關, 空 |
## [6\.4 Documentation formatting](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-634)
It is possible to use simple HTML formatting with [test suite](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-documentation), [test case](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-case-name-and-documentation) and [user keyword](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#user-keyword-documentation) documentation and [free suite metadata](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#free-suite-metadata) in the test data, as well as when [documenting test libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#documenting-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.
- [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#handling-whitespace-in-test-data)
- [Newlines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#newlines)
- [Spaces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#spaces)
- [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs)
- [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-styles)
- [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls)
- [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#custom-links-and-images)
- [Link with text content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#link-with-text-content)
- [Link with image content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#link-with-image-content)
- [Image with title text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#image-with-title-text)
- [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#section-titles)
- [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#tables)
- [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists)
- [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text)
- [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#horizontal-ruler)
### [6\.4.1 Handling whitespace in test data](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-670)
#### [Newlines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-671)
When documenting test suites, test cases and user keywords or adding metadata to test suites, newlines can be added manually using `\n` [escape sequence](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escape-sequence).
```
*** Settings ***
Documentation First line.\n\nSecond paragraph. This time\nwith multiple lines.
Metadata Example list - first item\n- second item\n- third
```
Note
As explained in the [Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs) section below, the single newline in `Second paragraph, this time\nwith multiple lines.` does not actually affect how that paragraph is rendered. Newlines are needed when creating [lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists) or other such constructs, though.
Adding newlines manually to a long documentation takes some effort and extra characters also make the documentation harder to read. This can be avoided, though, as newlines are inserted automatically between [continued documentation and metadata lines](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#dividing-data-to-several-rows). In practice this means that the above example could be written also as follows.
```
*** Settings ***
Documentation
... First line.
...
... Second paragraph. This time
... with multiple lines.
Metadata
... Example list
... - first item
... - second item
... - third
```
No automatic newline is added if a line already ends with a literal newline or if it ends with an [escaping backslash](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#escaping):
```
*** Test Cases ***
Ends with newline
[Documentation] Ends with a newline and\n
... automatic newline is not added.
Ends with backslash
[Documentation] Ends with a backslash and \
... no newline is added.
```
#### [Spaces](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-672)
Unlike elsewhere in Robot Framework data, leading spaces and consecutive internal spaces are preserved in documentation and metadata. This makes it possible, for example, to split [list items](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#lists) to multiple rows and have [preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#preformatted-text) with spaces:
```
*** Test Cases ***
Long list item
[Documentation]
... List:
... - Short item.
... - Second item is pretty long and it is split to
... multiple rows. Leading spaces are preserved.
... - Another short item.
Preformatted text
[Documentation]
... Example with consecutive internal spaces:
...
... | *** Test Cases ***
... | Example
... | Keyword
```
Note
Preserving spaces in documentation and metadata is new in Robot Framework 6.1. With earlier versions spaces need to be escaped with a backslash.
### [6\.4.2 Paragraphs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-673)
All regular text in the formatted HTML documentation is represented as paragraphs. In practice, lines separated by a single newline will be combined in a paragraph regardless whether the newline is added manually or automatically. Multiple paragraphs can be separated with an empty line (i.e. two newlines) and also tables, lists, and other specially formatted blocks discussed in subsequent sections end a paragraph.
For example, the following test suite or resource file documentation:
```
*** Settings ***
Documentation
... First paragraph has only one line.
...
... Second paragraph, this time created
... with multiple lines.
```
will be formatted in HTML as:
First paragraph has only one line.
Second paragraph, this time created with multiple lines.
### [6\.4.3 Inline styles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-674)
The documentation syntax supports inline styles **bold**, *italic* and `code`. 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*_`.
The code style is created using double backticks like \``code\``. The result is monospaced text with light gray background.
Asterisks, underscores or double backticks alone, or in the middle of a word, do not start formatting, but punctuation characters before or after them are allowed. When multiple lines form a [paragraph](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#paragraphs), all inline styles can span over multiple lines.
| Unformatted | Formatted |
|---|---|
| \*bold\* | **bold** |
| \_italic\_ | *italic* |
| \_\*bold italic\*\_ | ***bold italic*** |
| \``code\`` | `code` |
| \*bold\*, then \_italic\_ and finally \``some code\`` | **bold**, then *italic* and finally `some code` |
| This is \*bold\\n on multiple\\n lines\*. | This is **bold** **on multiple** **lines**. |
### [6\.4.4 URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-675)
All strings that look like URLs are automatically converted into clickable links. Additionally, URLs that end with extension .jpg, .jpeg, .png, .gif, .bmp or .svg (case-insensitive) will automatically create images. For example, URLs like `http://example.com` are turned into links, and `http:///host/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, and for test suite metadata.
Note
.svg image support is new in Robot Framework 3.2.
### [6\.4.5 Custom links and images](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-676)
It is possible to create custom links and embed images using special syntax `[link|content]`. This creates a link or image depending are `link` and `content` images. They are considered images if they have the same image extensions that are special with [URLs](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#urls) or start with `data:image/`. The surrounding square brackets and the pipe character between the parts are mandatory in all cases.
Note
Support for the `data:image/` prefix is new in Robot Framework 3.2.
#### [Link with text content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-677)
If neither `link` nor `content` is an image, the end result is a normal link where `link` is the link target and `content` the visible text:
```
[file.html|this file] -> <a href="file.html">this file</a>
[http://host|that host] -> <a href="http://host">that host</a>
```
#### [Link with image content](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-678)
If `content` is an image, you get a link where the link content is an image. Link target is created by `link` and it can be either text or image:
```
[robot.html|robot.png] -> <a href="robot.html"><img src="robot.png"></a>
[robot.html|data:image/png;base64,oooxxx=] -> <a href="robot.html"><img src="data:image/png;base64,oooxxx="></a>
[image.jpg|thumb.jpg] -> <a href="image.jpg"><img src="thumb.jpg"></a>
```
#### [Image with title text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-679)
If `link` is an image but `content` is not, the syntax creates an image where the `content` is the title text shown when mouse is over the image:
```
[robot.jpeg|Robot rocks!] -> <img src="robot.jpeg" title="Robot rocks!">
[data:image/png;base64,oooxxx=|Robot rocks!] -> <img src="data:image/png;base64,oooxxx=" title="Robot rocks!">
```
### [6\.4.6 Section titles](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-680)
If documentation gets longer, it is often a good idea to split it into sections. It is possible to separate sections with titles using syntax `= My Title =`, where the number of equal signs denotes the level of the title:
```
= First section =
== Subsection ==
Some text.
== Second subsection ==
More text.
= Second section =
You probably got the idea.
```
Notice that only three title levels are supported and that spaces between equal signs and the title text are mandatory.
### [6\.4.7 Tables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-681)
Tables are created using pipe characters with spaces around them as column separators and newlines as row separators. Header cells can be created by surrounding the cell content with equal signs and optional spaces like `= Header =` or `=Header=`. Tables cells can also contain links and formatting such as bold and italic:
```
| =A= | =B= | = C = |
| _1_ | Hello | world! |
| _2_ | Hi |
```
The created table always has a thin border and normal text is left-aligned. Text in header cells is bold and centered. Empty cells are automatically added to make rows equally long. For example, the above example would be formatted like this in HTML:
| A | B | C |
|---|---|---|
| *1* | Hello | world |
| *2* | Hi | |
### [6\.4.8 Lists](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-682)
Lists are created by starting a line with a hyphen and space ('- '). List items can be split into multiple lines by indenting continuing lines with one or more spaces. A line that does not start with '- ' and is not indented ends the list:
```
Example:
- a list item
- second list item
is continued
This is outside the list.
```
The above documentation is formatted like this in HTML:
Example:
- a list item
- second list item is continued
This is outside the list.
### [6\.4.9 Preformatted text](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-683)
It is possible to embed blocks of preformatted text in the documentation. Preformatted block is created by starting lines with '\| ', one space being mandatory after the pipe character except on otherwise empty lines. The starting '\| ' sequence will be removed from the resulting HTML, but all other whitespace is preserved.
In the following documentation, the two middle lines form a preformatted block when converted to HTML:
```
Doc before block:
| inside block
| some additional whitespace
After block.
```
The above documentation is formatted like this:
Doc before block:
```
inside block
some additional whitespace
```
After block.
### [6\.4.10 Horizontal ruler](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-684)
Horizontal rulers (the `<hr>` tag) make it possible to separate larger sections from each others, and they can be created by having three or more hyphens alone on a line:
```
Some text here.
---
More text...
```
The above documentation is formatted like this:
Some text here.
***
More text...
## [6\.5 Time format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-635)
Robot Framework has its own time format that is both flexible to use and easy to understand. It is used by several keywords (for example, [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords Sleep and Wait Until Keyword Succeeds), [DateTime](https://robotframework.org/robotframework/latest/libraries/DateTime.html) library, and [timeouts](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#timeouts).
- [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-number)
- [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-time-string)
- [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#time-as-timer-string)
### [6\.5.1 Time as number](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-685)
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.
Note
In some contexts plain numbers can be interpreted otherwise as times. For example, with [WHILE loop limit](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#limiting-while-loop-iterations) integers denote the maximum iteration count.
### [6\.5.2 Time as time string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-686)
Representing the time as a time string 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 it is possible to add `-` prefix to specify negative times. The available time specifiers are:
- weeks, week, w
- days, day, d
- hours, hour, h
- minutes, minute, mins, min, m
- seconds, second, secs, sec, s
- milliseconds, millisecond, millis, ms
- microseconds, microsecond, us, μs
- nanoseconds, nanosecond, ns
Examples:
```
1 min 30 secs
1.5 minutes
90 s
1 day 2 hours 3 minutes 4 seconds 5 milliseconds 6 microseconds 7 nanoseconds
8 weeks 7 days 6 hours 5 minutes 4 seconds 3 milliseconds 2 microseconds 1 nanosecond
1d 2h 3m 4s 5ms 6μs 7 ns
8w 7d 6h 5m 4s 3ms 2μs 1ns
- 10 seconds
```
Note
Support for micro and nanoseconds is new in Robot Framework 6.0. Support for weeks is new in Robot Framework 7.1.
### [6\.5.3 Time as "timer" string](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-687)
Time can also be given in timer like format `hh:mm:ss.mil`. In this format both hour and millisecond parts are optional, leading and trailing zeros can be left out when they are not meaningful, and negative times can be represented by adding the `-` prefix. For example, following timer and time string values are identical:
| Timer | Time string |
|---|---|
| 00:00:01 | 1 second |
| 01:02:03 | 1 hour 2 minutes 3 seconds |
| 1:00:00 | 1 hour |
| 100:00:00 | 100 hours |
| 00:02 | 2 seconds |
| 42:00 | 42 minutes |
| 00:01:02.003 | 1 minute 2 seconds 3 milliseconds |
| 00:01.5 | 1\.5 seconds |
| \-01:02.345 | \- 1 minute 2 seconds 345 milliseconds |
## [6\.6 Boolean arguments](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-636)
Many keywords in Robot Framework [standard libraries](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#standard-libraries) accept arguments that are handled as Boolean values true or false. If such an argument is given as a string, it is considered false if it is an empty string or equal to `FALSE`, `NONE`, `NO`, `OFF` or `0`, case-insensitively. Other strings are considered true unless the keyword documentation explicitly states otherwise, and other argument types are tested using the same [rules as in Python](http://docs.python.org/library/stdtypes.html#truth-value-testing).
```
*** Keywords ***
True examples
Should Be Equal ${x} ${y} Custom error values=True # Strings are generally true.
Should Be Equal ${x} ${y} Custom error values=yes # Same as the above.
Should Be Equal ${x} ${y} Custom error values=${TRUE} # Python `True` is true.
Should Be Equal ${x} ${y} Custom error values=${42} # Numbers other than 0 are true.
False examples
Should Be Equal ${x} ${y} Custom error values=False # String `false` is false.
Should Be Equal ${x} ${y} Custom error values=no # Also string `no` is false.
Should Be Equal ${x} ${y} Custom error values=${EMPTY} # Empty string is false.
Should Be Equal ${x} ${y} Custom error values=${FALSE} # Python `False` is false.
Should Be Equal ${x} ${y} Custom error values=no values # Special false string with this keyword.
```
Note
Considering `OFF` and `0` false is new in Robot Framework 3.1.
## [6\.7 Evaluating expressions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-637)
This appendix explains how expressions are evaluated using Python in different contexts and how variables in expressions are handled.
- [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#introduction-4)
- [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#evaluation-namespace)
- [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-variables-1)
- [Normal `${variable}` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#normal-variable-syntax)
- [Special `$variable` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#special-variable-syntax)
### [6\.7.1 Introduction](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-688)
Constructs such as [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures), [WHILE loops](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#while-loops) and [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) as well as several [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords accept an expression that is evaluated in Python:
```
*** Test Cases ***
IF/ELSE
IF ${x} > 0
Log to console ${x} is positive
ELSE
Log to console ${x} is negative
END
Inline Python evaluation
Log to console ${x} is ${{'positive' if ${x} > 0 else 'negative'}}
Evaluate keyword
${type} = Evaluate 'positive' if ${x} > 0 else 'negative'
Log to console ${x} is ${type}
Should Be True keyword
Should Be True ${x} > 0
```
Notice that instead of creating complicated expressions, it is often better to move the logic into a [test library](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#using-test-libraries). That typically eases maintenance and also enhances execution speed.
### [6\.7.2 Evaluation namespace](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-689)
Expressions are evaluated using Python's [eval](http://docs.python.org/library/functions.html#eval) function so that normal Python constructs like `'${x}' == 'expected'`, `${x} > 0` and `'${x}'.upper() not in ('FAIL', 'BAD')` can be used and all builtin functions like `len()` and `int()` are available. In addition to that, all unrecognized Python variables are considered to be modules that are automatically imported. It is possible to use all available Python modules, including the standard modules and the installed third party modules.
The following examples demonstrate using Python builtins as well as modules using the [inline Python evaluation](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#inline-python-evaluation) syntax, but same expressions would also work with [IF/ELSE structures](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#if-else-structures) and [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keywords without the need to use the `${{}}` decoration around the expression:
```
*** Variables ***
${VAR} 123
*** Test Cases ***
Python syntax
Should Be True ${{'${VAR}' == '123'}}
Should Be True ${{'${VAR}'.startswith('x') or '${VAR}' in '012345'}}
Python builtins
Should Be Equal ${{len('${VAR}')}} ${3}
Should Be Equal ${{int('${VAR}')}} ${123}
Access modules
Should Be Equal ${{os.sep}} ${/}
Should Be Equal ${{round(math.pi, 2)}} ${3.14}
Should Start With ${{robot.__version__}} 4.
```
A limitation of using modules is that nested modules like `rootmod.submod` can only be used if the root module automatically imports the submodule. That is not always the case and using such modules is not possible. An concrete example that is relevant in the automation context is the `selenium` module that is implemented, at least at the time of this writing, so that just importing `selenium` does not import the `selenium.webdriver` submodule. Another limitation is that modules cannot be used in the expression part of a list comprehension. A workaround to both of these problems is using the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) keyword Evaluate that accepts modules to be imported and added to the evaluation namespace as an argument:
```
*** Test Cases ***
Does not work due to nested module structure
Log ${{selenium.webdriver.ChromeOptions()}}
Evaluate keyword with nested module
${options} = Evaluate selenium.webdriver.ChromeOptions() modules=selenium.webdriver
Log ${options}
Does not work due to list comprehension
Log ${{[json.loads(item) for item in ('1', '"b"')]}}
Evaluate keyword with list comprehension
${items} = Evaluate [json.loads(item) for item in ('1', '"b"')] modules=json
Log ${items}
```
The Evaluate keyword also supports custom evaluation namespaces if further customization is needed. See its documentation in the [BuiltIn](https://robotframework.org/robotframework/latest/libraries/BuiltIn.html) library for more details.
### [6\.7.3 Using variables](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-690)
#### [Normal `${variable}` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-691)
When a variable is used in the expression using the normal `${variable}` syntax, its value is replaced before the expression is evaluated. This means that the value used in the expression will be the string representation of the variable value, not the variable value itself. This is not a problem with numbers and other objects that have a string representation that can be evaluated directly. For example, if we have a return code as an integer in variable `${rc}`, using something like `${rc} > 0` is fine.
With other objects the behavior depends on the string representation. Most importantly, strings must always be quoted either with single or double quotes like `'${x}'`, and if they can contain newlines, they must be triple-quoted like `'''${x}'''`. Strings containing quotes themselves cause additional problems, but triple-quoting typically handles them. Also the backslash character \\ is problematic, but can be handled by using Python's raw-string notation like `r'${path}'`.
```
*** Test Cases ***
Using normal variable syntax
Should Be True ${rc} > 0
IF '${status}'.upper() == 'PASS'
Log Passed
END
IF 'FAIL' in r'''${output}'''
Log Output contains FAIL
END
```
#### [Special `$variable` syntax](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-692)
Quoting strings is not that convenient, but there are cases where replacing the variable with its string representation causes even bigger problems. For example, if the variable value can be either a string or Python `None`, quoting like `'${var}'` is needed because otherwise strings do not work, but then `None` is interpreted to be a string as well. Luckily there is an easy solution to these problems discussed in this section.
Actual variables values are available in the evaluation namespace and can be accessed using special variable syntax without the curly braces like `$variable`. Such variables should never be quoted, not even if they contain strings.
Compare this these examples with the example in the previous section:
```
*** Test Cases ***
Using special variable syntax
Should Be True $rc > 0
IF $status.upper() == 'PASS'
Log Passed
END
IF 'FAIL' in $output
Log Output contains FAIL
END
Only possible using special variable syntax
Should Be True $example is not None
Should Be True len($result) > 1 and $result[1] == 'OK'
```
Using the `$variable` syntax slows down expression evaluation a little. This should not typically matter, but should be taken into account if complex expressions are evaluated often and there are strict time constrains. Moving such logic to test libraries is typically a good idea anyway.
Note
Due to technical reasons, these special variables are available during evaluation as local variables. That makes them unavailable in non-local scopes such as in the expression part of list comprehensions and inside lambdas.
## [6\.8 Registrations](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-638)
This appendix lists file extensions, media types, and so on, that are associated with Robot Framework.
### [6\.8.1 Suite file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-222)
[Suite files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#suite-files) with the following extensions are parsed automatically:
.robot
Suite file using the [plain text format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#plain-text-format).
.robot.rst
Suite file using the [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#restructuredtext-format).
.rbt
Suite file using the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#json-format).
Using other extensions is possible, but it requires [separate configuration](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#selecting-files-to-parse).
### [6\.8.2 Resource file extensions](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#toc-entry-223)
[Resource files](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files) can use the following extensions:
.resource
Recommended when using the plain text format.
.robot, .txt and .tsv
Supported with the plain text format for backwards compatibility reasons. .resource is recommended and may be mandated in the future.
.rst and .rest
Resource file using the [reStructuredText format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-restructured-text-format).
.rsrc and .json
Resource file using the [JSON format](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#resource-files-using-json-format). |
| Shard | 15 (laksa) |
| Root Hash | 1181309642191291415 |
| Unparsed URL | org,robotframework!/robotframework/latest/RobotFrameworkUserGuide.html s443 |