added parameterized class functionallity
diff --git a/.gitignore b/.gitignore
index e2beb9c..d0531b9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,5 @@
.tox
build/
.cache/
+
+\.idea/
diff --git a/parameterized/parameterized.py b/parameterized/parameterized.py
index 1d83404..88bb458 100644
--- a/parameterized/parameterized.py
+++ b/parameterized/parameterized.py
@@ -386,6 +386,29 @@
input_values = list(input_values)
return [ param.from_decorator(p) for p in input_values ]
+
+ @classmethod
+ def parameterized_class(cls, properties, test_values):
+ def decorator(base_class):
+ test_class_module = sys.modules[base_class.__module__].__dict__
+ for test_value_key, test_field in enumerate(test_values):
+ test_class_dict = dict(base_class.__dict__)
+
+ if isinstance(properties, string_types):
+ test_class_dict[properties] = test_field
+ _create_module(base_class, test_class_module, test_value_key, test_class_dict)
+ elif len(properties) == len(test_field):
+ for j, property_key in enumerate(properties):
+ test_class_dict[property_key] = test_field[j]
+ _create_module(base_class, test_class_module, test_value_key, test_class_dict)
+
+ def _create_module(base_class, test_class_module, test_value_key, test_class_dict):
+ name = '{method_name}_{index}'.format(method_name=base_class.__name__, index=test_value_key + 1)
+ test_class_module[name] = type(name, (base_class,), test_class_dict)
+
+ return decorator
+
+
@classmethod
def expand(cls, input, name_func=None, doc_func=None, **legacy):
""" A "brute force" method of parameterizing test cases. Creates new
diff --git a/parameterized/test.py b/parameterized/test.py
index d5bcd8f..0cfc6c0 100644
--- a/parameterized/test.py
+++ b/parameterized/test.py
@@ -10,9 +10,11 @@
short_repr, detect_runner,
)
+
def assert_contains(haystack, needle):
if needle not in haystack:
- raise AssertionError("%r not in %r" %(needle, haystack))
+ raise AssertionError("%r not in %r" % (needle, haystack))
+
runner = detect_runner()
UNITTEST = runner.startswith("unittest")
@@ -29,6 +31,7 @@
missing_tests = set()
+
def expect(skip, tests=None):
if tests is None:
tests = skip
@@ -37,8 +40,9 @@
return
missing_tests.update(tests)
+
test_params = [
- (42, ),
+ (42,),
"foo0",
param("foo1"),
param("foo2", bar=42),
@@ -51,9 +55,10 @@
"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))
+ missing_tests.remove("test_naked_function(%r, bar=%r)" % (foo, bar))
class TestParameterized(object):
@@ -66,7 +71,7 @@
@parameterized(test_params)
def test_instance_method(self, foo, bar=None):
- missing_tests.remove("test_instance_method(%r, bar=%r)" %(foo, bar))
+ missing_tests.remove("test_instance_method(%r, bar=%r)" % (foo, bar))
if not PYTEST:
@@ -86,12 +91,12 @@
self.actual_order = self.stack.pop(0)
def tearDown(self):
- missing_tests.remove("teardown_called(%s)" %(self.stack.pop(0), ))
+ missing_tests.remove("teardown_called(%s)" % (self.stack.pop(0),))
- @parameterized([(1, ), (2, )])
+ @parameterized([(1,), (2,)])
def test_setup(self, count, *a):
- assert_equal(self.actual_order, "setup %s" %(count, ))
- missing_tests.remove("test_setup(%s)" %(self.actual_order, ))
+ assert_equal(self.actual_order, "setup %s" % (count,))
+ missing_tests.remove("test_setup(%s)" % (self.actual_order,))
def custom_naming_func(custom_tag):
@@ -111,7 +116,7 @@
@parameterized.expand(test_params)
def test_on_TestCase(self, foo, bar=None):
- missing_tests.remove("test_on_TestCase(%r, bar=%r)" %(foo, bar))
+ missing_tests.remove("test_on_TestCase(%r, bar=%r)" % (foo, bar))
expect([
"test_on_TestCase2_custom_name_42(42, bar=None)",
@@ -131,7 +136,7 @@
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))
+ missing_tests.remove("%s(%r, bar=%r)" % (expected_name, foo, bar))
class TestParameterizedExpandDocstring(TestCase):
@@ -141,8 +146,8 @@
stack = inspect.stack()
f_locals = stack[3][0].f_locals
test_method = (
- f_locals.get("testMethod") or # Py27
- f_locals.get("function") # Py33
+ 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")
@@ -160,12 +165,12 @@
@parameterized.expand([param("foo")])
def test_single_line_docstring(self, foo):
"""Documentation."""
- self._assert_docstring("Documentation [with foo=%r]." %(foo, ))
+ 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, ))
+ self._assert_docstring("[with foo=%r]" % (foo,))
@parameterized.expand([param("foo")])
def test_multiline_documentation(self, foo):
@@ -174,31 +179,31 @@
More"""
self._assert_docstring(
"Documentation [with foo=%r].\n\n"
- " More" %(foo, )
+ " 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, ))
+ 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))
+ 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)
+ 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, )])
+ @parameterized([(42,)])
def test_in_subclass_of_TestCase(self, foo):
pass
except Exception as e:
@@ -206,6 +211,7 @@
else:
raise AssertionError("Expected exception not raised")
+
def test_helpful_error_on_invalid_parameters():
try:
parameterized([1432141234243])(lambda: None)
@@ -214,12 +220,16 @@
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, ))
+ missing_tests.remove("test_wrapped_iterable_input(%r)" % (foo,))
+
def test_helpful_error_on_non_iterable_input():
try:
@@ -234,13 +244,16 @@
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:
@@ -259,28 +272,28 @@
@parameterized.expand(["foo", "bar"])
def test_old_style_classes(self, param):
- missing_tests.remove("test_on_old_style_class(%r)" %(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})]),
+ ("*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", 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, 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})]),
+ ("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, ))
+ helper = eval("lambda %s: None" % (func_params,))
actual = parameterized_argument_value_pairs(helper, p)
assert_equal(actual, expected)
@@ -294,9 +307,41 @@
def test_short_repr(input, expected, n=6):
assert_equal(short_repr(input, n=n), expected)
+
@parameterized([
- ("foo", ),
+ ("foo",),
])
def test_with_docstring(input):
""" Docstring! """
pass
+
+
+@parameterized.parameterized_class(('a', 'b', 'c'), [
+ ("", 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})]),
+])
+class TestParameterizedClass(TestCase):
+ def _assertions(self):
+ assert hasattr(self, 'a')
+ assert hasattr(self, 'b')
+ assert hasattr(self, 'c')
+
+ def test_method_a(self):
+ self._assertions()
+
+ def test_method_b(self):
+ self._assertions()
+