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.
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.
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.
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:
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:
There can be multiple nesting levels and loops can also be combined with other control structures:
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:
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.
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:
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:
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):
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:
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:
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:
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.
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 usingstrict=Truewith 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 thefilloption orNoneif it is not used. This is the same as using Python's zip_longest function except that it hasfillvalueargument instead offill.
All these modes are illustrated by the following examples:
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.
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.
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:
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.
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.
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¶
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. Although 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.
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.
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.
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:
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.
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.
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.
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:
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:
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:
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:
The inline IF syntax supports also ELSE and ELSE IF branches:
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.
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})}}):
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/ELSEsyntax 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.
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:
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.
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:
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.
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:
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:
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:
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:
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/EXCEPTwith 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 nativeTRY/EXCEPTfunctionality 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
PASSorFAILalong with possible return value or error message. It is basically the same as usingTRY/EXCEPT/ELSEso thatEXCEPTcatches 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
FINALLYbranches. -
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.
GROUP syntax¶
The GROUP syntax allows grouping related keywords and control structures together:
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:
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.