diff --git a/parameterized/parameterized.py b/parameterized/parameterized.py index 56dc535..a521eb6 100644 --- a/parameterized/parameterized.py +++ b/parameterized/parameterized.py @@ -687,23 +687,27 @@ class TestUserAccessLevel(TestCase): def decorator(base_class): test_class_module = sys.modules[base_class.__module__].__dict__ + # We need to leave the base class in place (see issue #73), but if we leave + # test methods in place, the test runner will try to pick them up and run + # them, which doesn't make sense, since no parameters will have been applied. + # Address this by copying all test methods into generated classes and setting + # them to None in the base class. + test_methods = { + method_name: getattr(base_class, method_name) + for method_name in dir(base_class) + if method_name.startswith("test") + } + for method_name in test_methods: + setattr(base_class, method_name, None) + + base_dict = {**base_class.__dict__, **test_methods} for idx, input_dict in enumerate(input_dicts): - test_class_dict = dict(base_class.__dict__) - test_class_dict.update(input_dict) + test_class_dict = {**base_dict, **input_dict} name = class_name_func(base_class, idx, input_dict) test_class_module[name] = type(name, (base_class, ), test_class_dict) - # We need to leave the base class in place (see issue #73), but if we - # leave the test_ methods in place, the test runner will try to pick - # them up and run them... which doesn't make sense, since no parameters - # will have been applied. - # Address this by iterating over the base class and remove all test - # methods. - for method_name in list(base_class.__dict__): - if method_name.startswith("test"): - delattr(base_class, method_name) return base_class return decorator diff --git a/parameterized/test.py b/parameterized/test.py index 6c71f79..c1cb228 100644 --- a/parameterized/test.py +++ b/parameterized/test.py @@ -35,7 +35,7 @@ def assert_raises_regexp_decorator(expected_exception, expected_regexp): def func_decorator(func): @wraps(func) def wrapper(self, *args, **kwargs): - with self.assertRaisesRegexp(expected_exception, expected_regexp): + with self.assertRaisesRegex(expected_exception, expected_regexp): func(self, *args, **kwargs) return wrapper @@ -615,12 +615,28 @@ def test_method(self): )) +class FoobarTestCase(TestCase): + def setUp(self): + missing_tests.remove("%s:setUp(%r, %r)" %( + self.__class__.__name__, + self.foo, + self.bar, + )) + + def tearDown(self): + missing_tests.remove("%s:tearDown(%r, %r)" %( + self.__class__.__name__, + self.foo, + self.bar, + )) + + @parameterized_class([ {"foo": 42}, {"bar": "some stuff"}, {"bar": "other stuff", "name": "some name", "foo": 12}, ]) -class TestParameterizedClassDict(TestCase): +class TestParameterizedClassDict(FoobarTestCase): expect([ "TestParameterizedClassDict_0:setUp(42, 'empty')", "TestParameterizedClassDict_0:test_method(42, 'empty')", @@ -637,23 +653,30 @@ class TestParameterizedClassDict(TestCase): bar = 'empty' def setUp(self): - # Ensure that super() works (issue #73) + # Ensure that super() with arguments works (issue #73) super(TestParameterizedClassDict, self).setUp() - missing_tests.remove("%s:setUp(%r, %r)" %( - self.__class__.__name__, - self.foo, - self.bar, - )) def tearDown(self): - # Ensure that super() works (issue #73) - super(TestParameterizedClassDict, self).tearDown() - missing_tests.remove("%s:tearDown(%r, %r)" %( + # Ensure that super() without arguments works + super().tearDown() + + def test_method(self): + missing_tests.remove("%s:test_method(%r, %r)" %( self.__class__.__name__, self.foo, self.bar, )) + +class TestMixin: + def setUp(self): + # Ensure that super() with arguments works + super(TestMixin, self).setUp() + + def tearDown(self): + # Ensure that super() without arguments works + super().tearDown() + def test_method(self): missing_tests.remove("%s:test_method(%r, %r)" %( self.__class__.__name__, @@ -662,6 +685,15 @@ def test_method(self): )) +@parameterized_class([{"foo": 42, "bar": 21}]) +class TestParameterizedMixin(TestMixin, FoobarTestCase): + expect([ + "TestParameterizedMixin_0:setUp(42, 21)", + "TestParameterizedMixin_0:test_method(42, 21)", + "TestParameterizedMixin_0:tearDown(42, 21)", + ]) + + class TestUnicodeDocstring(object): @parameterized.expand([ 'value1',