Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating user keywords with programmatic API #5119

Open
Tattoo opened this issue Apr 24, 2024 · 4 comments
Open

Creating user keywords with programmatic API #5119

Tattoo opened this issue Apr 24, 2024 · 4 comments

Comments

@Tattoo
Copy link
Member

Tattoo commented Apr 24, 2024

We have a case where we want to produce different output.xml's. Best way to do bunch of these is to programmatically create different test suites and then run them. However, currently the API only allows you to create test cases whose body is composed entirely of keywords in existing libraries or resource files; it is not possible to create user keyword programmatically.

What we would like to be able to do:

from robot.api import TestSuite

for index in range(10):
    suite = TestSuite('Example Suite')
    test = suite.tests.create('Example Test')
    kw = test.body.create_keyword('Example User Keyword')
    kw.create_keyword('Pass Execution', 'msg')  # this is not currently possible

    suite.run(output=f'output-{index}.xml')
@kkotenko
Copy link
Contributor

Would your scenario be solved by any of these?

  1. Create a resource file with arguments embedded in the keyword name, load said resource file and overwrite the variable by whatever you are generating dynamically

  2. Another approach would be to write your own keyword library, and overwrite the keyword name to use embedded arguments like so.

If not, could you say why these don't help?

@Tattoo
Copy link
Member Author

Tattoo commented Apr 25, 2024

@kkotenko ,

I don't even need embedded arguments, I can just add my keywords to a resource file or a library:

# res.resource
*** Keywords ***
Example user keyword
    [Arguments]    ${arg}
    Pass execution    msg
# gen.py
from robot.api import TestSuite

for index in range(10):
    suite = TestSuite('Example Suite')
    suite.resource.imports.resource('res.resource')
    test = suite.tests.create('Example Test')
    kw = test.body.create_keyword('Example User Keyword', args=['my arg'])

    suite.run(output=f'output-{index}.xml')

But the point here is that this is cumbersome, compared to doing this directly from API.

@DimonLavron
Copy link

DimonLavron commented May 1, 2024

@Tattoo hi!

First of all - thank you for this issue. I started using robot framework recently, especially using programmatic API approach, so it helped me with a better understanding of programmatic API overall.

From my experience so far, I found out that all user keywords related to suite are stored in suite.resource.keywords, so you can easily add your user keywords there, for example:

from robot.api import TestSuite
from robot.running import UserKeyword

for index in range(10):
    suite = TestSuite('Example Suite')
    user_keyword = UserKeyword('Example User Keyword', args=('${arg}',))
    user_keyword.body.create_keyword('Pass Execution', args=('msg',))
    suite.resource.keywords.append(user_keyword)
    test = suite.tests.create('Example Test')
    test.body.create_keyword('Example User Keyword', args=('my arg',))

    suite.run(output=f'output-{index}.xml')

or you can pass your user keyword as dict:

from robot.api import TestSuite

for index in range(10):
    suite = TestSuite('Example Suite')
    suite.resource.keywords.append({
        "name": 'Example User Keyword',
        "args": ('${arg}',),
        "body": [
            {
                "name": 'Pass Execution',
                "args": ('msg',),
            },
        ],
    })
    test = suite.tests.create('Example Test')
    test.body.create_keyword('Example User Keyword', args=('my arg',))

    suite.run(output=f'output-{index}.xml')

I hope that I understand you correctly and it'll be helpful for you. Let me know if I misunderstand you, maybe I can find another solution that suits better for your needs!

@pekkaklarck
Copy link
Member

It is true that it isn't currently possible to define a higher level keyword with child keywords in the execution model. Basically a keyword in the execution model represents a keyword call with name and arguments. The keyword to actually run is resolved during execution and can either be a user keyword with child keywords or a library keyword.

Being able to define higher level keywords directly would be convenient in some cases. In addition to making it easier to programmatically create tests with suitable abstraction levels, it would make it easier for library keywords and listeners to create keywords with child keywords. We already have some other related enhancements initially planned to be done in RF 8, so I add this issue to its initial scope as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants