Search code examples
pythonrobotframework

create robot framework Test Case dynamically on running test suite


I got a very specific scenario, where I'm inserting some data to the database(e.g. let's say 3 inserts and each one of them returns some ID) and based on a return value I want to create dynamically test cases for those return values E.g.

*** Variables ***
@{result}    ${EMPTY}

*** Test Cases ***
Some dummy sql inserts
    ${result}    Insert sql statements    dt1    dt2    dt3 #e.g. return ['123', '456', '789']

Verify some ids
    # NOPE, sorry i can't use [Template] because each iteration is not marked on a report as a "TEST" but as a "VAR"
    Verify if ids exist somewhere ${result} #This keyword execution should create another 3 test cases, one for each item from ${result} list

*** Keywords ***
Insert sql statement
    [Arguments]    @{data}
    Create List    ${result}
    FOR    ${elem}    IN    @{data}
        ${return_id}    SomeLib.Execute SQL    INSERT INTO some_table(some_id) VALUES (${elem})
        Append To List    ${result}    ${return_id}
    END
    [Return]    ${result}

Verify if ids exist somewhere
    [Arguments]    ${some_list_of_ids}
    FOR    ${id}    IN    @{some_list_of_ids}
        So some stuff on ${id}
    END

I was trying to figure out how to do that by reffering to robot API documentation but without any success. Can you please tell/advise if it's feasible, if so, than how can I achieve that.
So far I've figured out that there might be 2 ways of doing this:

  1. by creating a listener
  2. by creating own keyword

In both cases, I have to put the logic there, but can't figure out how to create test cases on-the-fly.
Help, please? :)

P.S. Some examples are more than welcome. Thanks in advance


Solution

  • There is a blog post with a answer for you: https://gerg.dev/2018/09/dynamically-create-test-cases-with-robot-framework/

    As you suggested the solution is to create a listener so you can add tests dynamically. Just carefully read the post as there are some constrains as when you can and cannot create tests (during the execution process). Also, the post was for 3.x framework and for 4.x you need to make a tiny change in the class, by replacing: tc.keywords.create(name=kwname, args=args) with: tc.body.create_keyword(name=kwname, args=args).

    Example on how to implement this:

    demo.robot:

    *** Settings ***
    Library           DynamicTestCases.py
    
    *** Test Cases ***
    Create Dynamic Test Cases
        @{TestNamesList}    Create List    "Test 1"    "Test 2"    "Test 3"
        FOR    ${element}    IN    @{TestNamesList}
            Add Test Case    ${element}   Keyword To Execute
        END
    
    *** Keywords ***
    Keyword To Execute
        Log    This is executed for each test!
    

    DynamicTestCases.py contents (basic copy from the url I posted + the changed line):

    from __future__ import print_function
    from robot.running.model import TestSuite
    
    
    class DynamicTestCases(object):
        ROBOT_LISTENER_API_VERSION = 3
        ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
    
        def __init__(self):
            self.ROBOT_LIBRARY_LISTENER = self
            self.current_suite = None
    
        def _start_suite(self, suite, result):
            # save current suite so that we can modify it later
            self.current_suite = suite
    
        def add_test_case(self, name, kwname, *args):
            """Adds a test case to the current suite
    
            'name' is the test case name
            'kwname' is the keyword to call
            '*args' are the arguments to pass to the keyword
    
            Example:
                add_test_case  Example Test Case  
                ...  log  hello, world  WARN
            """
            tc = self.current_suite.tests.create(name=name)
            #tc.keywords.create(name=kwname, args=args) #deprecated in 4.0
            tc.body.create_keyword(name=kwname, args=args)
    
    # To get our class to load, the module needs to have a class
    # with the same name of a module. This makes that happen:
    globals()[__name__] = DynamicTestCases
    

    This is a small example how to make it work. If for example you want to give a variable to the keyword, just add the argument:

    *** Settings ***
    Library           DynamicTestCases.py
    
    *** Test Cases ***
    Create Dynamic Test Cases
        @{TestNamesList}    Create List    "Test 1"    "Test 2"    "Test 3"
        FOR    ${element}    IN    @{TestNamesList}
            Add Test Case    ${element}   Keyword To Execute    ${element}
        END
    
    *** Keywords ***
    Keyword To Execute
        [Arguments]    ${variable}
        Log    The variable sent to the test was: ${variable}