| # Copyright 2017 The Abseil Authors. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| """Tests for absl.testing.parameterized.""" |
| |
| from collections import abc |
| import sys |
| import unittest |
| |
| from absl.testing import absltest |
| from absl.testing import parameterized |
| |
| |
| class MyOwnClass(object): |
| pass |
| |
| |
| def dummy_decorator(method): |
| |
| def decorated(*args, **kwargs): |
| return method(*args, **kwargs) |
| |
| return decorated |
| |
| |
| def dict_decorator(key, value): |
| """Sample implementation of a chained decorator. |
| |
| Sets a single field in a dict on a test with a dict parameter. |
| Uses the exposed '_ParameterizedTestIter.testcases' field to |
| modify arguments from previous decorators to allow decorator chains. |
| |
| Args: |
| key: key to map to |
| value: value to set |
| |
| Returns: |
| The test decorator |
| """ |
| def decorator(test_method): |
| # If decorating result of another dict_decorator |
| if isinstance(test_method, abc.Iterable): |
| actual_tests = [] |
| for old_test in test_method.testcases: |
| # each test is a ('test_suffix', dict) tuple |
| new_dict = old_test[1].copy() |
| new_dict[key] = value |
| test_suffix = '%s_%s_%s' % (old_test[0], key, value) |
| actual_tests.append((test_suffix, new_dict)) |
| |
| test_method.testcases = actual_tests |
| return test_method |
| else: |
| test_suffix = ('_%s_%s') % (key, value) |
| tests_to_make = ((test_suffix, {key: value}),) |
| # 'test_method' here is the original test method |
| return parameterized.named_parameters(*tests_to_make)(test_method) |
| return decorator |
| |
| |
| class ParameterizedTestsTest(absltest.TestCase): |
| # The test testcases are nested so they're not |
| # picked up by the normal test case loader code. |
| |
| class GoodAdditionParams(parameterized.TestCase): |
| |
| @parameterized.parameters( |
| (1, 2, 3), |
| (4, 5, 9)) |
| def test_addition(self, op1, op2, result): |
| self.arguments = (op1, op2, result) |
| self.assertEqual(result, op1 + op2) |
| |
| # This class does not inherit from TestCase. |
| class BadAdditionParams(absltest.TestCase): |
| |
| @parameterized.parameters( |
| (1, 2, 3), |
| (4, 5, 9)) |
| def test_addition(self, op1, op2, result): |
| pass # Always passes, but not called w/out TestCase. |
| |
| class MixedAdditionParams(parameterized.TestCase): |
| |
| @parameterized.parameters( |
| (1, 2, 1), |
| (4, 5, 9)) |
| def test_addition(self, op1, op2, result): |
| self.arguments = (op1, op2, result) |
| self.assertEqual(result, op1 + op2) |
| |
| class DictionaryArguments(parameterized.TestCase): |
| |
| @parameterized.parameters( |
| {'op1': 1, 'op2': 2, 'result': 3}, |
| {'op1': 4, 'op2': 5, 'result': 9}) |
| def test_addition(self, op1, op2, result): |
| self.assertEqual(result, op1 + op2) |
| |
| class NoParameterizedTests(parameterized.TestCase): |
| # iterable member with non-matching name |
| a = 'BCD' |
| # member with matching name, but not a generator |
| testInstanceMember = None # pylint: disable=invalid-name |
| test_instance_member = None |
| |
| # member with a matching name and iterator, but not a generator |
| testString = 'foo' # pylint: disable=invalid-name |
| test_string = 'foo' |
| |
| # generator, but no matching name |
| def someGenerator(self): # pylint: disable=invalid-name |
| yield |
| yield |
| yield |
| |
| def some_generator(self): |
| yield |
| yield |
| yield |
| |
| # Generator function, but not a generator instance. |
| def testGenerator(self): |
| yield |
| yield |
| yield |
| |
| def test_generator(self): |
| yield |
| yield |
| yield |
| |
| def testNormal(self): |
| self.assertEqual(3, 1 + 2) |
| |
| def test_normal(self): |
| self.assertEqual(3, 1 + 2) |
| |
| class ArgumentsWithAddresses(parameterized.TestCase): |
| |
| @parameterized.parameters( |
| (object(),), |
| (MyOwnClass(),), |
| ) |
| def test_something(self, case): |
| pass |
| |
| class CamelCaseNamedTests(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| ('Interesting', 0), |
| ) |
| def testSingle(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'Interesting', 'case': 0}, |
| ) |
| def testDictSingle(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| ('Interesting', 0), |
| ('Boring', 1), |
| ) |
| def testSomething(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'Interesting', 'case': 0}, |
| {'testcase_name': 'Boring', 'case': 1}, |
| ) |
| def testDictSomething(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'Interesting', 'case': 0}, |
| ('Boring', 1), |
| ) |
| def testMixedSomething(self, case): |
| pass |
| |
| def testWithoutParameters(self): |
| pass |
| |
| class NamedTests(parameterized.TestCase): |
| """Example tests using PEP-8 style names instead of camel-case.""" |
| |
| @parameterized.named_parameters( |
| ('interesting', 0), |
| ) |
| def test_single(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'interesting', 'case': 0}, |
| ) |
| def test_dict_single(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| ('interesting', 0), |
| ('boring', 1), |
| ) |
| def test_something(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'interesting', 'case': 0}, |
| {'testcase_name': 'boring', 'case': 1}, |
| ) |
| def test_dict_something(self, case): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'interesting', 'case': 0}, |
| ('boring', 1), |
| ) |
| def test_mixed_something(self, case): |
| pass |
| |
| def test_without_parameters(self): |
| pass |
| |
| class ChainedTests(parameterized.TestCase): |
| |
| @dict_decorator('cone', 'waffle') |
| @dict_decorator('flavor', 'strawberry') |
| def test_chained(self, dictionary): |
| self.assertDictEqual(dictionary, {'cone': 'waffle', |
| 'flavor': 'strawberry'}) |
| |
| class SingletonListExtraction(parameterized.TestCase): |
| |
| @parameterized.parameters( |
| (i, i * 2) for i in range(10)) |
| def test_something(self, unused_1, unused_2): |
| pass |
| |
| class SingletonArgumentExtraction(parameterized.TestCase): |
| |
| @parameterized.parameters(1, 2, 3, 4, 5, 6) |
| def test_numbers(self, unused_1): |
| pass |
| |
| @parameterized.parameters('foo', 'bar', 'baz') |
| def test_strings(self, unused_1): |
| pass |
| |
| class SingletonDictArgument(parameterized.TestCase): |
| |
| @parameterized.parameters({'op1': 1, 'op2': 2}) |
| def test_something(self, op1, op2): |
| del op1, op2 |
| |
| @parameterized.parameters( |
| (1, 2, 3), |
| (4, 5, 9)) |
| class DecoratedClass(parameterized.TestCase): |
| |
| def test_add(self, arg1, arg2, arg3): |
| self.assertEqual(arg1 + arg2, arg3) |
| |
| def test_subtract_fail(self, arg1, arg2, arg3): |
| self.assertEqual(arg3 + arg2, arg1) |
| |
| @parameterized.parameters( |
| (a, b, a+b) for a in range(1, 5) for b in range(1, 5)) |
| class GeneratorDecoratedClass(parameterized.TestCase): |
| |
| def test_add(self, arg1, arg2, arg3): |
| self.assertEqual(arg1 + arg2, arg3) |
| |
| def test_subtract_fail(self, arg1, arg2, arg3): |
| self.assertEqual(arg3 + arg2, arg1) |
| |
| @parameterized.parameters( |
| (1, 2, 3), |
| (4, 5, 9), |
| ) |
| class DecoratedBareClass(absltest.TestCase): |
| |
| def test_add(self, arg1, arg2, arg3): |
| self.assertEqual(arg1 + arg2, arg3) |
| |
| class OtherDecoratorUnnamed(parameterized.TestCase): |
| |
| @dummy_decorator |
| @parameterized.parameters((1), (2)) |
| def test_other_then_parameterized(self, arg1): |
| pass |
| |
| @parameterized.parameters((1), (2)) |
| @dummy_decorator |
| def test_parameterized_then_other(self, arg1): |
| pass |
| |
| class OtherDecoratorNamed(parameterized.TestCase): |
| |
| @dummy_decorator |
| @parameterized.named_parameters(('a', 1), ('b', 2)) |
| def test_other_then_parameterized(self, arg1): |
| pass |
| |
| @parameterized.named_parameters(('a', 1), ('b', 2)) |
| @dummy_decorator |
| def test_parameterized_then_other(self, arg1): |
| pass |
| |
| class OtherDecoratorNamedWithDict(parameterized.TestCase): |
| |
| @dummy_decorator |
| @parameterized.named_parameters( |
| {'testcase_name': 'a', 'arg1': 1}, |
| {'testcase_name': 'b', 'arg1': 2}) |
| def test_other_then_parameterized(self, arg1): |
| pass |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'a', 'arg1': 1}, |
| {'testcase_name': 'b', 'arg1': 2}) |
| @dummy_decorator |
| def test_parameterized_then_other(self, arg1): |
| pass |
| |
| class UniqueDescriptiveNamesTest(parameterized.TestCase): |
| |
| @parameterized.parameters(13, 13) |
| def test_normal(self, number): |
| del number |
| |
| class MultiGeneratorsTestCase(parameterized.TestCase): |
| |
| @parameterized.parameters((i for i in (1, 2, 3)), (i for i in (3, 2, 1))) |
| def test_sum(self, a, b, c): |
| self.assertEqual(6, sum([a, b, c])) |
| |
| class NamedParametersReusableTestCase(parameterized.TestCase): |
| named_params_a = ( |
| {'testcase_name': 'dict_a', 'unused_obj': 0}, |
| ('list_a', 1), |
| ) |
| named_params_b = ( |
| {'testcase_name': 'dict_b', 'unused_obj': 2}, |
| ('list_b', 3), |
| ) |
| named_params_c = ( |
| {'testcase_name': 'dict_c', 'unused_obj': 4}, |
| ('list_b', 5), |
| ) |
| |
| @parameterized.named_parameters(*(named_params_a + named_params_b)) |
| def testSomething(self, unused_obj): |
| pass |
| |
| @parameterized.named_parameters(*(named_params_a + named_params_c)) |
| def testSomethingElse(self, unused_obj): |
| pass |
| |
| class SuperclassTestCase(parameterized.TestCase): |
| |
| @parameterized.parameters('foo', 'bar') |
| def test_name(self, name): |
| del name |
| |
| class SubclassTestCase(SuperclassTestCase): |
| pass |
| |
| @unittest.skipIf( |
| (sys.version_info[:2] == (3, 7) and sys.version_info[2] in {0, 1, 2}), |
| 'Python 3.7.0 to 3.7.2 have a bug that breaks this test, see ' |
| 'https://bugs.python.org/issue35767') |
| def test_missing_inheritance(self): |
| ts = unittest.makeSuite(self.BadAdditionParams) |
| self.assertEqual(1, ts.countTestCases()) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(1, res.testsRun) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertIn('without having inherited', str(res.errors[0])) |
| |
| def test_correct_extraction_numbers(self): |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| self.assertEqual(2, ts.countTestCases()) |
| |
| def test_successful_execution(self): |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_correct_arguments(self): |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| res = unittest.TestResult() |
| |
| params = set([ |
| (1, 2, 3), |
| (4, 5, 9)]) |
| for test in ts: |
| test(res) |
| self.assertIn(test.arguments, params) |
| params.remove(test.arguments) |
| self.assertEmpty(params) |
| |
| def test_recorded_failures(self): |
| ts = unittest.makeSuite(self.MixedAdditionParams) |
| self.assertEqual(2, ts.countTestCases()) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertLen(res.failures, 1) |
| self.assertEmpty(res.errors) |
| |
| def test_short_description(self): |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| short_desc = list(ts)[0].shortDescription() |
| |
| location = unittest.util.strclass(self.GoodAdditionParams).replace( |
| '__main__.', '') |
| expected = ('{}.test_addition0 (1, 2, 3)\n'.format(location) + |
| 'test_addition(1, 2, 3)') |
| self.assertEqual(expected, short_desc) |
| |
| def test_short_description_addresses_removed(self): |
| ts = unittest.makeSuite(self.ArgumentsWithAddresses) |
| short_desc = list(ts)[0].shortDescription().split('\n') |
| self.assertEqual( |
| 'test_something(<object>)', short_desc[1]) |
| short_desc = list(ts)[1].shortDescription().split('\n') |
| self.assertEqual( |
| 'test_something(<__main__.MyOwnClass>)', short_desc[1]) |
| |
| def test_id(self): |
| ts = unittest.makeSuite(self.ArgumentsWithAddresses) |
| self.assertEqual( |
| (unittest.util.strclass(self.ArgumentsWithAddresses) + |
| '.test_something0 (<object>)'), |
| list(ts)[0].id()) |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| self.assertEqual( |
| (unittest.util.strclass(self.GoodAdditionParams) + |
| '.test_addition0 (1, 2, 3)'), |
| list(ts)[0].id()) |
| |
| def test_str(self): |
| ts = unittest.makeSuite(self.GoodAdditionParams) |
| test = list(ts)[0] |
| |
| expected = 'test_addition0 (1, 2, 3) ({})'.format( |
| unittest.util.strclass(self.GoodAdditionParams)) |
| self.assertEqual(expected, str(test)) |
| |
| def test_dict_parameters(self): |
| ts = unittest.makeSuite(self.DictionaryArguments) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_no_parameterized_tests(self): |
| ts = unittest.makeSuite(self.NoParameterizedTests) |
| self.assertEqual(4, ts.countTestCases()) |
| short_descs = [x.shortDescription() for x in list(ts)] |
| full_class_name = unittest.util.strclass(self.NoParameterizedTests) |
| full_class_name = full_class_name.replace('__main__.', '') |
| self.assertSameElements( |
| [ |
| '{}.testGenerator'.format(full_class_name), |
| '{}.test_generator'.format(full_class_name), |
| '{}.testNormal'.format(full_class_name), |
| '{}.test_normal'.format(full_class_name), |
| ], |
| short_descs) |
| |
| def test_successful_product_test_testgrid(self): |
| |
| class GoodProductTestCase(parameterized.TestCase): |
| |
| @parameterized.product( |
| num=(0, 20, 80), |
| modulo=(2, 4), |
| expected=(0,) |
| ) |
| def testModuloResult(self, num, modulo, expected): |
| self.assertEqual(expected, num % modulo) |
| |
| ts = unittest.makeSuite(GoodProductTestCase) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(ts.countTestCases(), 6) |
| self.assertEqual(res.testsRun, 6) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_successful_product_test_kwarg_seqs(self): |
| |
| class GoodProductTestCase(parameterized.TestCase): |
| |
| @parameterized.product((dict(num=0), dict(num=20), dict(num=0)), |
| (dict(modulo=2), dict(modulo=4)), |
| (dict(expected=0),)) |
| def testModuloResult(self, num, modulo, expected): |
| self.assertEqual(expected, num % modulo) |
| |
| ts = unittest.makeSuite(GoodProductTestCase) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(ts.countTestCases(), 6) |
| self.assertEqual(res.testsRun, 6) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_successful_product_test_kwarg_seq_and_testgrid(self): |
| |
| class GoodProductTestCase(parameterized.TestCase): |
| |
| @parameterized.product((dict( |
| num=5, modulo=3, expected=2), dict(num=7, modulo=4, expected=3)), |
| dtype=(int, float)) |
| def testModuloResult(self, num, dtype, modulo, expected): |
| self.assertEqual(expected, dtype(num) % modulo) |
| |
| ts = unittest.makeSuite(GoodProductTestCase) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(ts.countTestCases(), 4) |
| self.assertEqual(res.testsRun, 4) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_inconsistent_arg_names_in_kwargs_seq(self): |
| with self.assertRaisesRegex(AssertionError, 'must all have the same keys'): |
| |
| class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable |
| |
| @parameterized.product((dict(num=5, modulo=3), dict(num=7, modula=2)), |
| dtype=(int, float)) |
| def test_something(self): |
| pass # not called because argnames are not the same |
| |
| def test_duplicate_arg_names_in_kwargs_seqs(self): |
| with self.assertRaisesRegex(AssertionError, 'must all have distinct'): |
| |
| class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable |
| |
| @parameterized.product((dict(num=5, modulo=3), dict(num=7, modulo=4)), |
| (dict(foo='bar', num=5), dict(foo='baz', num=7)), |
| dtype=(int, float)) |
| def test_something(self): |
| pass # not called because `num` is specified twice |
| |
| def test_duplicate_arg_names_in_kwargs_seq_and_testgrid(self): |
| with self.assertRaisesRegex(AssertionError, 'duplicate argument'): |
| |
| class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable |
| |
| @parameterized.product( |
| (dict(num=5, modulo=3), dict(num=7, modulo=4)), |
| (dict(foo='bar'), dict(foo='baz')), |
| dtype=(int, float), |
| foo=('a', 'b'), |
| ) |
| def test_something(self): |
| pass # not called because `foo` is specified twice |
| |
| def test_product_recorded_failures(self): |
| |
| class MixedProductTestCase(parameterized.TestCase): |
| |
| @parameterized.product( |
| num=(0, 10, 20), |
| modulo=(2, 4), |
| expected=(0,) |
| ) |
| def testModuloResult(self, num, modulo, expected): |
| self.assertEqual(expected, num % modulo) |
| |
| ts = unittest.makeSuite(MixedProductTestCase) |
| self.assertEqual(6, ts.countTestCases()) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(res.testsRun, 6) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertLen(res.failures, 1) |
| self.assertEmpty(res.errors) |
| |
| def test_mismatched_product_parameter(self): |
| |
| class MismatchedProductParam(parameterized.TestCase): |
| |
| @parameterized.product( |
| a=(1, 2), |
| mismatch=(1, 2) |
| ) |
| # will fail because of mismatch in parameter names. |
| def test_something(self, a, b): |
| pass |
| |
| ts = unittest.makeSuite(MismatchedProductParam) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(res.testsRun, 4) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertLen(res.errors, 4) |
| |
| def test_no_test_error_empty_product_parameter(self): |
| with self.assertRaises(parameterized.NoTestsError): |
| |
| class EmptyProductParam(parameterized.TestCase): # pylint: disable=unused-variable |
| |
| @parameterized.product(arg1=[1, 2], arg2=[]) |
| def test_something(self, arg1, arg2): |
| pass # not called because arg2 has empty list of values. |
| |
| def test_bad_product_parameters(self): |
| with self.assertRaisesRegex(AssertionError, 'must be given as list or'): |
| |
| class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable |
| |
| @parameterized.product(arg1=[1, 2], arg2='abcd') |
| def test_something(self, arg1, arg2): |
| pass # not called because arg2 is not list or tuple. |
| |
| def test_generator_tests_disallowed(self): |
| with self.assertRaisesRegex(RuntimeError, 'generated.*without'): |
| class GeneratorTests(parameterized.TestCase): # pylint: disable=unused-variable |
| test_generator_method = (lambda self: None for _ in range(10)) |
| |
| def test_named_parameters_run(self): |
| ts = unittest.makeSuite(self.NamedTests) |
| self.assertEqual(9, ts.countTestCases()) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(9, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_named_parameters_id(self): |
| ts = sorted(unittest.makeSuite(self.CamelCaseNamedTests), |
| key=lambda t: t.id()) |
| self.assertLen(ts, 9) |
| full_class_name = unittest.util.strclass(self.CamelCaseNamedTests) |
| self.assertEqual( |
| full_class_name + '.testDictSingleInteresting', |
| ts[0].id()) |
| self.assertEqual( |
| full_class_name + '.testDictSomethingBoring', |
| ts[1].id()) |
| self.assertEqual( |
| full_class_name + '.testDictSomethingInteresting', |
| ts[2].id()) |
| self.assertEqual( |
| full_class_name + '.testMixedSomethingBoring', |
| ts[3].id()) |
| self.assertEqual( |
| full_class_name + '.testMixedSomethingInteresting', |
| ts[4].id()) |
| self.assertEqual( |
| full_class_name + '.testSingleInteresting', |
| ts[5].id()) |
| self.assertEqual( |
| full_class_name + '.testSomethingBoring', |
| ts[6].id()) |
| self.assertEqual( |
| full_class_name + '.testSomethingInteresting', |
| ts[7].id()) |
| self.assertEqual( |
| full_class_name + '.testWithoutParameters', |
| ts[8].id()) |
| |
| def test_named_parameters_id_with_underscore_case(self): |
| ts = sorted(unittest.makeSuite(self.NamedTests), |
| key=lambda t: t.id()) |
| self.assertLen(ts, 9) |
| full_class_name = unittest.util.strclass(self.NamedTests) |
| self.assertEqual( |
| full_class_name + '.test_dict_single_interesting', |
| ts[0].id()) |
| self.assertEqual( |
| full_class_name + '.test_dict_something_boring', |
| ts[1].id()) |
| self.assertEqual( |
| full_class_name + '.test_dict_something_interesting', |
| ts[2].id()) |
| self.assertEqual( |
| full_class_name + '.test_mixed_something_boring', |
| ts[3].id()) |
| self.assertEqual( |
| full_class_name + '.test_mixed_something_interesting', |
| ts[4].id()) |
| self.assertEqual( |
| full_class_name + '.test_single_interesting', |
| ts[5].id()) |
| self.assertEqual( |
| full_class_name + '.test_something_boring', |
| ts[6].id()) |
| self.assertEqual( |
| full_class_name + '.test_something_interesting', |
| ts[7].id()) |
| self.assertEqual( |
| full_class_name + '.test_without_parameters', |
| ts[8].id()) |
| |
| def test_named_parameters_short_description(self): |
| ts = sorted(unittest.makeSuite(self.NamedTests), |
| key=lambda t: t.id()) |
| actual = {t._testMethodName: t.shortDescription() for t in ts} |
| expected = { |
| 'test_dict_single_interesting': 'case=0', |
| 'test_dict_something_boring': 'case=1', |
| 'test_dict_something_interesting': 'case=0', |
| 'test_mixed_something_boring': '1', |
| 'test_mixed_something_interesting': 'case=0', |
| 'test_something_boring': '1', |
| 'test_something_interesting': '0', |
| } |
| for test_name, param_repr in expected.items(): |
| short_desc = actual[test_name].split('\n') |
| self.assertIn(test_name, short_desc[0]) |
| self.assertEqual('{}({})'.format(test_name, param_repr), short_desc[1]) |
| |
| def test_load_tuple_named_test(self): |
| loader = unittest.TestLoader() |
| ts = list(loader.loadTestsFromName('NamedTests.test_something_interesting', |
| module=self)) |
| self.assertLen(ts, 1) |
| self.assertEndsWith(ts[0].id(), '.test_something_interesting') |
| |
| def test_load_dict_named_test(self): |
| loader = unittest.TestLoader() |
| ts = list( |
| loader.loadTestsFromName( |
| 'NamedTests.test_dict_something_interesting', module=self)) |
| self.assertLen(ts, 1) |
| self.assertEndsWith(ts[0].id(), '.test_dict_something_interesting') |
| |
| def test_load_mixed_named_test(self): |
| loader = unittest.TestLoader() |
| ts = list( |
| loader.loadTestsFromName( |
| 'NamedTests.test_mixed_something_interesting', module=self)) |
| self.assertLen(ts, 1) |
| self.assertEndsWith(ts[0].id(), '.test_mixed_something_interesting') |
| |
| def test_duplicate_named_test_fails(self): |
| with self.assertRaises(parameterized.DuplicateTestNameError): |
| |
| class _(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| ('Interesting', 0), |
| ('Interesting', 1), |
| ) |
| def test_something(self, unused_obj): |
| pass |
| |
| def test_duplicate_dict_named_test_fails(self): |
| with self.assertRaises(parameterized.DuplicateTestNameError): |
| |
| class _(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'Interesting', 'unused_obj': 0}, |
| {'testcase_name': 'Interesting', 'unused_obj': 1}, |
| ) |
| def test_dict_something(self, unused_obj): |
| pass |
| |
| def test_duplicate_mixed_named_test_fails(self): |
| with self.assertRaises(parameterized.DuplicateTestNameError): |
| |
| class _(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| {'testcase_name': 'Interesting', 'unused_obj': 0}, |
| ('Interesting', 1), |
| ) |
| def test_mixed_something(self, unused_obj): |
| pass |
| |
| def test_named_test_with_no_name_fails(self): |
| with self.assertRaises(RuntimeError): |
| |
| class _(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| (0,), |
| ) |
| def test_something(self, unused_obj): |
| pass |
| |
| def test_named_test_dict_with_no_name_fails(self): |
| with self.assertRaises(RuntimeError): |
| |
| class _(parameterized.TestCase): |
| |
| @parameterized.named_parameters( |
| {'unused_obj': 0}, |
| ) |
| def test_something(self, unused_obj): |
| pass |
| |
| def test_parameterized_test_iter_has_testcases_property(self): |
| @parameterized.parameters(1, 2, 3, 4, 5, 6) |
| def test_something(unused_self, unused_obj): # pylint: disable=invalid-name |
| pass |
| |
| expected_testcases = [1, 2, 3, 4, 5, 6] |
| self.assertTrue(hasattr(test_something, 'testcases')) |
| self.assertCountEqual(expected_testcases, test_something.testcases) |
| |
| def test_chained_decorator(self): |
| ts = unittest.makeSuite(self.ChainedTests) |
| self.assertEqual(1, ts.countTestCases()) |
| test = next(t for t in ts) |
| self.assertTrue(hasattr(test, 'test_chained_flavor_strawberry_cone_waffle')) |
| res = unittest.TestResult() |
| |
| ts.run(res) |
| self.assertEqual(1, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_singleton_list_extraction(self): |
| ts = unittest.makeSuite(self.SingletonListExtraction) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(10, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_singleton_argument_extraction(self): |
| ts = unittest.makeSuite(self.SingletonArgumentExtraction) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(9, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_singleton_dict_argument(self): |
| ts = unittest.makeSuite(self.SingletonDictArgument) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(1, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_decorated_bare_class(self): |
| ts = unittest.makeSuite(self.DecoratedBareClass) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) |
| |
| def test_decorated_class(self): |
| ts = unittest.makeSuite(self.DecoratedClass) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(4, res.testsRun) |
| self.assertLen(res.failures, 2) |
| |
| def test_generator_decorated_class(self): |
| ts = unittest.makeSuite(self.GeneratorDecoratedClass) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(32, res.testsRun) |
| self.assertLen(res.failures, 16) |
| |
| def test_no_duplicate_decorations(self): |
| with self.assertRaises(AssertionError): |
| |
| @parameterized.parameters(1, 2, 3, 4) |
| class _(parameterized.TestCase): |
| |
| @parameterized.parameters(5, 6, 7, 8) |
| def test_something(self, unused_obj): |
| pass |
| |
| def test_double_class_decorations_not_supported(self): |
| |
| @parameterized.parameters('foo', 'bar') |
| class SuperclassWithClassDecorator(parameterized.TestCase): |
| |
| def test_name(self, name): |
| del name |
| |
| with self.assertRaises(AssertionError): |
| |
| @parameterized.parameters('foo', 'bar') |
| class SubclassWithClassDecorator(SuperclassWithClassDecorator): |
| pass |
| |
| del SubclassWithClassDecorator |
| |
| def test_other_decorator_ordering_unnamed(self): |
| ts = unittest.makeSuite(self.OtherDecoratorUnnamed) |
| res = unittest.TestResult() |
| ts.run(res) |
| # Two for when the parameterized tests call the skip wrapper. |
| # One for when the skip wrapper is called first and doesn't iterate. |
| self.assertEqual(3, res.testsRun) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertEmpty(res.failures) |
| # One error from test_other_then_parameterized. |
| self.assertLen(res.errors, 1) |
| |
| def test_other_decorator_ordering_named(self): |
| ts = unittest.makeSuite(self.OtherDecoratorNamed) |
| # Verify it generates the test method names from the original test method. |
| for test in ts: # There is only one test. |
| ts_attributes = dir(test) |
| self.assertIn('test_parameterized_then_other_a', ts_attributes) |
| self.assertIn('test_parameterized_then_other_b', ts_attributes) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| # Two for when the parameterized tests call the skip wrapper. |
| # One for when the skip wrapper is called first and doesn't iterate. |
| self.assertEqual(3, res.testsRun) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertEmpty(res.failures) |
| # One error from test_other_then_parameterized. |
| self.assertLen(res.errors, 1) |
| |
| def test_other_decorator_ordering_named_with_dict(self): |
| ts = unittest.makeSuite(self.OtherDecoratorNamedWithDict) |
| # Verify it generates the test method names from the original test method. |
| for test in ts: # There is only one test. |
| ts_attributes = dir(test) |
| self.assertIn('test_parameterized_then_other_a', ts_attributes) |
| self.assertIn('test_parameterized_then_other_b', ts_attributes) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| # Two for when the parameterized tests call the skip wrapper. |
| # One for when the skip wrapper is called first and doesn't iterate. |
| self.assertEqual(3, res.testsRun) |
| self.assertFalse(res.wasSuccessful()) |
| self.assertEmpty(res.failures) |
| # One error from test_other_then_parameterized. |
| self.assertLen(res.errors, 1) |
| |
| def test_no_test_error_empty_parameters(self): |
| with self.assertRaises(parameterized.NoTestsError): |
| |
| @parameterized.parameters() |
| def test_something(): |
| pass |
| |
| del test_something |
| |
| def test_no_test_error_empty_generator(self): |
| with self.assertRaises(parameterized.NoTestsError): |
| |
| @parameterized.parameters((i for i in [])) |
| def test_something(): |
| pass |
| |
| del test_something |
| |
| def test_unique_descriptive_names(self): |
| |
| class RecordSuccessTestsResult(unittest.TestResult): |
| |
| def __init__(self, *args, **kwargs): |
| super(RecordSuccessTestsResult, self).__init__(*args, **kwargs) |
| self.successful_tests = [] |
| |
| def addSuccess(self, test): |
| self.successful_tests.append(test) |
| |
| ts = unittest.makeSuite(self.UniqueDescriptiveNamesTest) |
| res = RecordSuccessTestsResult() |
| ts.run(res) |
| self.assertTrue(res.wasSuccessful()) |
| self.assertEqual(2, res.testsRun) |
| test_ids = [test.id() for test in res.successful_tests] |
| full_class_name = unittest.util.strclass(self.UniqueDescriptiveNamesTest) |
| expected_test_ids = [ |
| full_class_name + '.test_normal0 (13)', |
| full_class_name + '.test_normal1 (13)', |
| ] |
| self.assertTrue(test_ids) |
| self.assertCountEqual(expected_test_ids, test_ids) |
| |
| def test_multi_generators(self): |
| ts = unittest.makeSuite(self.MultiGeneratorsTestCase) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) |
| |
| def test_named_parameters_reusable(self): |
| ts = unittest.makeSuite(self.NamedParametersReusableTestCase) |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(8, res.testsRun) |
| self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) |
| |
| def test_subclass_inherits_superclass_test_params_reprs(self): |
| self.assertEqual( |
| {'test_name0': "('foo')", 'test_name1': "('bar')"}, |
| self.SuperclassTestCase._test_params_reprs) |
| self.assertEqual( |
| {'test_name0': "('foo')", 'test_name1': "('bar')"}, |
| self.SubclassTestCase._test_params_reprs) |
| |
| |
| def _decorate_with_side_effects(func, self): |
| self.sideeffect = True |
| func(self) |
| |
| |
| class CoopMetaclassCreationTest(absltest.TestCase): |
| |
| class TestBase(absltest.TestCase): |
| |
| # This test simulates a metaclass that sets some attribute ('sideeffect') |
| # on each member of the class that starts with 'test'. The test code then |
| # checks that this attribute exists when the custom metaclass and |
| # TestGeneratorMetaclass are combined with cooperative inheritance. |
| |
| # The attribute has to be set in the __init__ method of the metaclass, |
| # since the TestGeneratorMetaclass already overrides __new__. Only one |
| # base metaclass can override __new__, but all can provide custom __init__ |
| # methods. |
| |
| class __metaclass__(type): # pylint: disable=g-bad-name |
| |
| def __init__(cls, name, bases, dct): |
| type.__init__(cls, name, bases, dct) |
| for member_name, obj in dct.items(): |
| if member_name.startswith('test'): |
| setattr(cls, member_name, |
| lambda self, f=obj: _decorate_with_side_effects(f, self)) |
| |
| class MyParams(parameterized.CoopTestCase(TestBase)): |
| |
| @parameterized.parameters( |
| (1, 2, 3), |
| (4, 5, 9)) |
| def test_addition(self, op1, op2, result): |
| self.assertEqual(result, op1 + op2) |
| |
| class MySuite(unittest.TestSuite): |
| # Under Python 3.4 the TestCases in the suite's list of tests to run are |
| # destroyed and replaced with None after successful execution by default. |
| # This disables that behavior. |
| _cleanup = False |
| |
| def test_successful_execution(self): |
| ts = unittest.makeSuite(self.MyParams) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertEqual(2, res.testsRun) |
| self.assertTrue(res.wasSuccessful()) |
| |
| def test_metaclass_side_effects(self): |
| ts = unittest.makeSuite(self.MyParams, suiteClass=self.MySuite) |
| |
| res = unittest.TestResult() |
| ts.run(res) |
| self.assertTrue(list(ts)[0].sideeffect) |
| |
| |
| if __name__ == '__main__': |
| absltest.main() |