How to pass objects to keywords in robot framework?

Sara Sarvi picture Sara Sarvi · Oct 25, 2016 · Viewed 7.3k times · Source

I have a python class MyClass written in file MyClass.py:

class MyClass(object):
    def __init__(self):
        self.myvar = list()

    def setvar(self, val):
        self.myvar = val

    def mymethod(self):
        return self.myvar

I have imported in Robot Framework as below:

Library         MyClass    WITH NAME    my_component

I also have a keyword which call a method of objects which are passed to it:

testing component
    [Arguments]       ${cmp}
    log to console    ************* ${cmp}
    ${result} =       ${cmp}.mymethod

I have multiple objects instantiated from class MyClass and every object has different properties. I want to get their attributes using testing component keyword regardless of the object itself.

When I call testing component passing my_component:

Test Method Call
    testing component    my_component

I get:

No keyword with name '${cmp}.mymethod' found.

If I call it this way in keyword testing component:

${result} =    call method     ${cmp}   mymethod

I get:

Object 'my_component' does not have method 'mymethod'.

I also tried call method my_component mymethod for test and I again got Object 'my_component' does not have method 'mymethod'..

But when I use ${result} = my_component.mymethod, everything works fine.

Answer

Bryan Oakley picture Bryan Oakley · Oct 25, 2016

The literal answer to your question of how to call a method of a python object is that you can use extended variable syntax (eg: ${cmp.mymethod()} or you can use the call method keyword (eg: call method ${cmp} mymethod).

For example, normal scalar variables in robot are python string objects. Thus, we can call methods on them such as lower() and upper(). The following test case shows how you can call these methods on a string, using the two mechanisms I mentioned earlier:

*** Variables ***
${message}    Hello, world    # a python string object

*** Test cases ***
Example
    # Example using "Call method" keyword
    ${lower}=    call method    ${message}    lower
    should be equal    ${lower}    hello, world

    # Example using extended variable syntax
    ${upper}=    set variable    ${message.upper()}
    should be equal    ${upper}    HELLO, WORLD

The problem with your code is your misunderstanding of what my_component and ${cmp} represents. They are not python objects. Rather, it is the name of a robot framework library. Even though under the hood it may exist as a reference to an instance of a class defined in the library, from within the test my_component is simply the name of the library.

This is why my_component.my_method works - my_component is the name of a library, and my_method is the name of a keyword within that library. This is standard robot framework syntax. See Specifying a keyword explicitly in the robot framework user guide.

If you want to be able to pass my_component around as if it were an object, you can use run keyword to run the keywords implemented in that library.

For example, start by creating MyClass.py with the following code:

class MyClass(object):
    def mymethod(self):
        return "Hello, world"

Your code can work if you replace call method with run keyword:

*** Keywords ***
testing component
    [Arguments]       ${cmp}
    log to console    ************* ${cmp}
    ${result} =       run keyword   ${cmp}.mymethod

Finally, if you really want to pass the actual library object around, you can use the built-in keyword Get Library Instance to get the actual library object, which you can then use with Call Method

*** Keywords ***
testing component
    [Arguments]       ${cmp_name}
    ${cmp}=  Get library instance    ${cmp_name}
    log to console    ************* ${cmp}
    ${result} =       call method    ${cmp}    mymethod
    [return]          ${result}

Oddly, the extended variable syntax doesn't work in this case. I don't know why.