Is there a way of defining, in the Variables section of a robot framework file (.rst), a list of dictionaries (or list of lists)?
This should be very straighforward, even for a Robot novice, but I'm struggling to do it.
To make things clear, I need something like this:
`*** Variables ***
#{list_of_dicts} [{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30},
{'name': 'Charlie', 'age': 35}]
*** Keywords ***
Example Keyword
: FOR ${dict} IN #{list_of_dicts}
\ Log ${dict['name']} is ${dict['age']} years old`
I tried varying the posted code in several ways.
Robot Version: 2.9.2
Actually it's not so straightforward. I would suggest to user .yaml file for storing such variables. So in your case:
Persons:
- name: Alice
age: 25
- name: Bob
age: 30
- name: Charlie
age: 35
and latter use it in robot:
*** Settings ***
Variables persons.yaml
*** Test Cases ***
Example Test Case
FOR ${person} IN #{PERSONS}
Log ${person["name"]} is ${person["age"]} years old
END
Regretfully, no, it's painfully not-straightforward using just RF syntax - you have to define each dict as a var, and then include them individually in the list variable:
*** Variables ***
&{dict1} key1=value1 key2=value2
&{dict2} keyY=valueY keyX=valueX
#{list_of_dicts} &{dict1} &{dict2}
There is an alternative though - the inline evaluation technique; it for sure will work inside cases and keywords (I've used it for exactly this purpose - a list of dicts to later serialize as json), but I don't know does it work in the Variables section, you have to try it out.
If it does, it'll look like this - a direct python statement or expression inside ${{}}(double curly brackets):
*** Variables ***
${list_of_dicts} ${{ [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}, {'name': 'Charlie', 'age': 35}] }}
If it doesn't (work there) - you can do it in a keyword, call Set Suite Variable on the variable, and have that keyword called in Suite Setup (that goes under the moto "life is a series of workarounds" :))
Related
I have trouble with assert keys in my code.
No keyword with name 'in {'name': '$.data[0].name'}' found.
my code is
*** Variables ***
&{name} name=$.data[0].name
*** Variables ***
Run keyword if 'name' in ${name} log name is in the log as expected
The way you've defined your test cases (assuming the second *** Variables *** is actually *** Test Cases ***), robot thinks Run keyword if is the name of a test case, and the first keyword is 'name' in ${name}
The solution is to give your test case a name.
There's also a problem that you have two spaces after 'name' which should give you a different error than what you're reporting. Also, the second table should be named *** Test Cases ***.
*** Test Cases ***
Example test case
Run keyword if 'name' in ${name} log name is in the log as expected
You should probably also use $name rather than ${name} so that robot injects the actual variable into the expression.
*** Test Cases ***
Example test case
Run keyword if 'name' in $name log name is in the log as expected
I want to Define variable having dynamic name.
For example
${${FILE}{VAR}} Create List // ${FILE} = TEST, ${VAR} = VAR
Then I want to get variable named '${TESTVAR}'.
Here is my Summarized code...
*** Settings ***
Library SeleniumLibrary
Library ExcelLibrary
Library Collections
*** Variables ***
${VAR}= VAR
*** Keywords ***
Open Document And Assign Variable
[Arguments] ${FILE}
Open Excel Document filename=${FILE} doc_id=doc_var
${${FILE}${VAR}} Create List # It doesn't work ..
The previous answer is not really accurate.
This can be achieved exactly with robot's "Variables inside variables" feature like so:
FOR ${idx} IN RANGE 3
${var_name} = Catenate SEPARATOR=_ var ${idx}
Set Suite Variable ${${var_name}} ${idx}
END
you get:
var_1=1
var_2=2
var_3=3
Please note that variables resolution is happening only for keywords arguments (at least for robot version 3.1.2 that I am using), therefore either one of 'Set test variable', 'Set Suite Variable' or 'Set Global Variable' keywords must be used. The following won't work:
FOR ${idx} IN RANGE 3
${var_name} = Catenate SEPARATOR=_ var ${idx}
${${var_name}} = ${idx}
END
results in:
No keyword with name '${${var_name}} =' found.
For your list case you just need to create a list variable and reassign it to dynamically named variable using the above mentioned keywords
This is currently not possible with Robot Framework. You can use "variables inside variables" to resolve the values of variables (see the documentation on this topic) but not to resolve/set the name of the variable itself.
Though I am afraid that would be confusing anyway. Maybe you can explain your motivations and people can come up with another solution for your problem.
I am trying to use variables from a variables phyton file.
I think I am doing everything as described in the user manual, yet, the variables remain unavailable to me.
This is the variables file
TEST_VAR = 'Michiel'
def get_variables(environment = 'UAT'):
if environment.upper() == 'INT':
ENV = {"NAME": "Bol.com INT",
"BROWSER": "safari",
"URL": "www.bol.com"}
else:
ENV = {"NAME": "Bol.com UAT",
"BROWSER": "firefox",
"URL": "www.bol.com"}
return ENV
I import this like this:
*** Settings ***
Variables Variables.py ${ENVIRONMENT}
Library Selenium2Library
Resource ../PO/MainPage.robot
Resource ../PO/LoginPage.robot
*** Variables ***
${ENVIRONMENT}
*** Keywords ***
Initialize suite
log ${TEST_VAR}
log start testing on ${ENV.NAME}
Start application
open browser ${ENV.URL} ${ENV.BROWSER}
Stop application
close browser
Both files are at the same level in the folder structure.
Yet the variables from the file are not available to me. Not even the normal variable.
Can someone tell me what I am doing wrong here?
Must be something small that I'm forgetting.
Many thanks.
When you use a variable file like this, you don't end up with a variable named ${ENV}. Instead, every key in the dictionary that you return becomes a variable.
From the robot framework user guide (emphasis added):
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 or a Java Map with variable names as keys and variable values as values.
In this specific case that means that you will end up with the variables ${NAME}, ${BROWSER} and ${URL}.
If you want to set a variable named ${ENV}, you will have to make that part of the returned dictionary
# Variables.py
from robot.utils import DotDict
def get_variables(environment="UAT"):
...
return {
"ENV": DotDict(ENV)
}
I'm trying to set up a dictionary as a variable (so I can use it as a Resource and access its values from another file) and there is something that is driving me crazy.
Here is the code I have (just for testing purposes):
*** Settings ***
Documentation Suite description
Library Collections
*** Variables ***
&{SOME DICT} key1=value1 key2=value2
*** Test Cases ***
Dict Test # why $ instead of &?
${RANDOM VAR}= Get From Dictionary ${SOME DICT} key1
Log ${RANDOM VAR} WARN
If I run that, I got the expected result ([ WARN ] value1) BUT the IDE (PyCharm) is complaining about that ${SOME DICT} variable is not defined, and the dictionary declaration is not highlighted the same as variable or a list.
If I change that to &{SOME DICT} the IDE won't complain anymore, but the test fails with the following output:
Dict Test | FAIL |
Keyword 'Collections.Get From Dictionary' got positional argument after named arguments.
That is puzzling me to no end: why I have to use a $ instead of a & if it's a dictionary to make it work? Is there something I am doing wrong and it is just running by luck?
Thanks for any advice or guidance you may have!
Have a look into "Get from Dictionary" libdoc,looks like example is showing the same as your working snippet:
Name: Get From Dictionary
Source: Library (Collections)
Arguments: [dictionary, key]
Returns a value from the given ``dictionary`` based on the given ``key``.
If the given ``key`` cannot be found from the ``dictionary``, this
keyword fails.
The given dictionary is never altered by this keyword.
Example:
| ${value} = | Get From Dictionary | ${D3} | b |
=>
| ${value} = 2
Keyword implementation details are as follows:
try:
return dictionary[key]
except KeyError:
raise RuntimeError("Dictionary does not contain key '%s'." % key)
So indeed, Robot sends representation of dict content and not dict name thus value for key can be returned.
This is the same as direct call in python:
a = {u'key1': u'value1', u'key2': u'value2'}
print(a['key1'])
In the end, libdoc for that KW is not straightforward but your PyCharm plugin for Robot does not work properly in this case.
In RED Robot Editor (Eclipse based), proper case does not rise any warnings in editor, wrong-case provides error marker about arguments (better but still not clear what is exactly wrong. Blame minimalistic libdoc info).
ps. I am lead of RED project to be clear.
Simple Example to Use Key Value Variable in robot framework
Set value to dictionary
Get value from dictionary
&{initValues} Create Dictionary key1=value1 key2=value2
Set To Dictionary ${initValues} key1=newvalue1
Set To Dictionary ${initValues} key2=newvalue2
Set To Dictionary ${initValues} key3=newvalue3
${value} Get From Dictionary ${intialValues} key1
In a robot framework test case I set a variable and then do a process.
Because the setting of the variable is not a very interesting bit of information, I don't want to include that in my report.
| Verifying STUFF |
| | ${endpoint}= | set variable | STUFF
| | Verify
My report contains this:
KEYWORD: ${endpoint} = BuiltIn.Set Variable STUFF
But I would rather not have it there. How can I tell Robot Framework to just not log that line?
------edit------
It looks like this should do it:
pybot --removekeywords NAME:SetVariable testcase.txt
But the Set Variable keywords are still there.
(And yes, I upgraded my robot framework to 2.8.3 to take advantage of this function.)
The best you can do is to use
Set Log Level NONE
but it will still log all the keyword calls, just not anything inside those.
Or if you call a python function which calls another function, then the call to the second function is not logged.
Like this:
*** Settings ***
Library lib.py
*** Test Cases ***
demo
Set Log Level NONE
${a} foo
xyzzy
*** Keywords ***
xyzzy
qwerty
qwerty
No Operation
Log 123
and lib.py being like this:
def foo():
abc = bar()
return abc
def bar():
c = 1
print c
return c
The problem is that when you assign a variable like ${var} = Keyword, the name of the keyword in Robot Framework outputs is ${var} = Keyword, not Keyword as you would expect. If your keyword is from a library or a resource file, its name will also be included like ${var} = MyLibrary.Keyword. The latter is a feature but the former is a bug that is hopefully fixed in RF 2.9.
An easy workaround for the keyword name, for now, including the variable name is using wildcards. Something like this ought to work for you:
--RemoveKeywords 'name:* = BuiltIn.Set Variable'
You can use --removekeywords or --flattenkeywords option on pybot to remove the content of keyword So if you have e.g. keyword "foo" that contains lot's of logging keywords, you can set "--flattenkeywords name:foo" option to pybot, and In the log you'll only see the primary keyword, but no keywords inside it.
http://robotframework.googlecode.com/hg/doc/userguide/RobotFrameworkUserGuide.html?r=2.8.3#removing-and-flattening-keywords
If you use a python library, the following monkey-patching works for me:
from robot.libraries.BuiltIn import BuiltIn
from robot.output.logger import LOGGER
import types
def _nothing(*args, **kwargs):
pass
def disable_keyword_logging(self):
self._logging_methods = (LOGGER.start_keyword, LOGGER.end_keyword)
LOGGER.start_keyword = types.MethodType(_nothing,LOGGER)
LOGGER.end_keyword = types.MethodType(_nothing,LOGGER)
def enable_keyword_logging(self):
LOGGER.start_keyword, LOGGER.end_keyword = self._logging_methods
Then when this script is run:
Disable keyword logging
Log Hello world
Enable keyword logging
the "Log" keyword is not logged to the output but the output is.
If you really want nothing (also no debug/info/warn information logged by the called keywords), you will still have to set the log level to "NONE".
Robot Framework doesn't log "global" variables as part of a variable table. Global is in quotation marks because Set Global Variable actually is logged, but if you initialize your variable like so...
*** Variables ***
${endpoint} stuff
*** Keywords ***
...then it will not be in the Log. Additionally, if you don't want anyone to see the variable at all if they're just looking at the front end of your testing suite, you can bury it in a Resource file and the call the Resource file.
Robot Framework logs your Set Variable keywords and results because Set Variable implies that you're setting a variable dynamically and might be setting it based on the result of a keyword, in which case you'd probably want to know what the result of the keyword is. If you're just creating a static variable, then no extra work beyond the table is required. Is a dynamic variable a required part of your code?