Source code for haas.suite

# -*- coding: utf-8 -*-
# Copyright (c) 2013-2014 Simon Jagoe
# All rights reserved.
#
# This software may be modified and distributed under the terms
# of the 3-clause BSD license.  See the LICENSE.txt file for details.
from __future__ import absolute_import, unicode_literals

import logging
import sys
from .error_holder import ErrorHolder

logger = logging.getLogger(__name__)


[docs]def find_test_cases(suite): """Generate a list of all test cases contained in a test suite. Parameters ---------- suite : haas.suite.TestSuite The test suite from which to generate the test case list. """ try: iter(suite) except TypeError: yield suite else: for test in suite: for test_ in find_test_cases(test): yield test_
class _TestSuiteState(object): def __init__(self, result): self._result = result self._previous_class = None self._module_setup_failed = False self._class_setup_failed = False def _run_setup(self, item, setup_name, error_name): setup = getattr(item, setup_name, lambda: None) try: setup() except Exception: error = '{0} ({1})'.format(setup_name, error_name) self._result.addError(ErrorHolder(error), sys.exc_info()) return False return True def _setup_module(self, module_name): if self._previous_class is not None: previous_module = self._previous_class.__module__ if previous_module == module_name: return self._teardown_module(previous_module) module = sys.modules.get(module_name) if module is None: return logger.debug('Set up module: %r', module_name) self._module_setup_failed = not self._run_setup( module, 'setUpModule', module_name) def _setup_class(self, current_class): previous_class = self._previous_class if previous_class == current_class: logger.debug('Class has not changed; not setting up class %r', current_class) return if self._module_setup_failed: logger.debug('Module setup failed; not setting up class %r', previous_class) return if getattr(current_class, '__unittest_skip__', False): logger.debug('Class skipped; not setting up class %r', current_class) return logger.debug('Set up class: %r', current_class) self._class_setup_failed = not self._run_setup( current_class, 'setUpClass', current_class.__name__) def setup(self, test): if isinstance(test, TestSuite): return True logger.debug('Setup module and class for %r', test) current_class = test.__class__ module = current_class.__module__ self._teardown_previous_class(current_class) self._setup_module(module) self._setup_class(current_class) self._previous_class = current_class return not (self._class_setup_failed or self._module_setup_failed) def _teardown_previous_class(self, current_class): previous_class = self._previous_class if previous_class is None: logger.debug('No previous class to tear down') return if current_class == self._previous_class: logger.debug('Class has not changed; not tearing down class %r', previous_class) return if self._class_setup_failed: logger.debug( 'Previous class setup failed; not tearing down class %r', previous_class) self._class_setup_failed = False return if self._module_setup_failed: logger.debug('Module setup failed; not tearing down class %r', previous_class) return if getattr(previous_class, '__unittest_skip__', False): logger.debug('Previous class skipped; not tearing down class %r', previous_class) return logger.debug('Tear down previous class: %r', previous_class) self._run_setup( previous_class, 'tearDownClass', previous_class.__name__) def _teardown_module(self, module_name): if self._module_setup_failed: logger.debug('Module setup failed; not tearing down module %r', module_name) self._module_setup_failed = False return module = sys.modules.get(module_name) if module is None: return self._run_setup(module, 'tearDownModule', module_name) def teardown(self): if self._previous_class is None: return self._teardown_previous_class(None) previous_module = self._previous_class.__module__ self._teardown_module(previous_module)
[docs]class TestSuite(object): """A ``TestSuite`` is a container of test cases and allows executing many test cases while managing the state of the overall suite. """ def __init__(self, tests=()): self._tests = tuple(tests) def __iter__(self): return iter(self._tests) def __eq__(self, other): if not isinstance(other, TestSuite): return NotImplemented return list(self) == list(other) def __ne__(self, other): return not (self == other) def __call__(self, *args, **kwds): """Run all tests in the suite. Parameters ---------- result : unittest.result.TestResult """ return self.run(*args, **kwds)
[docs] def run(self, result, _state=None): """Run all tests in the suite. Parameters ---------- result : unittest.result.TestResult """ if _state is None: state = _TestSuiteState(result) else: state = _state kwargs = {} for test in self: if result.shouldStop: break if state.setup(test): if isinstance(test, TestSuite): kwargs = {'_state': state} logger.debug('Running test %r', test) test(result, **kwargs) if _state is None: state.teardown() return result
[docs] def countTestCases(self): """Return the total number of tests contained in this suite. """ return sum(test.countTestCases() for test in self)
def __repr__(self): return '<{0} number_of_tests={1!r}>'.format( type(self).__name__, self.countTestCases())