General information
I am using an acceptance testing framework (robot framework) and it has an API which allows you to 'visit' suites and tests before execution.
Specific goal
The framework does not save the original suites name (a.k.a. tests.my_test). If you wanted to run that test twice with different names it will throw out the tests component and become new_name.my_test. I wanted to be able to preserve that information so that while viewing it can have descriptive names, but while searching the suite trees I could still find the original test names and rerun.
Questions to people unfamiliar with the framework
I wanted to piggyback off of their work to stay as compatible with the framework as possible. The selection of rerunned tests is here. It includes a function gather_failed_tests
which uses class GatherFailedTests. Since, that native feature of rerunfailed and my feature of rerunrenamedtests can't coexist I chose to simply monkeypatch the GatherFailedTests class to inherit from my class, which fixes the names before it would gather the tests.
Is that a dangerous idea anyway? Should I copy all the source for the function gather_failed_tests
and rename them in their entirety? It's a maintainability vs stability problem. I either can monkey patch a minimal component and hope I get any fixes added to the function or surrounding framework or I can have to manually update the whole chain.
I feel like there is a more efficient way to go through the iterable suites. suite_obj.suites returns an iterable of suites. However the initial top level suite itself also needs to be searched. Is there a way to collapse config_suites
and config_all_suites
simply?
It is ultimately a tree of suites and I need to handle the first element in each branch that has the originallongname
in metadata.
Questions for anyone who knows robot
I'm unhappy with wiping out the parent when I am configuring a non-root suite test.parent.parent = None
. I'm uncertain if why that method doesn't just configure the parent's criticality instead of failing, but regardless of how it functions is there a better way to alter the longname property without destroying info?
from robot.api import SuiteVisitor
from robot.conf import gatherfailed
class rename(SuiteVisitor):
"""Store the original longname so that rerunning can happen even with virtually reorganized tests."""
def __init__(self, new_name):
self.new_name = new_name
def start_suite(self, suite):
originallongname = suite.longname
suite.metadata.setdefault('originallongname', originallongname)
suite.configure(name=self.new_name)
class resetname(SuiteVisitor):
def config_test(self, suite):
originallongname = suite.metadata['originallongname']
try:
suite.configure(name=originallongname)
# Critically setting from non-root error
except TypeError:
for test in suite.tests:
test.parent.name = originallongname
test.parent.parent = None
def config_all_suites(self, suite):
for suite in suite.suites:
try:
self.config_test(suite)
except KeyError:
self.config_suites(suite)
def config_suites(self, suite):
try:
self.config_test(suite)
except KeyError:
self.config_all_suites(suite)
def start_suite(self, suite):
self.config_suites(suite)
class RenameThenGatherFailedTests(resetname):
def __init__(self):
self.tests = []
def visit_test(self, test):
if not test.passed:
self.tests.append(test.longname)
def visit_keyword(self, kw):
pass
gatherfailed.GatherFailedTests = RenameThenGatherFailedTests
class rerunrenamedtests(SuiteVisitor):
def __init__(self, output):
self.output = output
def start_suite(self, suite):
tests = gatherfailed.gather_failed_tests(self.output)
suite.filter(included_tests=tests)
If it would help to see how this would be used you could see here.