Source code for nose2.plugins.loader.parameters

Load tests from parameterized functions and methods.

This plugin implements :func:`getTestCaseNames`,
:func:`loadTestsFromModule`, and :func:`loadTestsFromName` to support
loading tests from parameterized test functions and methods.

To parameterize a function or test case method, use :func:``.

To address a particular parameterized test via a command-line test name,
append a colon (':') followed by the index (*starting from 1*) of the
case you want to execute.

Such And The Parameters Plugin

The parameters plugin can work with the Such DSL, as long as the first argument
of the test function is the "case" argument, followed by the other parameters::

    from import such
    from import params

    with such.A('foo') as it:
        @it.should('do bar')
        def test(case, bar):
            case.assertTrue(isinstance(bar, int))

        @it.should('do bar and extra')
        @params((1, 2), (3, 4) ,(5, 6))
        def testExtraArg(case, bar, foo):
            case.assertTrue(isinstance(bar, int))
            case.assertTrue(isinstance(foo, int))


# This module contains some code copied from unittest2 and other code
# developed in reference to unittest2.
# unittest2 is Copyright (c) 2001-2010 Python Software Foundation; All
# Rights Reserved. See:

import functools
import logging
import sys
import types
import unittest

from nose2 import exceptions, util
from import Plugin
from nose2.plugins.loader.testclasses import MethodTestCase

log = logging.getLogger(__name__)
__unittest = True

class ParamsFunctionCase(unittest.FunctionTestCase):
    def __init__(self, name, func, **args):
        self._funcName = name
        unittest.FunctionTestCase.__init__(self, func, **args)

    def __repr__(self):
        return self._funcName

    id = __str__ = __repr__

[docs]class Parameters(Plugin): """Loader plugin that loads parameterized tests""" alwaysOn = True configSection = "parameters" def registerInSubprocess(self, event): event.pluginClasses.append(self.__class__)
[docs] def getTestCaseNames(self, event): """Generate test case names for all parameterized methods""" log.debug("getTestCaseNames %s", event) names = filter(event.isTestMethod, dir(event.testCase)) testCaseClass = event.testCase for name in names: method = getattr(testCaseClass, name) paramList = getattr(method, "paramList", None) if paramList is None: continue # exclude this method from normal collection event.excludedNames.append(name) # generate the methods to be loaded by the testcase loader self._generate(event, name, method, testCaseClass)
def getTestMethodNames(self, event): return self.getTestCaseNames(event)
[docs] def loadTestsFromModule(self, event): """Load tests from parameterized test functions in the module""" module = event.module def is_test(obj): return obj.__name__.startswith(self.session.testMethodPrefix) and hasattr( obj, "paramList" ) tests = [] for name in dir(module): obj = getattr(module, name) if isinstance(obj, types.FunctionType) and is_test(obj): tests.extend(self._generateFuncTests(obj)) event.extraTests.extend(tests)
[docs] def loadTestsFromName(self, event): """Load parameterized test named on command line""" original_name = name = module = event.module try: result = util.test_from_name(name, module) except (AttributeError, ImportError): event.handled = True return event.loader.failedLoadTests(name, sys.exc_info()) if result is None: # we can't find it - let the default case handle it return parent, obj, fqname, index = result if not hasattr(obj, "paramList"): return if ( index is None and not isinstance(parent, type) and not isinstance(obj, types.FunctionType) ): log.debug("Don't know how to load parameterized tests from %s", obj) return if ( parent and isinstance(parent, type) and issubclass(parent, unittest.TestCase) ): # parameterized method in test case names = self._generate(event, obj.__name__, obj, parent) tests = [parent(n) for n in names] elif parent and isinstance(parent, type): # parameterized method in test class names = self._generate(event, obj.__name__, obj, parent) tests = [MethodTestCase(parent)(name) for name in names] else: # parameterized func tests = list(self._generateFuncTests(obj)) if index is not None: try: tests = [tests[index - 1]] except IndexError: raise exceptions.TestNotFoundError(original_name) suite = event.loader.suiteClass() suite.addTests(tests) event.handled = True return suite
def _generate(self, event, name, method, testCaseClass): names = [] for index, argSet in enumerate_params(method.paramList): method_name = util.name_from_args(name, index, argSet) if not hasattr(testCaseClass, method_name): # not already generated def _method(self, method=method, argSet=argSet): return method(self, *argSet) _method = functools.update_wrapper(_method, method) delattr(_method, "paramList") setattr(testCaseClass, method_name, _method) names.append(method_name) return names def _generateFuncTests(self, obj): args = {} setUp = getattr(obj, "setUp", None) tearDown = getattr(obj, "tearDown", None) if setUp is not None: args["setUp"] = setUp if tearDown is not None: args["tearDown"] = tearDown for index, argSet in enumerate_params(obj.paramList): def func(argSet=argSet, obj=obj): return obj(*argSet) func = functools.update_wrapper(func, obj) delattr(func, "paramList") name = "%s.%s" % (obj.__module__, obj.__name__) func_name = util.name_from_args(name, index, argSet) yield util.transplant_class(ParamsFunctionCase, obj.__module__)( func_name, func, **args )
def enumerate_params(paramList): for index, argSet in enumerate(paramList): if not isinstance(argSet, tuple): argSet = (argSet,) yield index, argSet