123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- """nose unittest.TestCase subclasses. It is not necessary to subclass these
- classes when writing tests; they are used internally by nose.loader.TestLoader
- to create test cases from test functions and methods in test classes.
- """
- import logging
- import sys
- import unittest
- from inspect import isfunction
- from nose.config import Config
- from nose.failure import Failure # for backwards compatibility
- from nose.util import resolve_name, test_address, try_run
- log = logging.getLogger(__name__)
- __all__ = ['Test']
- class Test(unittest.TestCase):
- """The universal test case wrapper.
- When a plugin sees a test, it will always see an instance of this
- class. To access the actual test case that will be run, access the
- test property of the nose.case.Test instance.
- """
- __test__ = False # do not collect
- def __init__(self, test, config=None, resultProxy=None):
- # sanity check
- if not callable(test):
- raise TypeError("nose.case.Test called with argument %r that "
- "is not callable. A callable is required."
- % test)
- self.test = test
- if config is None:
- config = Config()
- self.config = config
- self.tbinfo = None
- self.capturedOutput = None
- self.resultProxy = resultProxy
- self.plugins = config.plugins
- self.passed = None
- unittest.TestCase.__init__(self)
- def __call__(self, *arg, **kwarg):
- return self.run(*arg, **kwarg)
- def __str__(self):
- name = self.plugins.testName(self)
- if name is not None:
- return name
- return str(self.test)
- def __repr__(self):
- return "Test(%r)" % self.test
- def afterTest(self, result):
- """Called after test is complete (after result.stopTest)
- """
- try:
- afterTest = result.afterTest
- except AttributeError:
- pass
- else:
- afterTest(self.test)
- def beforeTest(self, result):
- """Called before test is run (before result.startTest)
- """
- try:
- beforeTest = result.beforeTest
- except AttributeError:
- pass
- else:
- beforeTest(self.test)
- def exc_info(self):
- """Extract exception info.
- """
- exc, exv, tb = sys.exc_info()
- return (exc, exv, tb)
- def id(self):
- """Get a short(er) description of the test
- """
- return self.test.id()
- def address(self):
- """Return a round-trip name for this test, a name that can be
- fed back as input to loadTestByName and (assuming the same
- plugin configuration) result in the loading of this test.
- """
- if hasattr(self.test, 'address'):
- return self.test.address()
- else:
- # not a nose case
- return test_address(self.test)
- def _context(self):
- try:
- return self.test.context
- except AttributeError:
- pass
- try:
- return self.test.__class__
- except AttributeError:
- pass
- try:
- return resolve_name(self.test.__module__)
- except AttributeError:
- pass
- return None
- context = property(_context, None, None,
- """Get the context object of this test (if any).""")
- def run(self, result):
- """Modified run for the test wrapper.
- From here we don't call result.startTest or stopTest or
- addSuccess. The wrapper calls addError/addFailure only if its
- own setup or teardown fails, or running the wrapped test fails
- (eg, if the wrapped "test" is not callable).
- Two additional methods are called, beforeTest and
- afterTest. These give plugins a chance to modify the wrapped
- test before it is called and do cleanup after it is
- called. They are called unconditionally.
- """
- if self.resultProxy:
- result = self.resultProxy(result, self)
- try:
- try:
- self.beforeTest(result)
- self.runTest(result)
- except KeyboardInterrupt:
- raise
- except:
- err = sys.exc_info()
- result.addError(self, err)
- finally:
- self.afterTest(result)
- def runTest(self, result):
- """Run the test. Plugins may alter the test by returning a
- value from prepareTestCase. The value must be callable and
- must accept one argument, the result instance.
- """
- test = self.test
- plug_test = self.config.plugins.prepareTestCase(self)
- if plug_test is not None:
- test = plug_test
- test(result)
- def shortDescription(self):
- desc = self.plugins.describeTest(self)
- if desc is not None:
- return desc
- # work around bug in unittest.TestCase.shortDescription
- # with multiline docstrings.
- test = self.test
- try:
- test._testMethodDoc = test._testMethodDoc.strip()# 2.5
- except AttributeError:
- try:
- # 2.4 and earlier
- test._TestCase__testMethodDoc = \
- test._TestCase__testMethodDoc.strip()
- except AttributeError:
- pass
- # 2.7 compat: shortDescription() always returns something
- # which is a change from 2.6 and below, and breaks the
- # testName plugin call.
- try:
- desc = self.test.shortDescription()
- except Exception:
- # this is probably caused by a problem in test.__str__() and is
- # only triggered by python 3.1's unittest!
- pass
- try:
- if desc == str(self.test):
- return
- except Exception:
- # If str() triggers an exception then ignore it.
- # see issue 422
- pass
- return desc
- class TestBase(unittest.TestCase):
- """Common functionality for FunctionTestCase and MethodTestCase.
- """
- __test__ = False # do not collect
- def id(self):
- return str(self)
- def runTest(self):
- self.test(*self.arg)
- def shortDescription(self):
- if hasattr(self.test, 'description'):
- return self.test.description
- func, arg = self._descriptors()
- doc = getattr(func, '__doc__', None)
- if not doc:
- doc = str(self)
- return doc.strip().split("\n")[0].strip()
- class FunctionTestCase(TestBase):
- """TestCase wrapper for test functions.
- Don't use this class directly; it is used internally in nose to
- create test cases for test functions.
- """
- __test__ = False # do not collect
- def __init__(self, test, setUp=None, tearDown=None, arg=tuple(),
- descriptor=None):
- """Initialize the MethodTestCase.
- Required argument:
- * test -- the test function to call.
- Optional arguments:
- * setUp -- function to run at setup.
- * tearDown -- function to run at teardown.
- * arg -- arguments to pass to the test function. This is to support
- generator functions that yield arguments.
- * descriptor -- the function, other than the test, that should be used
- to construct the test name. This is to support generator functions.
- """
- self.test = test
- self.setUpFunc = setUp
- self.tearDownFunc = tearDown
- self.arg = arg
- self.descriptor = descriptor
- TestBase.__init__(self)
- def address(self):
- """Return a round-trip name for this test, a name that can be
- fed back as input to loadTestByName and (assuming the same
- plugin configuration) result in the loading of this test.
- """
- if self.descriptor is not None:
- return test_address(self.descriptor)
- else:
- return test_address(self.test)
- def _context(self):
- return resolve_name(self.test.__module__)
- context = property(_context, None, None,
- """Get context (module) of this test""")
- def setUp(self):
- """Run any setup function attached to the test function
- """
- if self.setUpFunc:
- self.setUpFunc()
- else:
- names = ('setup', 'setUp', 'setUpFunc')
- try_run(self.test, names)
- def tearDown(self):
- """Run any teardown function attached to the test function
- """
- if self.tearDownFunc:
- self.tearDownFunc()
- else:
- names = ('teardown', 'tearDown', 'tearDownFunc')
- try_run(self.test, names)
- def __str__(self):
- func, arg = self._descriptors()
- if hasattr(func, 'compat_func_name'):
- name = func.compat_func_name
- else:
- name = func.__name__
- name = "%s.%s" % (func.__module__, name)
- if arg:
- name = "%s%s" % (name, arg)
- # FIXME need to include the full dir path to disambiguate
- # in cases where test module of the same name was seen in
- # another directory (old fromDirectory)
- return name
- __repr__ = __str__
- def _descriptors(self):
- """Get the descriptors of the test function: the function and
- arguments that will be used to construct the test name. In
- most cases, this is the function itself and no arguments. For
- tests generated by generator functions, the original
- (generator) function and args passed to the generated function
- are returned.
- """
- if self.descriptor:
- return self.descriptor, self.arg
- else:
- return self.test, self.arg
- class MethodTestCase(TestBase):
- """Test case wrapper for test methods.
- Don't use this class directly; it is used internally in nose to
- create test cases for test methods.
- """
- __test__ = False # do not collect
- def __init__(self, method, test=None, arg=tuple(), descriptor=None):
- """Initialize the MethodTestCase.
- Required argument:
- * method -- the method to call, may be bound or unbound. In either
- case, a new instance of the method's class will be instantiated to
- make the call. Note: In Python 3.x, if using an unbound method, you
- must wrap it using pyversion.unbound_method.
- Optional arguments:
- * test -- the test function to call. If this is passed, it will be
- called instead of getting a new bound method of the same name as the
- desired method from the test instance. This is to support generator
- methods that yield inline functions.
- * arg -- arguments to pass to the test function. This is to support
- generator methods that yield arguments.
- * descriptor -- the function, other than the test, that should be used
- to construct the test name. This is to support generator methods.
- """
- self.method = method
- self.test = test
- self.arg = arg
- self.descriptor = descriptor
- if isfunction(method):
- raise ValueError("Unbound methods must be wrapped using pyversion.unbound_method before passing to MethodTestCase")
- self.cls = method.im_class
- self.inst = self.cls()
- if self.test is None:
- method_name = self.method.__name__
- self.test = getattr(self.inst, method_name)
- TestBase.__init__(self)
- def __str__(self):
- func, arg = self._descriptors()
- if hasattr(func, 'compat_func_name'):
- name = func.compat_func_name
- else:
- name = func.__name__
- name = "%s.%s.%s" % (self.cls.__module__,
- self.cls.__name__,
- name)
- if arg:
- name = "%s%s" % (name, arg)
- return name
- __repr__ = __str__
- def address(self):
- """Return a round-trip name for this test, a name that can be
- fed back as input to loadTestByName and (assuming the same
- plugin configuration) result in the loading of this test.
- """
- if self.descriptor is not None:
- return test_address(self.descriptor)
- else:
- return test_address(self.method)
- def _context(self):
- return self.cls
- context = property(_context, None, None,
- """Get context (class) of this test""")
- def setUp(self):
- try_run(self.inst, ('setup', 'setUp'))
- def tearDown(self):
- try_run(self.inst, ('teardown', 'tearDown'))
- def _descriptors(self):
- """Get the descriptors of the test method: the method and
- arguments that will be used to construct the test name. In
- most cases, this is the method itself and no arguments. For
- tests generated by generator methods, the original
- (generator) method and args passed to the generated method
- or function are returned.
- """
- if self.descriptor:
- return self.descriptor, self.arg
- else:
- return self.method, self.arg
|