You cannot do this directly. Each suite and test you run has whatever setup/teardown that was specified for them in the data. Good news is that you can pretty easily create a pre-run modifier to adjust setups and teardowns as needed.
Thanks, can you elaborate how I would approach this? I’ve not seen mention of pre-run modifiers anywhere in the documentation (if you can point to it would be great as I often refer back to the doco).
Basically I want to run the Setup once then run the test in a while loop until the while condition is met (in my case end of test run) then run the Teardown.
I would be ok with the suite setup and suite teardown being once and the test setup and test teardown being with every test run.
For details about the model objects you are editing and the visitor interface, you need to study the API docs. Relevant sections ought to be linked from the User Guide
Great! You can use the same API to rename your tests so you don’t get that warning about duplicate tests. That said, I’m not certain is that a useful warning in general. If you don’t like it, please submit an issue and we can consider removing it or making it configurable.
I’m not so worried about the warning, when I get to it i’ll probably rename the tests with iteration nn (nn being the number).
Another question, end_test and end_suite seem to get called before the first test is actually run, is this how it’s supposed to work? the documentation says:
end_suite ( suite )[source]
Called when a suite ends. Default implementation does nothing.
end_test ( test )[source]
Called when a test ends. Default implementation does nothing.
but when I actually run:
% robot --prerunmodifier Repeat.py repeatme.robot
suite: Repeatme
suite.tests: [robot.running.TestCase(name='Repeat Me')]
suite.tests[0]: Repeat Me
test: Repeat Me
test.parent: Repeatme
test.parent.tests: [robot.running.TestCase(name='Repeat Me')]
end suite: Repeatme
==============================================================================
Repeatme
==============================================================================
These were in my end_test
test: Repeat Me
test.parent: Repeatme
test.parent.tests: [robot.running.TestCase(name='Repeat Me')]
Docs seem to be a bit misleading. Visitor is executed for the whole model at once so that start methods are called before visiting possible children and end methods are called after that. Pre-run modifiers are run before test execution starts.
If you want to do something during execution, you need to use listeners. Listener API v3 operates with same model objects as modifiers so similar code works there as well. The major limitation of listener API v3 is that it doesn’t support start/end_keyword methods.
I already have a V2 listener, do I need a V3 listener to access the API for adding tests to the test suite? Or can that be done in the V2 API as well? It doesn’t look like end_test has the test object or end_suite has the tests list object, so I guess I need V3 for this.
Also I know I can pass multiple listeners to the same test but mix a V2 and V3 listener on the same test, or do they all have to be the same version? I guess I’ll find out when I try it.
I successfully ran the V2 and V3 listeners together, and got the trigger to add the test running from end_test which brings me to the next question.
From end_test I have the test object, and from the parent I can get the suite object, which has a metadata object. But how do I access the variables?
I pass some variables in on the command line, when I run the test again I would like to update one of these variables. I looked at the config object of the test but couldn’t see how to get the variables?
I was revisiting this and decided to post a full working example incase it helps someone else.
BTW Thanks @pekkaklarck for all your help with this.
Run Command:
robot --listener TestRepeater.py repeatme.robot
TestRepeater.py
from robot.api import SuiteVisitor
import time
class TestRepeater(SuiteVisitor):
ROBOT_LISTENER_API_VERSION = 3
testname = None
count = 1
def end_test(self, test, result):
# print("test:", test)
# print("test.parent:", test.parent)
# print("test.parent.tests:", test.parent.tests)
if self.count < 5:
self.count += 1
if self.testname is None:
self.testname = test.name
newname = "{} {}".format(self.testname, self.count)
copy = test.copy(name=newname)
test.parent.tests.append(copy)
# test.parent.tests.append(test)
def end_suite(self, suite, result):
# This prevents the error:
# [ ERROR ] Calling method 'end_suite' of listener 'TestRepeater.py' failed: TypeError: end_suite() takes 2 positional arguments but 3 were given
pass
def start_suite(self, suite, result):
# This prevents the error:
# [ ERROR ] Calling method 'start_suite' of listener 'TestRepeater.py' failed: TypeError: start_suite() takes 2 positional arguments but 3 were given
pass
def start_test(self, test, result):
# This prevents the error:
# [ ERROR ] Calling method 'start_test' of listener 'TestRepeater.py' failed: TypeError: start_test() takes 2 positional arguments but 3 were given
pass
repeatme.robot
*** Settings ***
Suite Setup SS keyword
Suite Teardown ST keyword
Test Setup TS keyword
Test Teardown TT keyword
*** Test Cases ***
Repeat Me
${time} = Get Time
Log Repeat Me ${time}
Log To Console Repeat Me ${time}
Sleep 5
*** Keywords ***
SS keyword
Log Suite Setup
Log To Console Suite Setup
TS keyword
Log Test Setup
Log To Console Test Setup
ST keyword
Log Suite Teardown
Log To Console Suite Teardown
TT keyword
Log Test Teardown
Log To Console Test Teardown
@damies13 Hello, i just tried running this and im getting a little different results. i still see the errors that you metnioned above but also the ‘Repeat Me n’ shows up with every iteration. i was hoping you could help me understand whats happening, thanks
Use the examples in my last post, that the final working version,
The errors I was getting was because multiple test had the same name, you can avoid this by renaming the test when you copy it, in my case I just append the counter to the original name and that’s enough.
This example should still work, It’s the foundation for the listener in RFSwarm and is working there for me (ran a build last night and didn’t have any issues with the code based on this example.