I have a test file which checks for the presence of all key elements on every page of the app (one Scenario per page). However, the app is fairly complex and has different types of users (admin, regular, etc.) and I want to be able to go through the same pages.robot file with every type of user (and maybe have some if statements in that pages.robot file for every type of user) but I'm not sure how I should do it. I'm guessing I should be using a Resource File and set a global userType variable with admin, regular, etc. and run the pages.robot file multiple times (once per user type) but I'm not sure how to set up the Resource File and the userType variable.
Any ideas on how the Resource File should look like and then how to run the same file for every type of user?
You can store your test user configuration/properties in a resource file (say test_properties.txt) as below:
=== test_properties.txt ===
| *** Variables *** |
| ${tp_app_url} | http://yourapp.com |
| ${tp_browser} | firefox |
| ###### user roles to test with - admin, non-admin, regular |
| ${tp_user_type} | admin |
| ###### test users |
| ${tp_admin_user} | admin#app.com |
| ${tp_admin_password} | admin#123 |
| ${tp_regular_user} | regular#app.com |
| ${tp_regular_password} | regular#123 |
Here, the user role/type with which you want to test your application is defined as:
| ###### user roles to test with - admin, regular |
| ${tp_user_type} | admin |
Your test suite file can then import above resource file as below:
=== testsuite.txt ===
| *** settings *** |
| Library | Selenium2Library |
| Resource | test_properties.txt |
| *** test cases *** |
| Validate Page Controls |
| | Open Browser To Login Page | ${tp_user_type} |
| | Page Controls Should be Visible | ${tp_user_type} |
| *** keywords *** |
| Open Browser To Login Page |
| | [Arguments] | ${user_type} |
| | Open Browser | ${tp_app_url} | ${tp_browser} |
| | Input Username | ${tp_${user_type}_user} |
| | Input Password | ${tp_${user_type}_password} |
| | Submit Credentials |
| | Title Should Be | Welcome Page |
| Input Username |
| | [Arguments] | ${username} |
| | Input Text | username_field | ${username} |
| Input Password |
| | [Arguments] | ${password} |
| | Input Text | password_field | ${password} |
| Submit Credentials |
| | Click Button | login_button |
| Page Controls Should be Visible |
| | [Arguments] | ${user_type} |
Your code related to validating the page controls could reside in the keyword Page Controls Should be Visible which will perform the checks based on the user type argument.
Note: Test user's userId and password variables are formed here by embedding the user type variable as: ${tp_${user_type}_user} which in turn gets evaluated as ${tp_admin_user} in our case.
During execution, you can pass the value of ${tp_user_type} on command line, and it override the value set in the resource file.
pybot --variable tp_user_type:non-admin path/to/your/testfile
If you want to run the same tests with multiple user types, you can create a batch file like:
pybot --variable tp_user_type:non-admin path/to/your/testfile
pybot --variable tp_user_type:admin path/to/your/testfile
pybot --variable tp_user_type:regular path/to/your/testfile
I'm sure there will be a better solution than this for your problem. Ideally, the keywords defined above in the test suite file should reside in a resource file. You can also create a data-driven test to run your template keyword (which validates page controls) for each user type.
Related
When I prepare for my exam, I meet the following statement:
If file1 and file2 are hard linked, and two processes open file1 and file2,
their read/write pointer keeps the same.
Which, according to the answer (no explanation), is wrong. So I searched google, and found something different.
This link: https://www.usna.edu/Users/cs/wcbrown/courses/IC221/classes/L09/Class.html Says the read/write pointer is in the (system wide) open file table.
But this link http://www.cs.kent.edu/~walker/classes/os.f08/lectures/Walker-11.pdf
Says the pointer is in the per process file table.
Which one is true?
IHMO, the read/write offset clearly has to be a per process property. You could easily crash other proceses if this was a system wide per file property. This is my understang, but I'd rather have this confirmed by an informed source.
I took a look at the 1986 AT&T book "The design of the Unix Operating System" by Maurice J. Bach, which I consider a informed source.
In topic 2.2.1 An Overview of the File Subsytem it sais:
... Inodes are stored in the file system ... The kernel reads them
into an in-core inode table when manipulating files ... The kernel
contains two other data structures, the file table and the user
file descriptor table. The file table is a global kernel
structure, but the user file descriptor table is allcated per
process ... The file table keeps track of the (read/write) byte
offset ...
This would contradict my statement. But then, clarification can be read in topic 5.1 OPEN, pages 92ff. Figure 5.3 shows an example of a process having done three opens, two of them being for the same file, /x/y/z (I simplfy the naming here, and in the illustration below).
User File
Descriptor Table File Table inode Table
+--------------+ +------------+ +------------+
0| | | | | |
+--------------+ | . | | . |
1| | | . | | . |
+--------------+ | . | | . |
2| | +------------+ | |
+--------------+ +-->| read offset|----+ | |
3| | | +------------+ | | |
+--------------+ | | | | +------------+
4| |---+ | . | +->| inode of |
+--------------+ | . | +--->| /x/y/z |
5| |----+ | . | | +------------+
+--------------+ | +------------+ | | . |
6| |-+ +->| read |----+ | . |
+--------------+ | +------------+ | | | . |
| . | | | . | | | +------------+
| . | | | . | | +->| inode of |
| | | | . | | | /a/b |
+--------------+ | +------------+ | +------------+
+---->|write offset|--+ | . |
+------------+ | . |
| . | | . |
| . | | . |
+------------+ +------------+
The final answer is in the text following figure 5.3 on page 94:
Figure 5.3 shows the relationship between the inode table, file
table, and user file descriptor table structures. Each open
returns a file descriptor to the process, and the corresponding entry
in the user file descriptor table points to a unique entry in the
kernel file table even though one file (/x/y/z) is opened twice.
To answer your question: The read/write offset is kept in the kernel file table, not in a per process table, but a unique entry is allocated upon each open().
But, why is there a kernel file table? After all, the read/write offsets could have been stored in the per process user file descriptor table, instead of in a kernel table, couldn't they?
To understand why there is a kernel file table, think of what the dup() and fork() functiones do with respect to file descriptors: They duplicate the state of an open file. Under a new file descriptor in the same process, dup(), or under the same file descriptor (number) but in a duplicated user file descriptor table in the new (child) process. In both cases, duplicating the state of an open file includes the read/write offset. So for these cases, more than one file descriptor will point to a single file table entry.
I am attempting to use the DataDriver package https://pypi.org/project/robotframework-datadriver/ with Robot Framework to generate a test report from a csv file generated in a test run. Here's the contents of the file:
${testid},${crc},${rrc}
100,1,0
101,1,1
102,0,1
The robot file is:
| *** Settings *** |
| Library | DataDriver | file=cr-run.csv | encoding=utf-8
| Test Template | Check Capture Replay Record
| *** Test Case ***
| Check Capture Replay Record ${testid}
| *** Keywords ***
| Check Capture Replay Record
| | [Arguments] | ${testid}
| | ... | ${crc}
| | ... | ${rrc}
| | Should Be Equal As Integers | ${crc} | ${rrc}
The error is Variable '${testid}' not found.
Datadriver works fine for other examples. I have tried many variations and read available docs, but I am stumped. Any suggestions would be appreciated.
I would understand how to properly display logs of a Python process executed in Roboframework.
Let's suppose that ${result1.stdout} is this one:
*INFO:1536834347873* ciao ciao
*INFO:1536834347883* ciao ciao2
Is it possibile to transform them in two robotframework logs with the right date? If I use the "Log keyword" they will have the keywork execution timestamp...
Rr
Note: I'm executing the python script with "start process". I need this because I need to run in parallel multiple scripts
| | Start Process | python .${/}files${/}testPython.py | alias=First | shell=yes | stderr=/tmp/provaerr1.log | stdout=/tmp/prova1.log |
| | ${result1}= | Wait For Process | First |
| | Log | ${result1.stdout}
|
I am new to Robotframework.
I am trying to see if there is a reusable concept in Robotframework. I want to create a login class and use it in my other test case to login. How can I do this in Robotframework?
Can we create functions in Robotframework and use them in test cases? Any simple example would be help.
The way you do this in robot framework is to create a reusable keyword.
For example, your keyword might look like this:
*** Keywords ***
| Log in to our application with
| | [Arguments] | ${username} | ${password}
| | Input text | id=username | ${username}
| | Input password | id=password | ${password}
| | Click button | id=submit_button
You could then use it in a test case like this:
*** Settings ***
| Library | Selenium2Library
| Suite Setup | Open browser | ${APP_ROOT} | ${BROWSER}
| Suite Teardown | Close all browsers
*** Test Cases ***
| Example test case
| | Log in to our application with | test_user | S3cr3tPa55w0rd
| | Page should contain | Welcome back, test_user
You don't have to put this all in one file. You can put the keywords in a resource file, and import it into as many test suites as you want.
The below is rewarded with a complaint that Remove Directory requires 1 or 2 arguments and I gave it none. I'm using 2.6.3, and dcsLshLocation is a variable (and adding an x in front doesn't change the error). I'm using the Java version of all this.
*** Settings ***
| Documentation | http://jira.basistech.net:8080/browse/JEST-226
| Resource | src/main/resources/jug-shared-keywords.txt
| Force Tags | integration |
| Suite Precondition | Run Keywords |
| | ... | Validate SUT Installations |
| | ... | Launch Derby Server |
| | ... | Copy file ${jddInstallDir}/conf/jdd-conf-basic.xml to ${jddInstallDir}/conf/jdd-conf.xml
| | ... | Remove Directory | ${dcsLshLocation} |
| Suite Teardown | Run Keywords | Shutdown Derby
| Test Timeout | 20 minutes
When this question was originally written, Run Keywords could only run keywords that do not take arguments. That is no longer true. From the documentation:
Starting from Robot Framework 2.7.6, 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.
The code in the question can thus be expressed like this:
| Suite Precondition | Run Keywords |
| | ... | Validate SUT Installations
| | ... | AND | Launch Derby Server
| | ... | AND | Copy file ${jddInstallDir}/conf/jdd-conf-basic.xml to ${jddInstallDir}/conf/jdd-conf.xml
| | ... | AND | Remove Directory | ${dcsLshLocation}
The following is the original answer to the question, which others may still find useful. It is still relevant for versions of robot framework prior to 2.7.6.
When you use Run Keywords, you cannot run keywords that take arguments. Admittedly the documentation is a bit unclear, but this is what it says:
User keywords must nevertheless be used if the executed keywords need
to take arguments.
What it should say is that, when you use Run Keywords, each argument is the name of a keyword to run. This keyword cannot take any arguments itself because robot can't know where the arguments for one keyword ends and the next keyword begins.
Remember that ... simply means that the previous row is continued on the next, so while it looks like each row is a separate keyword with arguments, it's not. You example is the same as:
| Suite Precondition | Run Keywords |
| | ... | Validate SUT Installations |
| | ... | Launch Derby Server |
| | ... | Copy file ${jddInstallDir}/conf/jdd-conf-basic.xml to ${jddInstallDir}/conf/jdd-conf.xml
| | ... | Remove Directory |
| | ... | ${dcsLshLocation} |