# Copyright 2008-2015 Nokia Networks
# Copyright 2016- Robot Framework Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from robot.errors import DataError
from robot.model import Statistics
from .executionerrors import ExecutionErrors
from .model import TestSuite
[docs]class Result(object):
"""Test execution results.
Can be created based on XML output files using the
:func:`~.resultbuilder.ExecutionResult`
factory method. Also returned by the
:meth:`robot.running.TestSuite.run <robot.running.model.TestSuite.run>`
method.
"""
def __init__(self, source=None, root_suite=None, errors=None, rpa=None):
#: Path to the XML file where results are read from.
self.source = source
#: Hierarchical execution results as a
#: :class:`~.result.model.TestSuite` object.
self.suite = root_suite or TestSuite()
#: Execution errors as an
#: :class:`~.executionerrors.ExecutionErrors` object.
self.errors = errors or ExecutionErrors()
self.generated_by_robot = True
self._status_rc = True
self._stat_config = {}
self.rpa = rpa
@property
def statistics(self):
"""Test execution statistics.
Statistics are an instance of
:class:`~robot.model.statistics.Statistics` that is created based
on the contained ``suite`` and possible
:func:`configuration <configure>`.
Statistics are created every time this property is accessed. Saving
them to a variable is thus often a good idea to avoid re-creating
them unnecessarily::
from robot.api import ExecutionResult
result = ExecutionResult('output.xml')
result.configure(stat_config={'suite_stat_level': 2,
'tag_stat_combine': 'tagANDanother'})
stats = result.statistics
print stats.total.critical.failed
print stats.total.critical.passed
print stats.tags.combined[0].total
"""
return Statistics(self.suite, rpa=self.rpa, **self._stat_config)
@property
def return_code(self):
"""Return code (integer) of test execution.
By default returns the number of failed critical tests (max 250),
but can be :func:`configured <configure>` to always return 0.
"""
if self._status_rc:
return min(self.suite.statistics.critical.failed, 250)
return 0
[docs] def save(self, path=None):
"""Save results as a new output XML file.
:param path: Path to save results to. If omitted, overwrites the
original file.
"""
from robot.reporting.outputwriter import OutputWriter
self.visit(OutputWriter(path or self.source, rpa=self.rpa))
[docs] def visit(self, visitor):
"""An entry point to visit the whole result object.
:param visitor: An instance of :class:`~.visitor.ResultVisitor`.
Visitors can gather information, modify results, etc. See
:mod:`~robot.result` package for a simple usage example.
Notice that it is also possible to call :meth:`result.suite.visit
<robot.result.testsuite.TestSuite.visit>` if there is no need to
visit the contained ``statistics`` or ``errors``.
"""
visitor.visit_result(self)
[docs] def handle_suite_teardown_failures(self):
"""Internal usage only."""
if self.generated_by_robot:
self.suite.handle_suite_teardown_failures()
[docs] def set_execution_mode(self, other):
"""Set execution mode based on other result. Internal usage only."""
if other.rpa is None:
pass
elif self.rpa is None:
self.rpa = other.rpa
elif self.rpa is not other.rpa:
this, that = ('task', 'test') if other.rpa else ('test', 'task')
raise DataError("Conflicting execution modes. File '%s' has %ss "
"but files parsed earlier have %ss. Use '--rpa' "
"or '--norpa' options to set the execution mode "
"explicitly." % (other.source, this, that))
[docs]class CombinedResult(Result):
"""Combined results of multiple test executions."""
def __init__(self, results=None):
Result.__init__(self)
for result in results or ():
self.add_result(result)
[docs] def add_result(self, other):
self.set_execution_mode(other)
self.suite.suites.append(other.suite)
self.errors.add(other.errors)