parameterized-0.6.1/0000755000076600001200000000000013064260214015141 5ustar woleveradmin00000000000000parameterized-0.6.1/.gitignore0000644000076600001200000000023112425542166017136 0ustar woleveradmin00000000000000*.class *.o *.pyc *.sqlite3 *.sw[op] *~ .DS_Store bin-debug/* bin-release/* bin/* tags *.beam *.dump env/ .env/ *egg-info* misc/ dist/ Icon? .tox build/ parameterized-0.6.1/.hgignore0000644000076600001200000000022412075364747016763 0ustar woleveradmin00000000000000syntax: glob *.class *.o *.pyc *.sqlite3 *.sw[op] *~ .DS_Store bin-debug/* bin-release/* bin/* tags *.beam *.dump env/ *egg-info* dist/ .tox .env32 parameterized-0.6.1/.travis.yml0000644000076600001200000000077312547575106017277 0ustar woleveradmin00000000000000language: python sudo: false env: - TOXENV=py26-nose - TOXENV=py26-nose2 - TOXENV=py26-pytest - TOXENV=py26-unit - TOXENV=py26-unit2 - TOXENV=py27-nose - TOXENV=py27-nose2 - TOXENV=py27-pytest - TOXENV=py27-unit - TOXENV=py27-unit2 - TOXENV=py33-nose - TOXENV=py33-nose2 - TOXENV=py33-pytest - TOXENV=py33-unit - TOXENV=py33-unit2 - TOXENV=pypy-nose - TOXENV=pypy-nose2 - TOXENV=pypy-pytest - TOXENV=pypy-unit - TOXENV=pypy-unit2 install: pip install tox script: tox parameterized-0.6.1/CHANGELOG.txt0000644000076600001200000000462713064257730017213 0ustar woleveradmin000000000000000.6.1 (2017-03-21) * Rename package from nose-parameterized to parameterized. A nose-parameterized package will be released with a deprecation warning. * Rename testcase_func_doc and testcase_func_name methods to doc_func and name_func (a DeprecationWarning will be issued, to be removed in 1.0). * Include parameters in all docstrings, not just `parameterized.expand` docstrings. * Explicitly unwrap iterators and generators before the test run (thanks @chornsby; https://github.com/wolever/nose-parameterized/pull/31) * 0.6.1 instead of 0.6.0 because I'm a dumb and accidentally uploaded the wrong thing to PyPI under version 0.6.0. 0.5.0 (2015-06-09) * Support for nose2, py.test, unittest, and unittest2 (nose2 support thanks to @marek-mazur; https://github.com/wolever/nose-parameterized/pull/26) 0.4.2 (2015-05-18) * Fix bug with expand + empty arguments (thanks @jikamens; https://github.com/wolever/nose-parameterized/pull/25) 0.4.1 (2015-05-17) * Fix bug with expand + empty docstring (thanks @jikamens; https://github.com/wolever/nose-parameterized/pull/24) 0.4.0 (2015-05-11) * Include parameters in ``parameterized.expand`` function docstrings (https://github.com/wolever/nose-parameterized/pull/22; thanks @smspillaz) * Drop Python 3.2 support 0.3.5 (2014-11-05) * Allow the names of test cases generated by ``parameterized.expand`` to be customized. (https://github.com/wolever/nose-parameterized/pull/19; thanks @curtissiemens) 0.3.4 (2014-10-03) * Use ``functools.wraps`` to wrap expanded functions (https://github.com/wolever/nose-parameterized/pull/17; thanks @toumorokoshi) 0.3.3 (2014-01-03) * Replace unsafe characters with "_" in names generated by ``@parameterized.expand``. 0.3.2 (2014-01-02) * Add helpful error message when used with old-style classes. 0.3.1 (2013-08-01) * Fix bug: `nose_parameterized.param` wasn't being imported. 0.3 (2013-05-18) * Add `param` class. * Add explicit support for callable inputs. * Update readme to more throughly describe useage. * Remove un-used test helpers (`setup_logging`, `teardown_logging`, `logged_messages`, `assert_logged`, `assert_no_errors_logged`, `assert_contains`, `assert_not_contains`, `assert_raises`, `imported_from_test`). 0.2 (2013-01-15) * Add Python 3 support parameterized-0.6.1/LICENSE.txt0000644000076600001200000000316112155471213016770 0ustar woleveradmin00000000000000tl;dr: all code code is licensed under simplified BSD, unless stated otherwise. Unless stated otherwise in the source files, all code is copyright 2010 David Wolever . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. The views and conclusions contained in the software and documentation are those of the authors and should not be interpreted as representing official policies, either expressed or implied, of David Wolever. parameterized-0.6.1/misspelling-helper/0000755000076600001200000000000013064260214020744 5ustar woleveradmin00000000000000parameterized-0.6.1/misspelling-helper/nose-parametrized/0000755000076600001200000000000013064260214024375 5ustar woleveradmin00000000000000parameterized-0.6.1/misspelling-helper/nose-parametrized/MANIFEST0000644000076600001200000000006413061614754025537 0ustar woleveradmin00000000000000# file GENERATED by distutils, do NOT edit setup.py parameterized-0.6.1/misspelling-helper/nose-parametrized/setup.py0000644000076600001200000000055213061614700026111 0ustar woleveradmin00000000000000import sys from distutils.core import setup if __name__ == "__main__": if "sdist" not in sys.argv[1:]: raise ValueError("please use the 'nose-parameterized' pypi package instead of 'nose-parametrized'") setup( name="nose-parametrized", version="0.0", description="please use 'nose-parameterized' for installation", ) parameterized-0.6.1/parameterized/0000755000076600001200000000000013064260214017775 5ustar woleveradmin00000000000000parameterized-0.6.1/parameterized/__init__.py0000644000076600001200000000006013064257211022105 0ustar woleveradmin00000000000000from .parameterized import parameterized, param parameterized-0.6.1/parameterized/parameterized.py0000644000076600001200000003417713064253165023226 0ustar woleveradmin00000000000000import re import sys import inspect import warnings from functools import wraps from collections import namedtuple try: from collections import OrderedDict as MaybeOrderedDict except ImportError: MaybeOrderedDict = dict from unittest import TestCase PY3 = sys.version_info[0] == 3 PY2 = sys.version_info[0] == 2 if PY3: def new_instancemethod(f, *args): return f # Python 3 doesn't have an InstanceType, so just use a dummy type. class InstanceType(): pass lzip = lambda *a: list(zip(*a)) text_type = str string_types = str, bytes_type = bytes else: import new new_instancemethod = new.instancemethod from types import InstanceType lzip = zip text_type = unicode bytes_type = str string_types = basestring, _param = namedtuple("param", "args kwargs") class param(_param): """ Represents a single parameter to a test case. For example:: >>> p = param("foo", bar=16) >>> p param("foo", bar=16) >>> p.args ('foo', ) >>> p.kwargs {'bar': 16} Intended to be used as an argument to ``@parameterized``:: @parameterized([ param("foo", bar=16), ]) def test_stuff(foo, bar=16): pass """ def __new__(cls, *args , **kwargs): return _param.__new__(cls, args, kwargs) @classmethod def explicit(cls, args=None, kwargs=None): """ Creates a ``param`` by explicitly specifying ``args`` and ``kwargs``:: >>> param.explicit([1,2,3]) param(*(1, 2, 3)) >>> param.explicit(kwargs={"foo": 42}) param(*(), **{"foo": "42"}) """ args = args or () kwargs = kwargs or {} return cls(*args, **kwargs) @classmethod def from_decorator(cls, args): """ Returns an instance of ``param()`` for ``@parameterized`` argument ``args``:: >>> param.from_decorator((42, )) param(args=(42, ), kwargs={}) >>> param.from_decorator("foo") param(args=("foo", ), kwargs={}) """ if isinstance(args, param): return args if isinstance(args, string_types): args = (args, ) return cls(*args) def __repr__(self): return "param(*%r, **%r)" %self class QuietOrderedDict(MaybeOrderedDict): """ When OrderedDict is available, use it to make sure that the kwargs in doc strings are consistently ordered. """ __str__ = dict.__str__ __repr__ = dict.__repr__ def parameterized_argument_value_pairs(func, p): """Return tuples of parameterized arguments and their values. This is useful if you are writing your own doc_func function and need to know the values for each parameter name:: >>> def func(a, foo=None, bar=42, **kwargs): pass >>> p = param(1, foo=7, extra=99) >>> parameterized_argument_value_pairs(func, p) [("a", 1), ("foo", 7), ("bar", 42), ("**kwargs", {"extra": 99})] If the function's first argument is named ``self`` then it will be ignored:: >>> def func(self, a): pass >>> p = param(1) >>> parameterized_argument_value_pairs(func, p) [("a", 1)] Additionally, empty ``*args`` or ``**kwargs`` will be ignored:: >>> def func(foo, *args): pass >>> p = param(1) >>> parameterized_argument_value_pairs(func, p) [("foo", 1)] >>> p = param(1, 16) >>> parameterized_argument_value_pairs(func, p) [("foo", 1), ("*args", (16, ))] """ argspec = inspect.getargspec(func) arg_offset = 1 if argspec.args[:1] == ["self"] else 0 named_args = argspec.args[arg_offset:] result = lzip(named_args, p.args) named_args = argspec.args[len(result) + arg_offset:] varargs = p.args[len(result):] result.extend([ (name, p.kwargs.get(name, default)) for (name, default) in zip(named_args, argspec.defaults or []) ]) seen_arg_names = set([ n for (n, _) in result ]) keywords = QuietOrderedDict(sorted([ (name, p.kwargs[name]) for name in p.kwargs if name not in seen_arg_names ])) if varargs: result.append(("*%s" %(argspec.varargs, ), tuple(varargs))) if keywords: result.append(("**%s" %(argspec.keywords, ), keywords)) return result def short_repr(x, n=64): """ A shortened repr of ``x`` which is guaranteed to be ``unicode``:: >>> short_repr("foo") u"foo" >>> short_repr("123456789", n=4) u"12...89" """ x_repr = repr(x) if isinstance(x_repr, bytes_type): try: x_repr = text_type(x_repr, "utf-8") except UnicodeDecodeError: x_repr = text_type(x_repr, "latin1") if len(x_repr) > n: x_repr = x_repr[:n//2] + "..." + x_repr[len(x_repr) - n//2:] return x_repr def default_doc_func(func, num, p): if func.__doc__ is None: return None all_args_with_values = parameterized_argument_value_pairs(func, p) # Assumes that the function passed is a bound method. descs = ["%s=%s" %(n, short_repr(v)) for n, v in all_args_with_values] # The documentation might be a multiline string, so split it # and just work with the first string, ignoring the period # at the end if there is one. first, nl, rest = func.__doc__.lstrip().partition("\n") suffix = "" if first.endswith("."): suffix = "." first = first[:-1] args = "%s[with %s]" %(len(first) and " " or "", ", ".join(descs)) return "".join([first.rstrip(), args, suffix, nl, rest]) def default_name_func(func, num, p): base_name = func.__name__ name_suffix = "_%s" %(num, ) if len(p.args) > 0 and isinstance(p.args[0], string_types): name_suffix += "_" + parameterized.to_safe_name(p.args[0]) return base_name + name_suffix class parameterized(object): """ Parameterize a test case:: class TestInt(object): @parameterized([ ("A", 10), ("F", 15), param("10", 42, base=42) ]) def test_int(self, input, expected, base=16): actual = int(input, base=base) assert_equal(actual, expected) @parameterized([ (2, 3, 5) (3, 5, 8), ]) def test_add(a, b, expected): assert_equal(a + b, expected) """ def __init__(self, input, doc_func=None): self.get_input = self.input_as_callable(input) self.doc_func = doc_func or default_doc_func def __call__(self, test_func): self.assert_not_in_testcase_subclass() @wraps(test_func) def wrapper(test_self=None): f = test_func if test_self is not None: # If we are a test method (which we suppose to be true if we # are being passed a "self" argument), we first need to create # an instance method, attach it to the instance of the test # class, then pull it back off to turn it into a bound method. # If we don't do this, Nose gets cranky. f = self.make_bound_method(test_self, test_func) # Note: because nose is so very picky, the more obvious # ``return self.yield_nose_tuples(f)`` won't work here. for nose_tuple in self.yield_nose_tuples(f, wrapper): yield nose_tuple test_func.__name__ = "_helper_for_%s" %(test_func.__name__, ) wrapper.parameterized_input = self.get_input() wrapper.parameterized_func = test_func return wrapper def yield_nose_tuples(self, func, wrapper): original_doc = wrapper.__doc__ for num, args in enumerate(wrapper.parameterized_input): p = param.from_decorator(args) # ... then yield that as a tuple. If those steps aren't # followed precicely, Nose gets upset and doesn't run the test # or doesn't run setup methods. nose_tuple = self.param_as_nose_tuple(func, num, p) nose_func = nose_tuple[0] try: wrapper.__doc__ = nose_func.__doc__ yield nose_tuple finally: wrapper.__doc__ = original_doc def param_as_nose_tuple(self, func, num, p): if p.kwargs: nose_func = wraps(func)(lambda args, kwargs: func(*args, **kwargs)) nose_args = (p.args, p.kwargs) else: nose_func = wraps(func)(lambda *args: func(*args)) nose_args = p.args nose_func.__doc__ = self.doc_func(func, num, p) return (nose_func, ) + nose_args def make_bound_method(self, instance, func): cls = type(instance) if issubclass(cls, InstanceType): raise TypeError(( "@parameterized can't be used with old-style classes, but " "%r has an old-style class. Consider using a new-style " "class, or '@parameterized.expand' " "(see http://stackoverflow.com/q/54867/71522 for more " "information on old-style classes)." ) %(instance, )) im_f = new_instancemethod(func, None, cls) setattr(cls, func.__name__, im_f) return getattr(instance, func.__name__) def assert_not_in_testcase_subclass(self): parent_classes = self._terrible_magic_get_defining_classes() if any(issubclass(cls, TestCase) for cls in parent_classes): raise Exception("Warning: '@parameterized' tests won't work " "inside subclasses of 'TestCase' - use " "'@parameterized.expand' instead") def _terrible_magic_get_defining_classes(self): """ Returns the set of parent classes of the class currently being defined. Will likely only work if called from the ``parameterized`` decorator. This function is entirely @brandon_rhodes's fault, as he suggested the implementation: http://stackoverflow.com/a/8793684/71522 """ stack = inspect.stack() if len(stack) <= 4: return [] frame = stack[4] code_context = frame[4] and frame[4][0].strip() if not (code_context and code_context.startswith("class ")): return [] _, _, parents = code_context.partition("(") parents, _, _ = parents.partition(")") return eval("[" + parents + "]", frame[0].f_globals, frame[0].f_locals) @classmethod def input_as_callable(cls, input): if callable(input): return lambda: cls.check_input_values(input()) input_values = cls.check_input_values(input) return lambda: input_values @classmethod def check_input_values(cls, input_values): # Explicitly convery non-list inputs to a list so that: # 1. A helpful exception will be raised if they aren't iterable, and # 2. Generators are unwrapped exactly once (otherwise `nosetests # --processes=n` has issues; see: # https://github.com/wolever/nose-parameterized/pull/31) if not isinstance(input_values, list): input_values = list(input_values) return input_values @classmethod def expand(cls, input, name_func=None, doc_func=None, **legacy): """ A "brute force" method of parameterizing test cases. Creates new test cases and injects them into the namespace that the wrapped function is being defined in. Useful for parameterizing tests in subclasses of 'UnitTest', where Nose test generators don't work. >>> @parameterized.expand([("foo", 1, 2)]) ... def test_add1(name, input, expected): ... actual = add1(input) ... assert_equal(actual, expected) ... >>> locals() ... 'test_add1_foo_0': ... >>> """ if "testcase_func_name" in legacy: warnings.warn("testcase_func_name= is deprecated; use name_func=", DeprecationWarning, stacklevel=2) if not name_func: name_func = legacy["testcase_func_name"] if "testcase_func_doc" in legacy: warnings.warn("testcase_func_doc= is deprecated; use doc_func=", DeprecationWarning, stacklevel=2) if not doc_func: doc_func = legacy["testcase_func_doc"] doc_func = doc_func or default_doc_func name_func = name_func or default_name_func def parameterized_expand_wrapper(f, instance=None): stack = inspect.stack() frame = stack[1] frame_locals = frame[0].f_locals paramters = cls.input_as_callable(input)() for num, args in enumerate(paramters): p = param.from_decorator(args) name = name_func(f, num, p) frame_locals[name] = cls.param_as_standalone_func(p, f, name) frame_locals[name].__doc__ = doc_func(f, num, p) f.__test__ = False return parameterized_expand_wrapper @classmethod def param_as_standalone_func(cls, p, func, name): @wraps(func) def standalone_func(*a): return func(*(a + p.args), **p.kwargs) standalone_func.__name__ = name # place_as is used by py.test to determine what source file should be # used for this test. standalone_func.place_as = func # Remove __wrapped__ because py.test will try to look at __wrapped__ # to determine which parameters should be used with this test case, # and obviously we don't need it to do any parameterization. try: del standalone_func.__wrapped__ except AttributeError: pass return standalone_func @classmethod def to_safe_name(cls, s): return str(re.sub("[^a-zA-Z0-9_]+", "_", s)) parameterized-0.6.1/parameterized/test.py0000644000076600001200000002204312750153234021333 0ustar woleveradmin00000000000000# coding=utf-8 import inspect from unittest import TestCase from nose.tools import assert_equal from nose.plugins.skip import SkipTest from .parameterized import ( PY3, PY2, parameterized, param, parameterized_argument_value_pairs, short_repr, ) def assert_contains(haystack, needle): if needle not in haystack: raise AssertionError("%r not in %r" %(needle, haystack)) def detect_runner(candidates): for x in reversed(inspect.stack()): frame = x[0] for mod in candidates: frame_mod = frame.f_globals.get("__name__", "") if frame_mod == mod or frame_mod.startswith(mod + "."): return mod return "" runner = detect_runner(["nose", "nose2","unittest", "unittest2"]) UNITTEST = runner.startswith("unittest") NOSE2 = (runner == "nose2") SKIP_FLAGS = { "generator": UNITTEST, # nose2 doesn't run tests on old-style classes under Py2, so don't expect # these tests to run under nose2. "py2nose2": (PY2 and NOSE2), } missing_tests = set() def expect(skip, tests=None): if tests is None: tests = skip skip = None if any(SKIP_FLAGS.get(f) for f in (skip or "").split()): return missing_tests.update(tests) if not (PY2 and NOSE2): missing_tests.update([ ]) test_params = [ (42, ), "foo0", param("foo1"), param("foo2", bar=42), ] expect("generator", [ "test_naked_function('foo0', bar=None)", "test_naked_function('foo1', bar=None)", "test_naked_function('foo2', bar=42)", "test_naked_function(42, bar=None)", ]) @parameterized(test_params) def test_naked_function(foo, bar=None): missing_tests.remove("test_naked_function(%r, bar=%r)" %(foo, bar)) class TestParameterized(object): expect("generator", [ "test_instance_method('foo0', bar=None)", "test_instance_method('foo1', bar=None)", "test_instance_method('foo2', bar=42)", "test_instance_method(42, bar=None)", ]) @parameterized(test_params) def test_instance_method(self, foo, bar=None): missing_tests.remove("test_instance_method(%r, bar=%r)" %(foo, bar)) def custom_naming_func(custom_tag): def custom_naming_func(testcase_func, param_num, param): return testcase_func.__name__ + ('_%s_name_' % custom_tag) + str(param.args[0]) return custom_naming_func class TestParamerizedOnTestCase(TestCase): expect([ "test_on_TestCase('foo0', bar=None)", "test_on_TestCase('foo1', bar=None)", "test_on_TestCase('foo2', bar=42)", "test_on_TestCase(42, bar=None)", ]) @parameterized.expand(test_params) def test_on_TestCase(self, foo, bar=None): missing_tests.remove("test_on_TestCase(%r, bar=%r)" %(foo, bar)) expect([ "test_on_TestCase2_custom_name_42(42, bar=None)", "test_on_TestCase2_custom_name_foo0('foo0', bar=None)", "test_on_TestCase2_custom_name_foo1('foo1', bar=None)", "test_on_TestCase2_custom_name_foo2('foo2', bar=42)", ]) @parameterized.expand(test_params, name_func=custom_naming_func("custom")) def test_on_TestCase2(self, foo, bar=None): stack = inspect.stack() frame = stack[1] frame_locals = frame[0].f_locals nose_test_method_name = frame_locals['a'][0]._testMethodName expected_name = "test_on_TestCase2_custom_name_" + str(foo) assert_equal(nose_test_method_name, expected_name, "Test Method name '%s' did not get customized to expected: '%s'" % (nose_test_method_name, expected_name)) missing_tests.remove("%s(%r, bar=%r)" %(expected_name, foo, bar)) class TestParameterizedExpandDocstring(TestCase): def _assert_docstring(self, expected_docstring, rstrip=False): """ Checks the current test method's docstring. Must be called directly from the test method. """ stack = inspect.stack() f_locals = stack[3][0].f_locals test_method = ( f_locals.get("testMethod") or # Py27 f_locals.get("function") # Py33 ) if test_method is None: raise AssertionError("uh oh, unittest changed a local variable name") actual_docstring = test_method.__doc__ if rstrip: actual_docstring = actual_docstring.rstrip() assert_equal(actual_docstring, expected_docstring) @parameterized.expand([param("foo")], doc_func=lambda f, n, p: "stuff") def test_custom_doc_func(self, foo, bar=None): """Documentation""" self._assert_docstring("stuff") @parameterized.expand([param("foo")]) def test_single_line_docstring(self, foo): """Documentation.""" self._assert_docstring("Documentation [with foo=%r]." %(foo, )) @parameterized.expand([param("foo")]) def test_empty_docstring(self, foo): "" self._assert_docstring("[with foo=%r]" %(foo, )) @parameterized.expand([param("foo")]) def test_multiline_documentation(self, foo): """Documentation. More""" self._assert_docstring( "Documentation [with foo=%r].\n\n" " More" %(foo, ) ) @parameterized.expand([param("foo")]) def test_unicode_docstring(self, foo): u"""Döcumentation.""" self._assert_docstring(u"Döcumentation [with foo=%r]." %(foo, )) @parameterized.expand([param("foo", )]) def test_default_values_get_correct_value(self, foo, bar=12): """Documentation""" self._assert_docstring("Documentation [with foo=%r, bar=%r]" %(foo, bar)) @parameterized.expand([param("foo", )]) def test_with_leading_newline(self, foo, bar=12): """ Documentation """ self._assert_docstring("Documentation [with foo=%r, bar=%r]" %(foo, bar), rstrip=True) def test_warns_when_using_parameterized_with_TestCase(): try: class TestTestCaseWarnsOnBadUseOfParameterized(TestCase): @parameterized([42]) def test_in_subclass_of_TestCase(self, foo): pass except Exception as e: assert_contains(str(e), "parameterized.expand") else: raise AssertionError("Expected exception not raised") expect("generator", [ "test_wrapped_iterable_input('foo')", ]) @parameterized(lambda: iter(["foo"])) def test_wrapped_iterable_input(foo): missing_tests.remove("test_wrapped_iterable_input(%r)" %(foo, )) def test_helpful_error_on_non_iterable_input(): try: for _ in parameterized(lambda: 42)(lambda: None)(): pass except Exception as e: assert_contains(str(e), "is not iterable") else: raise AssertionError("Expected exception not raised") def tearDownModule(): missing = sorted(list(missing_tests)) assert_equal(missing, []) def test_old_style_classes(): if PY3: raise SkipTest("Py3 doesn't have old-style classes") class OldStyleClass: @parameterized(["foo"]) def parameterized_method(self, param): pass try: list(OldStyleClass().parameterized_method()) except TypeError as e: assert_contains(str(e), "new-style") assert_contains(str(e), "parameterized.expand") assert_contains(str(e), "OldStyleClass") else: raise AssertionError("expected TypeError not raised by old-style class") class TestOldStyleClass: expect("py2nose2 generator", [ "test_on_old_style_class('foo')", "test_on_old_style_class('bar')", ]) @parameterized.expand(["foo", "bar"]) def test_old_style_classes(self, param): missing_tests.remove("test_on_old_style_class(%r)" %(param, )) @parameterized([ ("", param(), []), ("*a, **kw", param(), []), ("*a, **kw", param(1, foo=42), [("*a", (1, )), ("**kw", {"foo": 42})]), ("foo", param(1), [("foo", 1)]), ("foo, *a", param(1), [("foo", 1)]), ("foo, *a", param(1, 9), [("foo", 1), ("*a", (9, ))]), ("foo, *a, **kw", param(1, bar=9), [("foo", 1), ("**kw", {"bar": 9})]), ("x=9", param(), [("x", 9)]), ("x=9", param(1), [("x", 1)]), ("x, y=9, *a, **kw", param(1), [("x", 1), ("y", 9)]), ("x, y=9, *a, **kw", param(1, 2), [("x", 1), ("y", 2)]), ("x, y=9, *a, **kw", param(1, 2, 3), [("x", 1), ("y", 2), ("*a", (3, ))]), ("x, y=9, *a, **kw", param(1, y=2), [("x", 1), ("y", 2)]), ("x, y=9, *a, **kw", param(1, z=2), [("x", 1), ("y", 9), ("**kw", {"z": 2})]), ("x, y=9, *a, **kw", param(1, 2, 3, z=3), [("x", 1), ("y", 2), ("*a", (3, )), ("**kw", {"z": 3})]), ]) def test_parameterized_argument_value_pairs(func_params, p, expected): helper = eval("lambda %s: None" %(func_params, )) actual = parameterized_argument_value_pairs(helper, p) assert_equal(actual, expected) @parameterized([ ("abcd", "'abcd'"), ("123456789", "'12...89'"), (123456789, "123...789") # number types do not have quotes, so we can repr more ]) def test_short_repr(input, expected, n=6): assert_equal(short_repr(input, n=n), expected) @parameterized([ ("foo", ), ]) def test_with_docstring(input): """ Docstring! """ pass parameterized-0.6.1/parameterized.egg-info/0000755000076600001200000000000013064260214021467 5ustar woleveradmin00000000000000parameterized-0.6.1/parameterized.egg-info/dependency_links.txt0000644000076600001200000000000113064260214025535 0ustar woleveradmin00000000000000 parameterized-0.6.1/parameterized.egg-info/PKG-INFO0000644000076600001200000003376613064260214022603 0ustar woleveradmin00000000000000Metadata-Version: 1.1 Name: parameterized Version: 0.6.1 Summary: Parameterized testing with any Python test framework Home-page: https://github.com/wolever/parameterized Author: David Wolever Author-email: david@wolever.net License: FreeBSD Description: Parameterized testing with any Python test framework ==================================================== .. image:: https://travis-ci.org/wolever/parameterized.svg?branch=master :target: https://travis-ci.org/wolever/parameterized Parameterized testing in Python sucks. ``parameterized`` fixes that. For everything. Parameterized testing for nose, parameterized testing for py.test, parameterized testing for unittest. .. code:: python # test_math.py from nose.tools import assert_equal from parameterized import parameterized import unittest import math @parameterized([ (2, 2, 4), (2, 3, 8), (1, 9, 1), (0, 9, 0), ]) def test_pow(base, exponent, expected): assert_equal(math.pow(base, exponent), expected) class TestMathUnitTest(unittest.TestCase): @parameterized.expand([ ("negative", -1.5, -2.0), ("integer", 1, 1.0), ("large fraction", 1.6, 1), ]) def test_floor(self, name, input, expected): assert_equal(math.floor(input), expected) With nose (and nose2):: $ nosetests -v test_math.py test_math.test_pow(2, 2, 4) ... ok test_math.test_pow(2, 3, 8) ... ok test_math.test_pow(1, 9, 1) ... ok test_math.test_pow(0, 9, 0) ... ok test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 7 tests in 0.002s OK As the package name suggests, nose is best supported and will be used for all further examples. With py.test (version 2.0 and above):: $ py.test -v test_math.py ============================== test session starts ============================== platform darwin -- Python 2.7.2 -- py-1.4.30 -- pytest-2.7.1 collected 7 items test_math.py::test_pow::[0] PASSED test_math.py::test_pow::[1] PASSED test_math.py::test_pow::[2] PASSED test_math.py::test_pow::[3] PASSED test_math.py::TestMathUnitTest::test_floor_0_negative test_math.py::TestMathUnitTest::test_floor_1_integer test_math.py::TestMathUnitTest::test_floor_2_large_fraction =========================== 7 passed in 0.10 seconds ============================ With unittest (and unittest2):: $ python -m unittest -v test_math test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK (note: because unittest does not support test decorators, only tests created with ``@parameterized.expand`` will be executed) Installation ------------ :: $ pip install parameterized Compatibility ------------- `Yes`__. __ https://travis-ci.org/wolever/parameterized .. list-table:: :header-rows: 1 :stub-columns: 1 * - - Py2.6 - Py2.7 - Py3.3 - Py3.4 - PyPy * - nose - yes - yes - yes - yes - yes * - nose2 - yes - yes - yes - yes - yes * - py.test - yes - yes - yes - yes - yes * - | unittest | (``@parameterized.expand``) - yes - yes - yes - yes - yes * - | unittest2 | (``@parameterized.expand``) - yes - yes - yes - yes - yes Dependencies ------------ (this section left intentionally blank) Exhaustive Usage Examples -------------------------- The ``@parameterized`` and ``@parameterized.expand`` decorators accept a list or iterable of tuples or ``param(...)``, or a callable which returns a list or iterable: .. code:: python from parameterized import parameterized, param # A list of tuples @parameterized([ (2, 3, 5), (3, 5, 8), ]) def test_add(a, b, expected): assert_equal(a + b, expected) # A list of params @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) # An iterable of params @parameterized( param.explicit(*json.loads(line)) for line in open("testcases.jsons") ) def test_from_json_file(...): ... # A callable which returns a list of tuples def load_test_cases(): return [ ("test1", ), ("test2", ), ] @parameterized(load_test_cases) def test_from_function(name): ... .. ** Note that, when using an iterator or a generator, all the items will be loaded into memory before the start of the test run (we do this explicitly to ensure that generators are exhausted exactly once in multi-process or multi-threaded testing environments). The ``@parameterized`` decorator can be used test class methods, and standalone functions: .. code:: python from parameterized import parameterized class AddTest(object): @parameterized([ (2, 3, 5), ]) def test_add(self, a, b, expected): assert_equal(a + b, expected) @parameterized([ (2, 3, 5), ]) def test_add(a, b, expected): assert_equal(a + b, expected) And ``@parameterized.expand`` can be used to generate test methods in situations where test generators cannot be used (for example, when the test class is a subclass of ``unittest.TestCase``): .. code:: python import unittest from parameterized import parameterized class AddTestCase(unittest.TestCase): @parameterized.expand([ ("2 and 3", 2, 3, 5), ("3 and 5", 2, 3, 5), ]) def test_add(self, _, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_0_2_and_3 (example.AddTestCase) ... ok test_add_1_3_and_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK Note that ``@parameterized.expand`` works by creating new methods on the test class. If the first parameter is a string, that string will be added to the end of the method name. For example, the test case above will generate the methods ``test_add_0_2_and_3`` and ``test_add_1_3_and_5``. The names of the test cases generated by ``@parameterized.expand`` can be customized using the ``testcase_func_name`` keyword argument. The value should be a function which accepts three arguments: ``testcase_func``, ``param_num``, and ``params``, and it should return the name of the test case. ``testcase_func`` will be the function to be tested, ``param_num`` will be the index of the test case parameters in the list of parameters, and ``param`` (an instance of ``param``) will be the parameters which will be used. .. code:: python import unittest from parameterized import parameterized def custom_name_func(testcase_func, param_num, param): return "%s_%s" %( testcase_func.__name__, parameterized.to_safe_name("_".join(str(x) for x in param.args)), ) class AddTestCase(unittest.TestCase): @parameterized.expand([ (2, 3, 5), (2, 3, 5), ], testcase_func_name=custom_name_func) def test_add(self, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_1_2_3 (example.AddTestCase) ... ok test_add_2_3_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK The ``param(...)`` helper class stores the parameters for one specific test case. It can be used to pass keyword arguments to test cases: .. code:: python from parameterized import parameterized, param @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) If test cases have a docstring, the parameters for that test case will be appended to the first line of the docstring. This behavior can be controlled with the ``doc_func`` argument: .. code:: python from parameterized import parameterized @parameterized([ (1, 2, 3), (4, 5, 9), ]) def test_add(a, b, expected): """ Test addition. """ assert_equal(a + b, expected) def my_doc_func(func, num, param): return "%s: %s with %s" %(num, func.__name__, param) @parameterized([ (5, 4, 1), (9, 6, 3), ], doc_func=my_doc_func) def test_subtraction(a, b, expected): assert_equal(a - b, expected) :: $ nosetests example.py Test addition. [with a=1, b=2, expected=3] ... ok Test addition. [with a=4, b=5, expected=9] ... ok 0: test_subtraction with param(*(5, 4, 1)) ... ok 1: test_subtraction with param(*(9, 6, 3)) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK Migrating from ``nose-parameterized`` to ``parameterized`` ---------------------------------------------------------- To migrate a codebase from ``nose-parameterized`` to ``parameterized``: 1. Update your requirements file, replacing ``nose-parameterized`` with ``parameterized``. 2. Replace all references to ``nose_parameterized`` with ``parameterized``:: $ perl -pi -e 's/nose_parameterized/parameterized/g' your-codebase/ 3. You're done! FAQ --- What happened to ``nose-parameterized``? Originally only nose was supported. But now everything is supported, and it only made sense to change the name! What do you mean when you say "nose is best supported"? There are small caveates with ``py.test`` and ``unittest``: ``py.test`` does not show the parameter values (ex, it will show ``test_add[0]`` instead of ``test_add[1, 2, 3]``), and ``unittest``/``unittest2`` do not support test generators so ``@parameterized.expand`` must be used. Why not use ``@pytest.mark.parametrize``? Because spelling is difficult. Also, ``parameterized`` doesn't require you to repeat argument names, and (using ``param``) it supports optional keyword arguments. Why do I get an ``AttributeError: 'function' object has no attribute 'expand'`` with ``@parameterized.expand``? You've likely installed the ``parametrized`` (note the missing *e*) package. Use ``parameterized`` (with the *e*) instead and you'll be all set. Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: BSD License parameterized-0.6.1/parameterized.egg-info/SOURCES.txt0000644000076600001200000000063713064260214023361 0ustar woleveradmin00000000000000.gitignore .hgignore .travis.yml CHANGELOG.txt LICENSE.txt README.rst setup.cfg setup.py tox.ini misspelling-helper/nose-parametrized/MANIFEST misspelling-helper/nose-parametrized/setup.py parameterized/__init__.py parameterized/parameterized.py parameterized/test.py parameterized.egg-info/PKG-INFO parameterized.egg-info/SOURCES.txt parameterized.egg-info/dependency_links.txt parameterized.egg-info/top_level.txtparameterized-0.6.1/parameterized.egg-info/top_level.txt0000644000076600001200000000001613064260214024216 0ustar woleveradmin00000000000000parameterized parameterized-0.6.1/PKG-INFO0000644000076600001200000003376613064260214016255 0ustar woleveradmin00000000000000Metadata-Version: 1.1 Name: parameterized Version: 0.6.1 Summary: Parameterized testing with any Python test framework Home-page: https://github.com/wolever/parameterized Author: David Wolever Author-email: david@wolever.net License: FreeBSD Description: Parameterized testing with any Python test framework ==================================================== .. image:: https://travis-ci.org/wolever/parameterized.svg?branch=master :target: https://travis-ci.org/wolever/parameterized Parameterized testing in Python sucks. ``parameterized`` fixes that. For everything. Parameterized testing for nose, parameterized testing for py.test, parameterized testing for unittest. .. code:: python # test_math.py from nose.tools import assert_equal from parameterized import parameterized import unittest import math @parameterized([ (2, 2, 4), (2, 3, 8), (1, 9, 1), (0, 9, 0), ]) def test_pow(base, exponent, expected): assert_equal(math.pow(base, exponent), expected) class TestMathUnitTest(unittest.TestCase): @parameterized.expand([ ("negative", -1.5, -2.0), ("integer", 1, 1.0), ("large fraction", 1.6, 1), ]) def test_floor(self, name, input, expected): assert_equal(math.floor(input), expected) With nose (and nose2):: $ nosetests -v test_math.py test_math.test_pow(2, 2, 4) ... ok test_math.test_pow(2, 3, 8) ... ok test_math.test_pow(1, 9, 1) ... ok test_math.test_pow(0, 9, 0) ... ok test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 7 tests in 0.002s OK As the package name suggests, nose is best supported and will be used for all further examples. With py.test (version 2.0 and above):: $ py.test -v test_math.py ============================== test session starts ============================== platform darwin -- Python 2.7.2 -- py-1.4.30 -- pytest-2.7.1 collected 7 items test_math.py::test_pow::[0] PASSED test_math.py::test_pow::[1] PASSED test_math.py::test_pow::[2] PASSED test_math.py::test_pow::[3] PASSED test_math.py::TestMathUnitTest::test_floor_0_negative test_math.py::TestMathUnitTest::test_floor_1_integer test_math.py::TestMathUnitTest::test_floor_2_large_fraction =========================== 7 passed in 0.10 seconds ============================ With unittest (and unittest2):: $ python -m unittest -v test_math test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK (note: because unittest does not support test decorators, only tests created with ``@parameterized.expand`` will be executed) Installation ------------ :: $ pip install parameterized Compatibility ------------- `Yes`__. __ https://travis-ci.org/wolever/parameterized .. list-table:: :header-rows: 1 :stub-columns: 1 * - - Py2.6 - Py2.7 - Py3.3 - Py3.4 - PyPy * - nose - yes - yes - yes - yes - yes * - nose2 - yes - yes - yes - yes - yes * - py.test - yes - yes - yes - yes - yes * - | unittest | (``@parameterized.expand``) - yes - yes - yes - yes - yes * - | unittest2 | (``@parameterized.expand``) - yes - yes - yes - yes - yes Dependencies ------------ (this section left intentionally blank) Exhaustive Usage Examples -------------------------- The ``@parameterized`` and ``@parameterized.expand`` decorators accept a list or iterable of tuples or ``param(...)``, or a callable which returns a list or iterable: .. code:: python from parameterized import parameterized, param # A list of tuples @parameterized([ (2, 3, 5), (3, 5, 8), ]) def test_add(a, b, expected): assert_equal(a + b, expected) # A list of params @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) # An iterable of params @parameterized( param.explicit(*json.loads(line)) for line in open("testcases.jsons") ) def test_from_json_file(...): ... # A callable which returns a list of tuples def load_test_cases(): return [ ("test1", ), ("test2", ), ] @parameterized(load_test_cases) def test_from_function(name): ... .. ** Note that, when using an iterator or a generator, all the items will be loaded into memory before the start of the test run (we do this explicitly to ensure that generators are exhausted exactly once in multi-process or multi-threaded testing environments). The ``@parameterized`` decorator can be used test class methods, and standalone functions: .. code:: python from parameterized import parameterized class AddTest(object): @parameterized([ (2, 3, 5), ]) def test_add(self, a, b, expected): assert_equal(a + b, expected) @parameterized([ (2, 3, 5), ]) def test_add(a, b, expected): assert_equal(a + b, expected) And ``@parameterized.expand`` can be used to generate test methods in situations where test generators cannot be used (for example, when the test class is a subclass of ``unittest.TestCase``): .. code:: python import unittest from parameterized import parameterized class AddTestCase(unittest.TestCase): @parameterized.expand([ ("2 and 3", 2, 3, 5), ("3 and 5", 2, 3, 5), ]) def test_add(self, _, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_0_2_and_3 (example.AddTestCase) ... ok test_add_1_3_and_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK Note that ``@parameterized.expand`` works by creating new methods on the test class. If the first parameter is a string, that string will be added to the end of the method name. For example, the test case above will generate the methods ``test_add_0_2_and_3`` and ``test_add_1_3_and_5``. The names of the test cases generated by ``@parameterized.expand`` can be customized using the ``testcase_func_name`` keyword argument. The value should be a function which accepts three arguments: ``testcase_func``, ``param_num``, and ``params``, and it should return the name of the test case. ``testcase_func`` will be the function to be tested, ``param_num`` will be the index of the test case parameters in the list of parameters, and ``param`` (an instance of ``param``) will be the parameters which will be used. .. code:: python import unittest from parameterized import parameterized def custom_name_func(testcase_func, param_num, param): return "%s_%s" %( testcase_func.__name__, parameterized.to_safe_name("_".join(str(x) for x in param.args)), ) class AddTestCase(unittest.TestCase): @parameterized.expand([ (2, 3, 5), (2, 3, 5), ], testcase_func_name=custom_name_func) def test_add(self, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_1_2_3 (example.AddTestCase) ... ok test_add_2_3_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK The ``param(...)`` helper class stores the parameters for one specific test case. It can be used to pass keyword arguments to test cases: .. code:: python from parameterized import parameterized, param @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) If test cases have a docstring, the parameters for that test case will be appended to the first line of the docstring. This behavior can be controlled with the ``doc_func`` argument: .. code:: python from parameterized import parameterized @parameterized([ (1, 2, 3), (4, 5, 9), ]) def test_add(a, b, expected): """ Test addition. """ assert_equal(a + b, expected) def my_doc_func(func, num, param): return "%s: %s with %s" %(num, func.__name__, param) @parameterized([ (5, 4, 1), (9, 6, 3), ], doc_func=my_doc_func) def test_subtraction(a, b, expected): assert_equal(a - b, expected) :: $ nosetests example.py Test addition. [with a=1, b=2, expected=3] ... ok Test addition. [with a=4, b=5, expected=9] ... ok 0: test_subtraction with param(*(5, 4, 1)) ... ok 1: test_subtraction with param(*(9, 6, 3)) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK Migrating from ``nose-parameterized`` to ``parameterized`` ---------------------------------------------------------- To migrate a codebase from ``nose-parameterized`` to ``parameterized``: 1. Update your requirements file, replacing ``nose-parameterized`` with ``parameterized``. 2. Replace all references to ``nose_parameterized`` with ``parameterized``:: $ perl -pi -e 's/nose_parameterized/parameterized/g' your-codebase/ 3. You're done! FAQ --- What happened to ``nose-parameterized``? Originally only nose was supported. But now everything is supported, and it only made sense to change the name! What do you mean when you say "nose is best supported"? There are small caveates with ``py.test`` and ``unittest``: ``py.test`` does not show the parameter values (ex, it will show ``test_add[0]`` instead of ``test_add[1, 2, 3]``), and ``unittest``/``unittest2`` do not support test generators so ``@parameterized.expand`` must be used. Why not use ``@pytest.mark.parametrize``? Because spelling is difficult. Also, ``parameterized`` doesn't require you to repeat argument names, and (using ``param``) it supports optional keyword arguments. Why do I get an ``AttributeError: 'function' object has no attribute 'expand'`` with ``@parameterized.expand``? You've likely installed the ``parametrized`` (note the missing *e*) package. Use ``parameterized`` (with the *e*) instead and you'll be all set. Platform: UNKNOWN Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: License :: OSI Approved :: BSD License parameterized-0.6.1/README.rst0000644000076600001200000002504613064257247016653 0ustar woleveradmin00000000000000Parameterized testing with any Python test framework ==================================================== .. image:: https://travis-ci.org/wolever/parameterized.svg?branch=master :target: https://travis-ci.org/wolever/parameterized Parameterized testing in Python sucks. ``parameterized`` fixes that. For everything. Parameterized testing for nose, parameterized testing for py.test, parameterized testing for unittest. .. code:: python # test_math.py from nose.tools import assert_equal from parameterized import parameterized import unittest import math @parameterized([ (2, 2, 4), (2, 3, 8), (1, 9, 1), (0, 9, 0), ]) def test_pow(base, exponent, expected): assert_equal(math.pow(base, exponent), expected) class TestMathUnitTest(unittest.TestCase): @parameterized.expand([ ("negative", -1.5, -2.0), ("integer", 1, 1.0), ("large fraction", 1.6, 1), ]) def test_floor(self, name, input, expected): assert_equal(math.floor(input), expected) With nose (and nose2):: $ nosetests -v test_math.py test_math.test_pow(2, 2, 4) ... ok test_math.test_pow(2, 3, 8) ... ok test_math.test_pow(1, 9, 1) ... ok test_math.test_pow(0, 9, 0) ... ok test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 7 tests in 0.002s OK As the package name suggests, nose is best supported and will be used for all further examples. With py.test (version 2.0 and above):: $ py.test -v test_math.py ============================== test session starts ============================== platform darwin -- Python 2.7.2 -- py-1.4.30 -- pytest-2.7.1 collected 7 items test_math.py::test_pow::[0] PASSED test_math.py::test_pow::[1] PASSED test_math.py::test_pow::[2] PASSED test_math.py::test_pow::[3] PASSED test_math.py::TestMathUnitTest::test_floor_0_negative test_math.py::TestMathUnitTest::test_floor_1_integer test_math.py::TestMathUnitTest::test_floor_2_large_fraction =========================== 7 passed in 0.10 seconds ============================ With unittest (and unittest2):: $ python -m unittest -v test_math test_floor_0_negative (test_math.TestMathUnitTest) ... ok test_floor_1_integer (test_math.TestMathUnitTest) ... ok test_floor_2_large_fraction (test_math.TestMathUnitTest) ... ok ---------------------------------------------------------------------- Ran 3 tests in 0.000s OK (note: because unittest does not support test decorators, only tests created with ``@parameterized.expand`` will be executed) Installation ------------ :: $ pip install parameterized Compatibility ------------- `Yes`__. __ https://travis-ci.org/wolever/parameterized .. list-table:: :header-rows: 1 :stub-columns: 1 * - - Py2.6 - Py2.7 - Py3.3 - Py3.4 - PyPy * - nose - yes - yes - yes - yes - yes * - nose2 - yes - yes - yes - yes - yes * - py.test - yes - yes - yes - yes - yes * - | unittest | (``@parameterized.expand``) - yes - yes - yes - yes - yes * - | unittest2 | (``@parameterized.expand``) - yes - yes - yes - yes - yes Dependencies ------------ (this section left intentionally blank) Exhaustive Usage Examples -------------------------- The ``@parameterized`` and ``@parameterized.expand`` decorators accept a list or iterable of tuples or ``param(...)``, or a callable which returns a list or iterable: .. code:: python from parameterized import parameterized, param # A list of tuples @parameterized([ (2, 3, 5), (3, 5, 8), ]) def test_add(a, b, expected): assert_equal(a + b, expected) # A list of params @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) # An iterable of params @parameterized( param.explicit(*json.loads(line)) for line in open("testcases.jsons") ) def test_from_json_file(...): ... # A callable which returns a list of tuples def load_test_cases(): return [ ("test1", ), ("test2", ), ] @parameterized(load_test_cases) def test_from_function(name): ... .. ** Note that, when using an iterator or a generator, all the items will be loaded into memory before the start of the test run (we do this explicitly to ensure that generators are exhausted exactly once in multi-process or multi-threaded testing environments). The ``@parameterized`` decorator can be used test class methods, and standalone functions: .. code:: python from parameterized import parameterized class AddTest(object): @parameterized([ (2, 3, 5), ]) def test_add(self, a, b, expected): assert_equal(a + b, expected) @parameterized([ (2, 3, 5), ]) def test_add(a, b, expected): assert_equal(a + b, expected) And ``@parameterized.expand`` can be used to generate test methods in situations where test generators cannot be used (for example, when the test class is a subclass of ``unittest.TestCase``): .. code:: python import unittest from parameterized import parameterized class AddTestCase(unittest.TestCase): @parameterized.expand([ ("2 and 3", 2, 3, 5), ("3 and 5", 2, 3, 5), ]) def test_add(self, _, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_0_2_and_3 (example.AddTestCase) ... ok test_add_1_3_and_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK Note that ``@parameterized.expand`` works by creating new methods on the test class. If the first parameter is a string, that string will be added to the end of the method name. For example, the test case above will generate the methods ``test_add_0_2_and_3`` and ``test_add_1_3_and_5``. The names of the test cases generated by ``@parameterized.expand`` can be customized using the ``testcase_func_name`` keyword argument. The value should be a function which accepts three arguments: ``testcase_func``, ``param_num``, and ``params``, and it should return the name of the test case. ``testcase_func`` will be the function to be tested, ``param_num`` will be the index of the test case parameters in the list of parameters, and ``param`` (an instance of ``param``) will be the parameters which will be used. .. code:: python import unittest from parameterized import parameterized def custom_name_func(testcase_func, param_num, param): return "%s_%s" %( testcase_func.__name__, parameterized.to_safe_name("_".join(str(x) for x in param.args)), ) class AddTestCase(unittest.TestCase): @parameterized.expand([ (2, 3, 5), (2, 3, 5), ], testcase_func_name=custom_name_func) def test_add(self, a, b, expected): assert_equal(a + b, expected) Will create the test cases:: $ nosetests example.py test_add_1_2_3 (example.AddTestCase) ... ok test_add_2_3_5 (example.AddTestCase) ... ok ---------------------------------------------------------------------- Ran 2 tests in 0.001s OK The ``param(...)`` helper class stores the parameters for one specific test case. It can be used to pass keyword arguments to test cases: .. code:: python from parameterized import parameterized, param @parameterized([ param("10", 10), param("10", 16, base=16), ]) def test_int(str_val, expected, base=10): assert_equal(int(str_val, base=base), expected) If test cases have a docstring, the parameters for that test case will be appended to the first line of the docstring. This behavior can be controlled with the ``doc_func`` argument: .. code:: python from parameterized import parameterized @parameterized([ (1, 2, 3), (4, 5, 9), ]) def test_add(a, b, expected): """ Test addition. """ assert_equal(a + b, expected) def my_doc_func(func, num, param): return "%s: %s with %s" %(num, func.__name__, param) @parameterized([ (5, 4, 1), (9, 6, 3), ], doc_func=my_doc_func) def test_subtraction(a, b, expected): assert_equal(a - b, expected) :: $ nosetests example.py Test addition. [with a=1, b=2, expected=3] ... ok Test addition. [with a=4, b=5, expected=9] ... ok 0: test_subtraction with param(*(5, 4, 1)) ... ok 1: test_subtraction with param(*(9, 6, 3)) ... ok ---------------------------------------------------------------------- Ran 4 tests in 0.001s OK Migrating from ``nose-parameterized`` to ``parameterized`` ---------------------------------------------------------- To migrate a codebase from ``nose-parameterized`` to ``parameterized``: 1. Update your requirements file, replacing ``nose-parameterized`` with ``parameterized``. 2. Replace all references to ``nose_parameterized`` with ``parameterized``:: $ perl -pi -e 's/nose_parameterized/parameterized/g' your-codebase/ 3. You're done! FAQ --- What happened to ``nose-parameterized``? Originally only nose was supported. But now everything is supported, and it only made sense to change the name! What do you mean when you say "nose is best supported"? There are small caveates with ``py.test`` and ``unittest``: ``py.test`` does not show the parameter values (ex, it will show ``test_add[0]`` instead of ``test_add[1, 2, 3]``), and ``unittest``/``unittest2`` do not support test generators so ``@parameterized.expand`` must be used. Why not use ``@pytest.mark.parametrize``? Because spelling is difficult. Also, ``parameterized`` doesn't require you to repeat argument names, and (using ``param``) it supports optional keyword arguments. Why do I get an ``AttributeError: 'function' object has no attribute 'expand'`` with ``@parameterized.expand``? You've likely installed the ``parametrized`` (note the missing *e*) package. Use ``parameterized`` (with the *e*) instead and you'll be all set. parameterized-0.6.1/setup.cfg0000644000076600001200000000007513064260214016764 0ustar woleveradmin00000000000000[wheel] universal = 1 [egg_info] tag_build = tag_date = 0 parameterized-0.6.1/setup.py0000644000076600001200000000142113064257632016663 0ustar woleveradmin00000000000000#!/usr/bin/env python import os import sys from setuptools import setup, find_packages os.chdir(os.path.dirname(sys.argv[0]) or ".") try: long_description = open("README.rst", "U").read() except IOError: long_description = "See https://github.com/wolever/parameterized" setup( name="parameterized", version="0.6.1", url="https://github.com/wolever/parameterized", license="FreeBSD", author="David Wolever", author_email="david@wolever.net", description="Parameterized testing with any Python test framework", classifiers=[ 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'License :: OSI Approved :: BSD License', ], packages=find_packages(), long_description=long_description, ) parameterized-0.6.1/tox.ini0000644000076600001200000000050313064257353016464 0ustar woleveradmin00000000000000[tox] envlist=py{26,27,33,35,py}-{nose,nose2,pytest,unit,unit2} [testenv] deps= nose nose2: nose2 pytest: pytest>=2 unit2: unittest2 commands= nose: nosetests nose2: nose2 pytest: py.test parameterized/test.py unit: python -m unittest parameterized.test unit2: unit2 parameterized.test