class AllureCollectionListener(object): """ Listens to pytest collection-related hooks to generate reports for modules that failed to collect. """ def __init__(self, logdir): self.impl = AllureImpl(logdir) self.fails = [] def pytest_collectreport(self, report): if not report.passed: if report.failed: status = Status.BROKEN else: status = Status.SKIPPED self.fails.append(CollectFail(name=mangle_testnames(report.nodeid.split("::"))[-1], status=status, message=get_exception_message(report), trace=report.longrepr)) def pytest_collection_finish(self): """ Creates a testsuite with collection failures if there were any. """ if self.fails: self.impl.start_suite(name='test_collection_phase', title='Collection phase', description='This is the tests collection phase. Failures are modules that failed to collect.') for fail in self.fails: self.impl.start_case(name=fail.name) self.impl.stop_case(status=fail.status, message=fail.message, trace=fail.trace) self.impl.stop_suite()
class AllureTestListener(object): """ Listens to pytest hooks to generate reports for common tests. """ def __init__(self, logdir, config): self.impl = AllureImpl(logdir) self.config = config # FIXME: maybe we should write explicit wrappers? self.attach = self.impl.attach self.start_step = self.impl.start_step self.stop_step = self.impl.stop_step self.testsuite = None def _stop_case(self, report, status=None): """ Finalizes with important data the test at the top of ``self.stack`` and returns it """ [self.attach(name, contents, AttachmentType.TEXT) for (name, contents) in dict(report.sections).items()] if status in FAILED_STATUSES: self.impl.stop_case(status, message=get_exception_message(report), trace=report.longrepr or report.wasxfail) elif status == Status.SKIPPED: skip_message = type(report.longrepr) == tuple and \ report.longrepr[2] or report.wasxfail trim_msg_len = 89 short_message = skip_message.split('\n')[0][:trim_msg_len] # FIXME: see pytest.runner.pytest_runtest_makereport self.impl.stop_case(status, message=(short_message + '...' * (len(skip_message) > trim_msg_len)), trace=None if short_message == skip_message else skip_message) else: self.impl.stop_case(status) def pytest_runtest_protocol(self, __multicall__, item, nextitem): if not self.testsuite: module = parent_module(item) self.impl.start_suite(name='.'.join(mangle_testnames(module.nodeid.split("::"))), description=module.module.__doc__ or None) self.testsuite = 'Yes' name = '.'.join(mangle_testnames([x.name for x in parent_down_from_module(item)])) self.impl.start_case(name, description=item.function.__doc__, labels=labels_of(item)) result = __multicall__.execute() if not nextitem or parent_module(item) != parent_module(nextitem): self.impl.stop_suite() self.testsuite = None return result def pytest_runtest_logreport(self, report): if report.passed: if report.when == "call": # ignore setup/teardown self._stop_case(report, status=Status.PASSED) elif report.failed: if report.when != "call": self._stop_case(report, status=Status.BROKEN) else: self._stop_case(report, status=Status.FAILED) elif report.skipped: self._stop_case(report, status=Status.SKIPPED) def pytest_runtest_makereport(self, item, call, __multicall__): # @UnusedVariable """ That's the place we inject extra data into the report object from the actual Item. """ report = __multicall__.execute() report.__dict__.update( exception=call.excinfo, result=self.config.hook.pytest_report_teststatus(report=report)[0]) # get the failed/passed/xpassed thingy return report def pytest_sessionfinish(self): if self.testsuite: self.impl.stop_suite() self.testsuite = None
class AllureTestListener(object): """ Listens to pytest hooks to generate reports for common tests. """ def __init__(self, logdir, config): self.impl = AllureImpl(logdir) self.config = config # FIXME: maybe we should write explicit wrappers? self.attach = self.impl.attach self.start_step = self.impl.start_step self.stop_step = self.impl.stop_step self.testsuite = None def _stop_case(self, report, status=None): """ Finalizes with important data the test at the top of ``self.stack`` and returns it """ [ self.attach(name, contents, AttachmentType.TEXT) for (name, contents) in dict(report.sections).items() ] if status in FAILED_STATUSES: self.impl.stop_case(status, message=get_exception_message(report), trace=report.longrepr or report.wasxfail) elif status in SKIPPED_STATUSES: skip_message = type( report.longrepr ) == tuple and report.longrepr[2] or report.wasxfail trim_msg_len = 89 short_message = skip_message.split('\n')[0][:trim_msg_len] # FIXME: see pytest.runner.pytest_runtest_makereport self.impl.stop_case( status, message=(short_message + '...' * (len(skip_message) > trim_msg_len)), trace=status == Status.PENDING and report.longrepr or short_message != skip_message and skip_message or None) else: self.impl.stop_case(status) @pytest.mark.hookwrapper def pytest_runtest_protocol(self, item, nextitem): if not self.testsuite: module = parent_module(item) self.impl.start_suite(name=module.module.__name__, description=module.module.__doc__ or None) self.testsuite = 'Yes' name = '.'.join( mangle_testnames([x.name for x in parent_down_from_module(item)])) self.impl.start_case(name, description=item.function.__doc__, labels=labels_of(item)) yield if not nextitem or parent_module(item) != parent_module(nextitem): self.impl.stop_suite() self.testsuite = None def pytest_runtest_logreport(self, report): if report.passed: if report.when == "call": # ignore setup/teardown self._stop_case(report, status=Status.PASSED) elif report.failed: if report.when != "call": self._stop_case(report, status=Status.BROKEN) else: self._stop_case(report, status=Status.FAILED) elif report.skipped: if hasattr(report, 'wasxfail'): self._stop_case(report, status=Status.PENDING) else: self._stop_case(report, status=Status.CANCELED) @pytest.mark.hookwrapper def pytest_runtest_makereport(self, item, call): """ That's the place we inject extra data into the report object from the actual Item. """ report = yield report.get_result().__dict__.update( exception=call.excinfo, result=self.config.hook.pytest_report_teststatus( report=report.get_result()) [0]) # get the failed/passed/xpassed thingy def pytest_sessionfinish(self): if self.testsuite: self.impl.stop_suite() self.testsuite = None self.impl.store_environment()
class AllureTestListener(object): """ Listens to pytest hooks to generate reports for common tests. """ def __init__(self, logdir, config): self.impl = AllureImpl(logdir) self.config = config # FIXME: maybe we should write explicit wrappers? self.attach = self.impl.attach self.start_step = self.impl.start_step self.stop_step = self.impl.stop_step self.testsuite = None def _stop_case(self, report, status=None): """ Finalizes with important data the test at the top of ``self.stack`` and returns it """ [self.attach(name, contents, AttachmentType.TEXT) for (name, contents) in dict(report.sections).items()] if status in FAILED_STATUSES: self.impl.stop_case(status, message=get_exception_message(report), trace=report.longrepr or report.wasxfail) elif status == Status.SKIPPED: # FIXME: see pytest.runner.pytest_runtest_makereport self.impl.stop_case(status, message='skipped', trace=type(report.longrepr) == tuple and report.longrepr[2] or report.wasxfail) else: self.impl.stop_case(status) def pytest_runtest_protocol(self, __multicall__, item, nextitem): if not self.testsuite: module = parent_module(item) self.impl.start_suite(name='.'.join(mangle_testnames(module.nodeid.split("::"))), description=module.module.__doc__ or None) self.testsuite = 'Yes' name = '.'.join(mangle_testnames([x.name for x in parent_down_from_module(item)])) self.impl.start_case(name, description=item.function.__doc__, severity=severity_of(item)) result = __multicall__.execute() if not nextitem or parent_module(item) != parent_module(nextitem): self.impl.stop_suite() self.testsuite = None return result def pytest_runtest_logreport(self, report): if report.passed: if report.when == "call": # ignore setup/teardown self._stop_case(report, status=Status.PASSED) elif report.failed: if report.when != "call": self._stop_case(report, status=Status.BROKEN) else: self._stop_case(report, status=Status.FAILED) elif report.skipped: self._stop_case(report, status=Status.SKIPPED) def pytest_runtest_makereport(self, item, call, __multicall__): # @UnusedVariable """ That's the place we inject extra data into the report object from the actual Item. """ report = __multicall__.execute() report.__dict__.update( exception=call.excinfo, result=self.config.hook.pytest_report_teststatus(report=report)[0]) # get the failed/passed/xpassed thingy return report def pytest_sessionfinish(self): if self.testsuite: self.impl.stop_suite() self.testsuite = None