Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is a keyword in Robot Framework?

I couldn't find that explained anywhere. Even in the tutorial, where keywords are introduced, it doesn't explain how I will benefit from that concept.

So to make my question clear: Say I have a client and a server that I programmed. I want to use Robot Framework to test them work together. Where do "keywords" fit here? Can this be explained in simple and abstract testing terms?

PS: Explaining additional concepts, such as libraries and variables (albeit they might seem obvious), is highly appreciated.

like image 347
The Quantum Physicist Avatar asked Feb 17 '17 21:02

The Quantum Physicist


2 Answers

Overview

Think of a keyword as a single test step. Just as a test is conceptually made up of many steps, a robot test is made up of many keywords. Keywords are the foundation upon which all robot tests are built.

There are generic keywords provided by robot, and there are special-purpose keywords that you can create yourself. The real power of robot framework is when you create your own keywords so that tests can focus on the test logic rather than the underlying implementation.

For example, let's consider what an acceptance test for logging in to your server might be. From the perspective of an agile product owner or lead designer, it might look something like this:

  1. Open a browser to Super Website 2000!
  2. Enter a valid username
  3. Enter a valid password
  4. Click the "Go" button
  5. You should be on the dashboard page

This might be literally what the product owner adds as acceptance criteria on a story card or in a ticket tracking system. Wouldn't it be nice if that was an actual test which someone could run?

Example test case

Each one of those steps could be considered a keyword. One of the great things about robot is that you can write a test that looks almost identical to the original specification:

*** Test Cases ***
Login of an existing customer
    [Setup]     Open a browser to Super Website 2000!
    [Teardown]  close all browser windows

    Enter a valid username
    Enter a valid password
    Click the GO button
    You should be on the dashboard page

Keyword Implementation Example

To make this test case run, you will need to define these keywords since robot doesn't know what "Open a browser to Super Website 2000!" means. You can write them in python or several other languages, or you can write them by combining existing keywords.

For example, the first few keywords might be implemented using Selenium2Library keywords like so:

*** Settings ***
Library    Selenium2Library

*** Variables ***
${ROOT}     http://super.website2000.com
${BROWSER}  chrome

*** Keywords ***
Open a browser to Super Website 2000!
    # this is a pre-defined Selenium2Library keyword
    Open browser  ${ROOT}    ${BROWSER}

Enter a valid username
    # these are pre-defined Selenium2Library keywords
    wait until element is visible    id=username_input
    input text    id=username_input  Test User #1

Enter a valid password
    # these are pre-defined Selenium2Library keywords
    wait until element is visible      id=password_input
    input text    id=password_input    LetMeIn!

As you can see, you can use keywords to make very readable test cases. Keywords can be designed using other keywords, or you can write keywords in a programming language.

Alternative example without custom keywords

Of course, you don't have to write keywords like this. You could use the Selenium2Library keywords directly in your test, which would make your test look something like this:

*** Test Cases  ***
Login of an existing customer
    [Setup]      Open browser  ${ROOT}    ${BROWSER}
    [Teardown]   close all browsers

    wait until element is visible      id=username_input
    input text    id=username_input    Test User #1
    wait until element is visible      id=password_input
    input text    id=password_input    LetMeIn!
    wait until element is enabled      id=submit_button
    click button  id=submit_button
    wait until element is visible      id=//div[@class='dashboard']
    location should be  ${ROOT}/dashboard

Personally I think the first version of the test is much more readable, at the expense of having to maintain some custom keywords.

Advantages of custom keywords

By using keywords, you are able to hide the details of the web page implementation so that you can focus on the logic of the test. Plus, multiple tests can reuse the same keywords.

The actual details of the implementation (element ids, URLs, etc) can all be embedded within the keywords. If these details change, you don't have to change any of your test cases. Instead, you change the keywords and your tests will continue to run. Imagine if the developers changed the ids of the input to username_form_field and password_form_field -- do you want to edit every test case that has to log in, or do you want to edit one or two keywords that all tests share?

Variables

Variables in robot framework are very powerful. For example, you can define the root URL of your site in one place instead of hard-coding it in every test. For most production sites you have to run tests with two, three, or even more URLs. For example, you might have a local dev box, a qa box, a staging box, and a production box.

Robot lets you override variables on the command line or in argument files. That means you can create one set of tests that work on multiple systems. For example, to run your tests using firefox on staging you might do this (split across multiple lines for clarity):

$ pybot \
   --variable ROOT:http://staging.example.com \
   --variable BROWSER:firefox \
   /path/to/tests

To run the exact same tests on QA1 with chrome you could do this:

$ pybot \
   --variable ROOT:http://qa1.example.com \
   --variable BROWSER:chrome \
   /path/to/tests

Libraries

Simply put, keywords are organized into libraries. Robot comes with many libraries, and there are many more available on the internet.

Libraries may be written in the robot syntax like in these examples, but libraries may also be written in programming languages such as python and java. using a programming language makes it possible to do complex logic, using the robot language lets you more easily combine existing keywords into new keywords.

Keywords in an agile environment

If you are working on a scrum team, the keyword driven approach can help the team become very efficient. For example, if your testers are not highly skilled, the developers can create a library of keywords for interacting with the test so that the testers don't have to worry about the details of the page.

On the other hand, if you have highly technical testers, they can take on the task of writing the keywords themselves so that the developers can spend more time working on the actual product.

In both scenarios, the keyword-driven approach enables the qa and development teams to work together to create a high quality product.

like image 162
Bryan Oakley Avatar answered Nov 16 '22 03:11

Bryan Oakley


The other answer is very good and up to the point for the question's body - for user acceptance testing, behaviour driven testing, that's absolutely so.
I'd like to give a slightly different angle - keywords are analogues to functions/methods in software programming.

When talking with developers or other technical persons, it has always helped me to say "keywords are just functions" and that would set the correct context for in-depth talks. To piggyback on one of the examples above, this Robotframwork keyword:

Enter a valid username
    # these are pre-defined Selenium2Library keywords
    wait until element is visible    id=username_input
    input text    id=username_input  Test User #1

would look almost the same as a python method in POM (or java, or c#, or - you name it):

def enter_a_valid_username(self):
    self.driver_instance.wait_until_element_is_visible('id=username')
    self.driver_instance.input_text('id=username_input', 'Test User #1')

Passing values to a keyword is calling a function with arguments, and so is getting a value back:

Attempt to login with user and password
    [Documentation]   Enters the provided user and password, clicks the "Login" button, and returns boolean True/False is the user logged in.
    [Arguments]    ${user}    ${pass}
    wait until element is visible    id=username_input
    input text    id=username_input  ${user}
    input text    id=password_input  ${pass}
    click button  id=submit_button

    ${success}=   Run Keyword And Return Status     Dashboard Page Should Be Opened
    [Return]    ${success}

The analogue as a method:

def attempt_login(self, user, pass):
    self.driver_instance.wait_until_element_is_visible('id=username')
    self.driver_instance.input_text('id=username_input', user)
    self.driver_instance.input_text('id=password_input', pass)
    self.driver_instance.click_button('id=submit_button')

    try:
        self.dashboard_is_opened()
        return True
    except IncorrectPageException:
        return False

It needs to be stressed the keywords created in Robotframework syntax are functions, not methods - they are not a part of an object that stores state, thus their cross-communication is through shared variables in the current scope; this pushes to procedural, not object-orientented programming.


The beauty of Robotframework really shines when the keywords are going to higer-level abstractions - e.g. the top level keyword The account is terminated has in its implementstion calls to the keywords The account is not present in the Users page and No DB record for the account, each of them having lower and lower level keyword calls in them.

The account is terminated
 |
 \--> | The account is not present in the Users page
 |    \--> | Go to the Users page
 |         \--> | ${location}=    Get Location
 |         |    | Run Keyword If  '${location}' != '${url users page}'    Go To  '${url users page}'
 |         |    | The Users Page Is Opened
 |         |     \-->  | # checks the currently opened page is Users 
 |         |           | ...
 |         | ${users}=  Get All Users
 |         | ...
 |
 \--> | No DB record for the account
           | ${users}=  Get All DB Accounts 
           |            \--> | Connect To The DB
           |                 | ${DB data}=  Execute Query  SELECT * FROM users;  # etc
           |                 | ...
           | Should Not Contain   ${users}   ${the user}  msg=The user is still present!

This greatly helps the maintainability, implementation changes and debugging, while at the same time the top level usage remains unchanged; this approach is also a property of a good software design, helping get the analogy keywords are functions across to software developers.

like image 20
Todor Minakov Avatar answered Nov 16 '22 03:11

Todor Minakov