How to write a loop while in Robot Framework - automated-tests

I make my first simple test case, and I have one problem.
Is it possible write a loop in Robot Framework?
I want to retrieve the value from the address and the address of the modified variable "i". I want to perform until such an address exists, because it is a row in the table.
${f1} A
${f_temp} B
While ${f1} != ${f_temp}
or
While element xpath=//${i} is visible
\ ${F_temp} Get Text xpath=//${i}
\ ${i} ${i}+1
\ Run Keyword And Continue On Failure Should be equal ${f_temp} ${f1}
Any ideas?

I'm updating my answer because modern Robot Framework does have a while loop.
The old answer, do not use this:
Robot Framework does not have a while loop. You must use the FOR-loop and "exit for loop if" keywords to exit. It will run in a finite time, but if you select a large enough number in range, it is close enough for practical purposes.
*** Test Cases ***
For Test
FOR ${i} IN RANGE 999999
Exit For Loop If ${i} == 9
Log ${i}
END
Log Exited

You might be looking for the Wait Until Keyword Succeeds keyword, which enables you to do a similar construction to a while loop. It is much more readable than FOR cycles with conditional exiting.
You then use your custom keyword, which fails when you need to end the "loop".

This are other kinds of FOR Loops in Robot Framework, I have this on my own notes and its very helpfull.
FOR Loop with Upper Bounds Range
[Documentation] This gives us a 0 based range
FOR ${Index} IN RANGE 5
Do Something ${Index}
${RANDOM_STRING} = Generate Random String ${Index}
Log ${RANDOM_STRING}
END
FOR Loop with Start and Finish Range
[Documentation] No longer a 0 based range because I provided start
FOR ${Index} IN RANGE 1 4
Do Something ${Index}
${RANDOM_STRING} = Generate Random String ${Index}
Log ${RANDOM_STRING}
END
FOR Loop with Start, Finish, and Step Range
[Documentation] The counter will jump by 2 each time ("step" value = 2)
FOR ${Index} IN RANGE 1 10 2
Do Something ${Index}
${RANDOM_STRING} = Generate Random String ${Index}
Log ${RANDOM_STRING}
END
#index for elements in for
${index} = Set Variable 0
FOR ${col} IN #{cols}
${colum} Format String css:div[class='v-widget v-has-caption v-caption-on-top'] table[aria-rowcount='{0}'] tbody tr:nth-of-type({1}) td:nth-of-type(10) ${r_count} ${col}
Click element ${colum}
press Keys none ${net_config.broadcast}
Press Keys none TAB
Press Keys none ${net_config.${index}}
${index}= Evaluate ${index} + 1
END
#-------
FOR Loop with List
#{ITEMS} = Create List Item 1 Item 2 Item 3
FOR ${MyItem} IN #{ITEMS}
Log ${MyItem}
END
Exit a FOR Loop
#{ITEMS} = Create List Item 1 Item 2 Item 3 Item 4
FOR ${MyItem} IN #{ITEMS}
Log ${MyItem}
Run Keyword If "${MyItem}" == "Item 3" Exit For Loop
Log Didn't exit yet
END
Log Now we're out of the loop

As the above answer said, Robot doesn't support native WHILE loop.
But this one may help if you insist.
https://github.com/robotframework/robotframework/issues/3235

Related

How to keep the memory usage limited in a for loop with robot framework

(1) The test suite with installation & running instructions:
https://github.com/TeddyTeddy/robot-fw-rest-instance-library-tests-v2
(2) The test suite is testing a locally running JSON RESTFUL API server:
https://github.com/typicode/json-server
The DB file for the server (i.e. db.json) is at the root of (1). The server reads the file and creates the API endpoints based on it.
An example run of the server:
(base) ~/Python/Robot/robot-fw-rest-instance-library-tests-v2$ json-server --watch db.json
\{^_^}/ hi!
Loading db.json
Done
Resources
http://localhost:3000/posts
http://localhost:3000/comments
http://localhost:3000/albums
http://localhost:3000/photos
http://localhost:3000/users
http://localhost:3000/todos
(3) With the given db.json, you can make the following request to the server:
GET /posts?_start=<start_index>&_end=<end_index>
where _start is inclusive and _end is exclusive. Note that start_index starts from 0 just like in Array.Slice method.
(4) To be able to comprehensively test (3), i wrote the following Robot Test Case, which is provided in (1):
Slicing Posts With All Possible Start And End Combinations
[Documentation] Referring to the API documentation:
... GET /posts?_start=20&_end=30
... where _start is inclusive and _end is exclusive
... This test case make the above API call with all possible combinations of _start and _end values.
... For each call, the test case fetches expected_posts from database for the same _start and _end.
... It then compares the expected_posts with observed_posts. It also calculates the expected length
... of observed_posts and compares that with the observed length of observed_posts
[Tags] read-tested slicing run-me-only
FOR ${start_index} IN RANGE ${0} ${NUMBER_OF_POSTS+10}
FOR ${end_index} IN RANGE ${start_index+1} ${NUMBER_OF_POSTS + 10 +1}
Log To Console start_index:${start_index}
Log To Console end_index:${end_index}
# note that start_index starts from zero when posts are fetched from database
${expected_posts} = Fetch Posts From Database ${start_index} ${end_index}
# note that start_index starts from 0 too when posts are fetched via API call
# test call
${observed_posts} = Get Sliced Posts ${start_index} ${end_index}
Should Be Equal ${expected_posts} ${observed_posts}
# note that start_index is between [0, NUMBER_OF_POSTS-1]
# and end_index is between [start_index+1, start_index+NUMBER_OF_POSTS]
# we expect observed_posts to be a non-empty list at least containing 1 item
${observed_length} = Get Length ${observed_posts}
# calculate expected_length of the observed_posts list
IF ${end_index} < ${NUMBER_OF_POSTS}
${expected_length} = Evaluate $end_index-$start_index
ELSE IF ${end_index} >= ${NUMBER_OF_POSTS} and ${start_index} < ${NUMBER_OF_POSTS}
${expected_length} = Evaluate $NUMBER_OF_POSTS-$start_index
ELSE
${expected_length} = Set Variable ${0}
END
Should Be Equal ${expected_length} ${observed_length}
Free Memory ${expected_posts} # (*)
Free Memory ${observed_posts} # (*)
END
Reload Library REST # (**)
END
Note that when you follow the instruction to run the test suite via ./run, you will only execute this test case (because of --include run-me-only tag in run command).
The problem
As the test case runs, the amount of memory Robot & RESTInstance use grows to gigabyte levels in a few minutes.
The Question
How can I prevent this from happening?
How can I free the memory used in inner loop's iteration?
My failed attempts to fix the problem
I added the codes marked with (*) into the test case with the following custom keyword:
#keyword
def free_memory(reference):
del reference
Note also that I use RESTInstance library to make the GET call:
Get Sliced Posts
[Documentation] start_index starts from 1 as we fetch from the API now
[Arguments] ${start_index} ${end_index}
GET /posts?_start=${start_index}&_end=${end_index}
${posts} = Output response body
[Return] ${posts}
AFAIK, RESTInstance library keeps a list of instance objects:
https://asyrjasalo.github.io/RESTinstance/#Rest%20Instances
So, this list is growing by adding an instance object per API call. So, I tried:
Reload Library REST # (**)
in the test case, once the iteration with the outermost FOR loop ended. I thought the list would be destroyed & re-created as we reload the library, but the memory consumption kept rising still.

How to loop on a table column?

Badly need your help. In Vehicle ID column, I would like to find a vehicle and once it finds it, it will click on it... How can I do that in Robot Framework? What approach should i be using?
For looping in table you can use xpath easily:
*** Test Cases ***
Stackoverflow Test
[Tags] #InDevelop
Go To https://www.w3schools.com/html/html_tables.asp
Wait Until Element Is Visible id=customers ${global_timeout}
:FOR ${index} IN RANGE 2 8
\ Wait Until Element Is Visible xpath=//*[#id="customers"]/tbody/tr[${index}]/td[1] ${global_timeout}
\ ${var} = Get Text xpath=//*[#id="customers"]/tbody/tr[${index}]/td[1]
\ Log ${var}
In order to click the correct element, you probably need to compare the variable content with your expected value. That can be done this way:
${areYouMyLine} = Run Keyword and Return Status Should Be Equal As Strings ${var} Island Trading
Run Keyword If ${areYouMyLine} Click Elementxpath=//*[#id="customers"]/tbody/tr[${index}]/td[1]
And also don't forget to Exit your For Loop since you found your element.
Exit For Loop
However this is not the best practice. You probably should go to your product team asking for some data attributes which will help you to find your line. Alternatively, if you know your table content, put it into a list and use For In Loop instead. Good stuff about loops can be found here: https://blog.codecentric.de/en/2013/05/robot-framework-tutorial-loops-conditional-execution-and-more/

Running a block of code in until loop Robot Framework

I have a problem in writing a loop in Robot Framework for a block of code.
This code firstly check some values (Minimum and Current), then compare them, and then increase another value (Quantity) by input text. I would like this block of code to be executed UNTIL the condition that Current is greater than Minimum is fulfilled.
How should I write such kind of condition?
Thanks in advance.
${Minimum}= Get Table Cell xpath=... 5 3
${Current}= Get Table Cell xpath=... 5 4
${status} ${value}= Run Keyword And Ignore Error
... Should be true ${Current} > ${Minimum}
${quantity}= Get Value xpath=
... Run Keyword If '${status}' == 'FAIL'
... Input Text xpath=${quantity+10}
Ok, I manage to do this with simple FOR loop and EXIT FOR LOOP in ELSE condition.
: FOR ${i} IN RANGE 1 999
${BoxesMinimum}= Get Table Cell xpath=//someid 5 3
${BoxesCurrent}= Get Table Cell xpath=//someid 5 4
${status} ${value}= Run Keyword and Ignore Error
... Should be true ${BoxesCurrent} > ${BoxesMinimum}
${quantity}= Get Value xpath=//someid
Run Keyword If '${status}' == 'FAIL'
... Input Text xpath=//someid ${quantity+10}
... ELSE Exit for loop

Run a test case Multiple times and display the pass and fail count under test statistics

How to run a particular test case multiple times and display the pass and fail count under Test Statistics?
Below is the current code I have to run a test case multiple times. (The test case is implemented in a keyword and called)
*** Test Cases ***
Testcase
repeat keyword 5 Run Keyword And Continue On Failure Execute
*** Keywords ***
Execute
log Hello world!
The code is run from cmd using "pybot testcase.robot"
This code runs the test multiple times but I'm not getting the final pass/fail count in the logs.
I need to manually count the pass and fail test case repetitions.
So what modifications should I do to get the data automatically and should be seen in Test Statistics of the log also.
Instead of using "Repeat Keyword", use For loop.
Use "Run Keyword And Return Status" instead of "Run Keyword And Continue On Failure ".
*** Test Cases ***
Test Me
${fail}= Set Variable 0
:FOR ${index} IN RANGE 5
\ ${passed}= Run Keyword and Return Status Execute
\ Continue For Loop If ${passed}
\ ${fail}= ${fail} + 1
${success}= Set Variable 5 - ${fail}
Log Many Success: ${success}
Log Many fail: ${fail}

Maximum number of retry attempts

I encountered a freezing test but actually it was stuck in a retry loop.
Wait Until Keyword Succeeds | 60 sec | 12 sec
The first parameter is the timeout for an attempt and the second is retry interval. However, if the task is something like "Xpath Should Match X Times" on a large data set it might never succeed in given time and next attempt starts from scratch again.
Is there way to limit the maximum number of retry attempts in this kind of situation?
Your situation is a bit strange because theoretically there is no such thing as "infinite retry loop" with Wait Until Keyword Succeeds because the first parameter is not "timeout for an attempt" but rather "global timeout for all the attempts". So in your case, it would try every 12 seconds and stop after 60 secs elapsed. Maybe you should reconsider the value you use with this information.
To answer your question, there is no way (AFAIK) to give a max number of attempts. I had such a need for some keywords and I came up with my own custom keyword:
Run_keyword_n_times_and_stop_if_success
[Arguments] ${keyword} ${number_tries}
:FOR ${index} IN RANGE ${number_tries}
\ ${result} ${error_message} = Run Keyword And Ignore Error ${keyword}
\ Pass Execution If '${result}' == 'PASS' keyword execution was successful
Fail ${error_message}
This works only with keywords having no arguments, but maybe that could be helpful for you (either because you don't have args, or because you could elaborate on that first version)
Thanks for the Retry keyword. To use it with a keyword with arguments.
Run Keyword N Times And Stop If Success
[Arguments] ${number_tries} ${keyword} #{args}
: FOR ${index} IN RANGE ${number_tries}
\ ${result} ${error_message} = Run Keyword And Ignore Error ${keyword} #{args}
\ Pass Execution If '${result}' == 'PASS' keyword execution was successful
Fail ${errorLog_message}
Sample usage:
#{args} Create List #{User} ${Url} ${Browser}
Run Keyword N Times And Stop If Success 5 Login #{args}
Since April 2015, this has been implemented as an argument for the keyword.
An example of usage could be seen as:
Wait Until Keyword Succeeds | 5x | 30 sec | Flaky Keyword
More information on the keyword is available in the BuiltIn documentation.

Resources