I have this code snippet
*** Keywords ***
My Keyword
[Arguments] ${arg}
${xpath} Set Variable really long dynamic xpath using ${arg}
Do Something With ${xpath}
etc.
My Other Keyword
[Arguments] ${arg}
${xpath} Set Variable really long dynamic xpath using ${arg}
Do Something Totally Different With ${xpath}
etc.
To follow programming best practices, I want to have the xpath (the same in both keywords) defined at single place only. I tried to modify it like this
*** Variables ***
${xpath_template} really long dynamic xpath using \${arg}
*** Keywords ***
My Keyword
[Arguments] ${arg}
${xpath} Evaluate ${xpath_template}
Do Something With ${xpath}
etc.
My Other Keyword
[Arguments] ${arg}
${xpath} Evaluate ${xpath_template}
Do Something Totally Different With ${xpath}
etc.
In other words, I need the substitution of ${arg} in ${xpath_template} be defered until the moment ${arg} is defined. However, the code above does not perform it, nor my similar experiments when I tried to force Set Variable or ${{...}} to do it for me... Can you help me, please, to have the xpath be only once in my code?
The solution is to use the Replace Variables keyword.
*** Variables ***
${xpath_template} blah blah \${arg}
*** Keywords ***
My Keyword
[Arguments] ${arg}
${xpath} Replace variables ${xpath_template}
Return from keyword ${xpath}
*** Test Cases ***
Example
${xpath}= My keyword Hello, world
Should be equal ${xpath} blah blah Hello, world
Related
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']
In the Robot Framework user guide, it states a variable value is a list or list-like, it is also possible to use it as a list variable like #{EXAMPLE} and There is also an empty list variable #{EMPTY} but I am not able to create an empty list. In the minimally reproducible example below, no matter how I set it up I get the error, TypeError: Expected argument 1 to be a list or list-like, got string instead in my test case. How can I create an empty list that doesn't re-assign itself to be a string?
*** Settings ***
Library Collections
Suite Setup Re-instantiate List
*** Variables ***
#{shouldBeList}= #{EMPTY}
*** Test Cases ***
Add something to the list
Collections.Append to list #{shouldBeList} Test
*** Keywords ***
Re-instantiate List
#{shouldBeList}= Create List ${EMPTY}
Set Suite Variable #{shouldBeList} #{shouldBeList}
# Results:
# Add something to the list | FAIL |
# TypeError: Expected argument 1 to be a list or list-like, got string instead.
I should have read the user guide more closely.
All variables should be assigned using the ${var} syntax, including lists and dicts. The #{var} and &{var} syntax should be used when you want to unpack the ${var}, using the # symbol if it's list-like and & if it's dict-like.
My above code works when written as:
*** Settings ***
Library Collections
Suite Setup Re-instantiate List
*** Variables ***
*** Test Cases ***
Add something to the list
Collections.Append to list ${shouldBeList} Test
*** Keywords ***
Re-instantiate List
${shouldBeList}= Create List
Set Suite Variable #{shouldBeList} #{shouldBeList}
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 |
------------------------------------------------------------------------------
I want to work with the dictionary in different keywords. But I get the error when I try to work with the dictionary in another keyword:
AttributeError: 'str' object has no attribute 'keys'
This is my sample code:
*** Settings ***
Library Collections
*** Variables ***
&{PRODUCTS}
*** Keywords ***
Set the Dictionary
&{PRODUCTS} = create dictionary OrderN=R0
... OrderPersonal=No_Account OrderPosition=EmptyPosition
Get the Dictionary
log dictionary \&{PRODUCTS}
*** Test Cases ***
Using the dictionary type of variables
Set the Dictionary
Get the Dictionary
set to dictionary &{PRODUCTS} OrderPosition TestPosition
Get the Dictionary
Why is the variable not accessible in another keyword? How can I resolve the issue?
The problem you are facing is because of Robot Framework variable scope. This is explained in the following Robot Framework guide section: Variable priorities and scopes.
In this case I think you should use one of the Set Test/Suite/Global Variable keywords to store the variable outside the keyword scope.
*** Keywords ***
Set the Dictionary
&{PRODUCTS} = create dictionary OrderN=R0
... OrderPersonal=No_Account OrderPosition=EmptyPosition
Set Test Variable ${PRODUCTS} &{PRODUCTS}
consider the following robotframework code example:
*** Variables ***
${VAR_1} any value
${VAR_2} another value
*** Test Cases ***
For Example only
${VAR_1}= Some Conversion ${VAR_1}
${VAR_2}= Some Conversion ${VAR_2}
A User Keyword ${VAR_1} ${VAR_2}
Desired Notation
A User Keyword Some Conversion ${VAR_1} Some Conversion ${VAR_2}
*** Keywords ***
Some Conversion
[Arguments] ${value_to_convert}
${value_to_convert}= Catenate ${value_to_convert} Foobar
[Return] ${value_to_convert}
A User Keyword
[Arguments] ${arg1} ${arg2}
Log ${arg1}
Log ${arg2}
Question: is there a possibility to simplify the working testcase For Example only to the (non working) Desired Notation - or - can I somehow use the return value of a keyword to be passed as parameter without doing an explicit assignment before?
For clarification:
Some Conversion would be far more complex and is implemented within
a jrobotremotelibrary
Moving the assingments to A User Keyword is
no useful solution, because there will be many keywords with
different amount of parameters using the same functionality
Yes, it is possible. You can write your own keywords that call other keywords which are passed in as arguments
It would look something like this:
*** Keywords ***
A User Keyword
[Arguments] ${keyword1} ${var1} ${keyword2} ${var2}
${var1}= Run keyword ${keyword1} ${var1}
${var2}= Run keyword ${keyword2} ${var2}
log ${var1}
log ${var2}
You would use this keyword exactly like in your example:
A User Keyword Some Conversion ${VAR_1} Some Conversion ${VAR_2}
The argument value assignment of a keyword can not be the return value of another keyword.
As highlighted by #Bryan Oakly it is possible to mimic the appearance with some clever usage of Run keyword, as you highlighted this will not work as the assignment may not always be using keywords or even keywords with the same number of arguments.
So, the best approach is what you've already been doing, assigning the value to a variable and then the variable to the keyword argument.