Running test case In loop instead of copy the code - robotframework

I have several tests in robot. the Idea of all the tests is identical:
- load some parameter to module
- run
- compare expected to actual results
The only thing is different from test to test, is the input and the expected results.
I would like to run the test repeatedly but with different inputs- and each iteration will be considered as different test case - Instead of copy the same code for all of the test cases and change the inputs.
each iteration will have its own test case tag \ documentation \ name (lets say the iteration number)
for example:
FOR ${TC} IN #{TCS} #TCS is array of inputs and expected output
*** Test Cases ***
# edit the tag \ documentation \ test name
module.load ${TC['input']}
${output} = module.run
isValid ${output} ${TC['expectedOutput']}
END
Is it possible in robot?
Thanks:)

The easyest way is to define a Keyword with Arguments and Return Values.
You can call this Keyword in every Tescase (with specified tag/documentation etc), with specified Arguments for the Test and check the Reuturn Values.

You could use the test template feature of the framework, especially the template tests with for loop.
Using it would give the following advantages:
No code duplication. You need one keyword with the test logic, that will be invoked with all list elements.
Each iteration will be independent from the other. So if one iteration fails, the next will be still executed.
It is flexible. The number of iterations is dynamic, you can create an input list in a test or suite setup phase.
Example, note that I am providing my inputs from a variable file.
*** Settings ***
Variables VariableFile.py
*** Test Cases ***
Math test
[Template] Multiplication by 2
FOR ${TC} IN #{TCS}
input=${TC.input} output=${TC.output}
END
*** Keywords ***
Multiplication by 2
[arguments] ${input} ${output}
${result}= Evaluate ${input}*2
Should Be Equal As Integers ${output} ${result} Calculated result:${result} is not equal with the expected:${output}
Variable file:
class DataSet(object):
def __init__(self, input, output):
self.input = input
self.output = output
def __str__(self):
return f'i:{self.input} - o:{self.output}'
TCS = [DataSet(1,2), DataSet(2,4), DataSet(3,6), DataSet(3,7), DataSet(4,8)]
This is the output:

Related

Build a Robot Framework list from several keyword calls

I have several Robot Framework keywords that return a basic string.
#keyword
def keyword_one():
return 'one'
#keyword
def keyword_two():
return 'two'
In a robot test case, I try to build a list with this items, but I can't figure out how to do that is one line.
*** Test Cases ***
Test Case List
#{my_list}= Create List Keyword One Keywork Two
I tried several syntax but can't make it work.
Of course, something like below works (hardcoded values).
*** Test Cases ***
Test Case List
#{my_list}= Create List one two
Thanks for your help.
At the time that I write this, robot doesn't have the ability to call keywords inline, so what you want isn't directly possible.
You could write your own keyword to do this, however. The keyword can accept multiple keywords as arguments, and use run keyword from the built-in library to run the keyword.
For example, the following keyword definition creates a keyword that creates a list of results from multiple keywords:
Keyword written in python
If you want to try this out, name the file example.py
from robot.libraries.BuiltIn import BuiltIn
builtin = BuiltIn()
def create_list_from_keywords(*keywords):
result = []
for keyword in keywords:
result.append(builtin.run_keyword(keyword))
return result
Example test
*** Settings ***
Library example.py
*** Keywords ***
Keyword one
return from keyword one
Keyword two
return from keyword two
*** Test cases ***
Example
#{actual}= create list from keywords Keyword one Keyword two
#{expected}= create list one two
Should be equal ${actual} ${expected}
Robot-based keyword definition
If you're uncomfortable with python, here's a robot-based keyword definition:
Create list from keywords
[Arguments] #{keywords}
[Return] #{result}
#{result}= create list
FOR ${keyword} IN #{keywords}
${keyword result}= Run keyword ${keyword}
Append to list ${result} ${keyword result}
END
At the moment you are adding the keywords to the list, not the values returned from running those keywords
You would need to call the keywords to get the returned values and add them to the list e.g.
*** Test Cases ***
Test Case List
${keyword_one_val} Keyword One
${keyword_two_val} Keyword Two
#{my_list}= Create List ${keyword_one_val} ${keyword_two_val}
log to console ${my_list}
which outputs:
['one', 'two']

Test Template with Robot Framework cannot use variables

I have some problems using the robotframework template,how to get variables passed to the template?
Here is my code:
*** Keywords ***
re-random-value
${random int} = Evaluate random.randint(1, 5)
[Return] ${random-num}
*** Test Cases *** test1
[Template] test template
re-random-value # random-num is return value from keywords re-random-value
*** Keywords ***
test template
[Arguments] ${random-num}
log ${random-num}
when I run the test case test1, The result is re-random-value, not the number of values returned by the keyword re-random-value I expected
The documentation on Robot Framework Test Templates states the following:
... test cases with template contain only the arguments for the
template keyword.
Within the context of a test template an argument can never be a keyword, the approach in the example won't work as is.
Assuming for a moment that the keyword may change per line/test case an intermediate keyword can be constructed that takes the name of the keyword as an argument and executes it. In the below updated version of your example this is what is done. Using the FOR loop to generate multiple values.
*** Test Cases ***
test1
[Template] test template
FOR ${index} IN RANGE 1 5
re-random-value # random-num is return value from keywords re-random-value
END
*** Keywords ***
test template
[Arguments] ${keyword}
${value} Run Keyword ${keyword}
Log To Console ${value}
re-random-value
${random int} = Evaluate random.randint(1, 5) modules=random
[Return] ${random int}
Results in (bear in mind the randomness of the values):
==============================================================================
test1 1
3
2
3
| PASS |
------------------------------------------------------------------------------

Arguments in if statements are ignored 1/2 the time

*** variables ***
${x} 0
*** Test Cases ***
Test1
run keyword if ${x} == 1 run keywords
... print hi
... ELSE
... print hi
Test2
run keyword if ${x} == 0 run keywords
... print hi
... ELSE
... print hi
*** keywords ***
print
[arguments] ${x}
log to console ${x}
Output:
Test1 hi
Test1 | PASS |
------------------------------------------------------------------------------
Test2 | FAIL |
Keyword 'print' expected 1 argument, got 0.
------------------------------------------------------------------------------
What is going on here? Arguments at the second print work but are ignored at the first.
The difference is that in one case you're calling run keywords (with arguments) and in the other case you're running print (with arguments).
We can reformat your code to show how robot is looking at it:
run keyword if ${x} == 1
... run keywords print hi
... ELSE
... print hi
When the expression is false, you fall through and run print hi, and everything works.
When the case is true, robot runs run keywords print hi. run keywords treats each of its arguments as a separate keyword to run so it tries to run print, and then it tries to run hi. Since you aren't giving an argument to print, it throws the error.
The issue comes from you expecting the hi to be passed as an argument to print in the run keywords construct, but robot doesn't treat it that way, the hi is just another keyword to be ran.
In Run Keywords documentation there's a paragraph how to use keywords with arguments in it - you have to chain the keywords with an AND:
... keywords can also be run with arguments using upper case AND as a separator between keywords. The keywords are executed so that the first argument is the first keyword and proceeding arguments until the first AND are arguments to it. First argument after the first AND is the second keyword and proceeding arguments until the next AND are its arguments. And so on.
In your case:
run keyword if ${x} == 1 run keywords
... print hi AND No Operation
... ELSE
... print hi
, will now change the call to "run the keyword print with an argument 'hi', and then run the keyword No Operation" (which does literally nothing, comes in handy for situations like this).

How to null check List in Robot FrameWork

${rowcount}= Keyword1 Book1.xlsx 0
${length}= Set Variable ${rowcount}
${i} Set Variable 1
:FOR ${rowvalue} IN RANGE ${rowcount}
\ #{columnlist}= Keyword2 ${rowvalue}
Keyword2 is returning List of data. I want to check whether it is returning Empty List. Please help me with this?
The BuiltIn library has keywords Should be empty and Should not be empty which can be used to validate the length of a list.
Should Be Empty ${columnlist}
Should Not Be Empty ${columnlist}
Just in case someone else comes here looking for an answer which also addresses:
If ${columnlist} is not empty then I have to execute keyword below it. Is it possible using If statement? – Orsu Suni Jun 12 '17 at 4:44
Either one of these options should help (NOTE: only used within RIDE, I imagine they will work for others as well):
${len} Get Length ${columnlist} ---- will return zero if list is empty, you can then use ${len} in your conditional.
'#{columnlist}' == '#{EMPTY}' ---- should return true if list is empty, although so far I have only used it with RUN KEYWORD IF.
Alternatively you could run the following keyword:
${isEmpty} Run Keyword And Return Status Should Be Empty ${columnlist}
Then you get a boolean value in ${isEmpty} with whether the list is empty or not.
Statements/conditions in Robot are a bit confusing in my opinion. Previous suggestion 2. doesn't work for me. I'm using: Robot Framework 3.1.2 (Python 3.4.1 on win32)
I obtain expected solution:
*** Test Cases ***
TC1
${marker_files} Create List dummy3 dummy4 dummy5
Run keyword unless ${marker_files} == #{EMPTY} Operation on list
marker_files=${marker_files}
tc2
${marker_files} Create List #{EMPTY}
Run keyword unless ${marker_files} == #{EMPTY} Operation on list
marker_files=${marker_files}
*** Keywords ***
Operation on list
[Arguments] ${marker_files}=def
log to console \ndo something on list

How can I check if a variable is inside a list during a for loop in robot framework?

first time posting here. I've a feeling that this is a really dumb question, but for some reason my code keeps failing and I just can't put my finger on what's wrong.
Here's is what I have:
*** Settings ***
Library Selenium2Library
Library OperatingSystem
Library String
Library Collections
*** Test Cases ***
Test Robot Framework Logging
#{ALLOWED}= Create List /page1 /page2 /page3
${ControllersList}= Get File ${EXEC_DIR}/Resources/controllers.txt
#{PAGES}= Split to lines ${ControllersList}
:FOR ${PAGE} IN #{PAGES}
\ Run Keyword If '${PAGE} IN #{ALLOWED}' Log Testing WARN
[Teardown] Close Browser
This is the output:
Evaluating expression ''/page1 IN [u'/page1', u'/page2', u'/page3']'' failed: SyntaxError: invalid syntax (<string>, line 1)
If I change the condition to something like this it works:
'${PAGE} == /page1'
I checked the documentation and it seems that the IN condition could be used. I'm totally lost here. Any hints? Thanks!
This is the proper way to do the expression:
Run Keyword If $PAGE in $ALLOWED Log Testing WARN
By removing the quotes and the curly braces, robot is able to treat PAGE and ALLOWED as python variables when evaluating the expression.
From the section Evaluating Expressions in the documentation for the BuiltIn library:
Starting from Robot Framework 2.9, variables themselves are automatically available in the evaluation namespace. They can be accessed using special variable syntax without the curly braces like $variable. These variables should never be quoted, and in fact they are not even replaced inside strings.
Also, when using keywords like Run Keyword If, the expression must be a valid python expression after variable substitution. Therefore, you must use the operator in rather than IN. The latter is used only by the robot :FOR statement.
Example
*** Variables ***
#{ALLOWED} /page1 /page2 /page3
*** Test Cases ***
Example that passes
${PAGE}= set variable /page1
Run Keyword If $PAGE in $ALLOWED
... pass execution ${PAGE} is allowed
fail ${PAGE} is not allowed
Example that fails
${PAGE}= set variable /page99
Run Keyword If $PAGE in $ALLOWED
... pass execution ${PAGE} is allowed
fail ${PAGE} is not allowed
The check was almost right, but you've effectively turned the Boolean expression into a String by surrounding it with the quotes. Here's the syntax that'll do it:
\ Run Keyword If $PAGE in $ALLOWED Log Testing WARN
Mind there are no curly brackets {} around the variable names - thus the check is (almost) the straight python's variable in another_variable
The documentation Evaluating Expressions does indeed specify that in construction used in the evaluation itself. An alternative approach is to use the Collections library keyword Get Match Count. This will return 0 when no results are found, and not generate a test failure.
*** Settings ***
Library Collections
*** Test Cases ***
Test Robot Framework Logging
#{ALLOWED}= Create List /page1 /page2 /page3
#{PAGES}= Create List /page1 /page3 /page5
:FOR ${PAGE} IN #{PAGES}
\ ${InList}= Get Match Count ${ALLOWED} ${PAGE}
\ Run Keyword If ('${InList}' == '0') Log To Console Page Not Allowed
\ ... ELSE IF ('${InList}' == '1') Log To Console 1 Page Found
\ ... ELSE Log To Console More pages found.

Resources