1# Copyright 2017 The Abseil Authors. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tests for absl.testing.parameterized.""" 16 17from collections import abc 18import sys 19import unittest 20 21from absl.testing import absltest 22from absl.testing import parameterized 23 24 25class MyOwnClass(object): 26 pass 27 28 29def dummy_decorator(method): 30 31 def decorated(*args, **kwargs): 32 return method(*args, **kwargs) 33 34 return decorated 35 36 37def dict_decorator(key, value): 38 """Sample implementation of a chained decorator. 39 40 Sets a single field in a dict on a test with a dict parameter. 41 Uses the exposed '_ParameterizedTestIter.testcases' field to 42 modify arguments from previous decorators to allow decorator chains. 43 44 Args: 45 key: key to map to 46 value: value to set 47 48 Returns: 49 The test decorator 50 """ 51 def decorator(test_method): 52 # If decorating result of another dict_decorator 53 if isinstance(test_method, abc.Iterable): 54 actual_tests = [] 55 for old_test in test_method.testcases: 56 # each test is a ('test_suffix', dict) tuple 57 new_dict = old_test[1].copy() 58 new_dict[key] = value 59 test_suffix = '%s_%s_%s' % (old_test[0], key, value) 60 actual_tests.append((test_suffix, new_dict)) 61 62 test_method.testcases = actual_tests 63 return test_method 64 else: 65 test_suffix = ('_%s_%s') % (key, value) 66 tests_to_make = ((test_suffix, {key: value}),) 67 # 'test_method' here is the original test method 68 return parameterized.named_parameters(*tests_to_make)(test_method) 69 return decorator 70 71 72class ParameterizedTestsTest(absltest.TestCase): 73 # The test testcases are nested so they're not 74 # picked up by the normal test case loader code. 75 76 class GoodAdditionParams(parameterized.TestCase): 77 78 @parameterized.parameters( 79 (1, 2, 3), 80 (4, 5, 9)) 81 def test_addition(self, op1, op2, result): 82 self.arguments = (op1, op2, result) 83 self.assertEqual(result, op1 + op2) 84 85 # This class does not inherit from TestCase. 86 class BadAdditionParams(absltest.TestCase): 87 88 @parameterized.parameters( 89 (1, 2, 3), 90 (4, 5, 9)) 91 def test_addition(self, op1, op2, result): 92 pass # Always passes, but not called w/out TestCase. 93 94 class MixedAdditionParams(parameterized.TestCase): 95 96 @parameterized.parameters( 97 (1, 2, 1), 98 (4, 5, 9)) 99 def test_addition(self, op1, op2, result): 100 self.arguments = (op1, op2, result) 101 self.assertEqual(result, op1 + op2) 102 103 class DictionaryArguments(parameterized.TestCase): 104 105 @parameterized.parameters( 106 {'op1': 1, 'op2': 2, 'result': 3}, 107 {'op1': 4, 'op2': 5, 'result': 9}) 108 def test_addition(self, op1, op2, result): 109 self.assertEqual(result, op1 + op2) 110 111 class NoParameterizedTests(parameterized.TestCase): 112 # iterable member with non-matching name 113 a = 'BCD' 114 # member with matching name, but not a generator 115 testInstanceMember = None # pylint: disable=invalid-name 116 test_instance_member = None 117 118 # member with a matching name and iterator, but not a generator 119 testString = 'foo' # pylint: disable=invalid-name 120 test_string = 'foo' 121 122 # generator, but no matching name 123 def someGenerator(self): # pylint: disable=invalid-name 124 yield 125 yield 126 yield 127 128 def some_generator(self): 129 yield 130 yield 131 yield 132 133 # Generator function, but not a generator instance. 134 def testGenerator(self): 135 yield 136 yield 137 yield 138 139 def test_generator(self): 140 yield 141 yield 142 yield 143 144 def testNormal(self): 145 self.assertEqual(3, 1 + 2) 146 147 def test_normal(self): 148 self.assertEqual(3, 1 + 2) 149 150 class ArgumentsWithAddresses(parameterized.TestCase): 151 152 @parameterized.parameters( 153 (object(),), 154 (MyOwnClass(),), 155 ) 156 def test_something(self, case): 157 pass 158 159 class CamelCaseNamedTests(parameterized.TestCase): 160 161 @parameterized.named_parameters( 162 ('Interesting', 0), 163 ) 164 def testSingle(self, case): 165 pass 166 167 @parameterized.named_parameters( 168 {'testcase_name': 'Interesting', 'case': 0}, 169 ) 170 def testDictSingle(self, case): 171 pass 172 173 @parameterized.named_parameters( 174 ('Interesting', 0), 175 ('Boring', 1), 176 ) 177 def testSomething(self, case): 178 pass 179 180 @parameterized.named_parameters( 181 {'testcase_name': 'Interesting', 'case': 0}, 182 {'testcase_name': 'Boring', 'case': 1}, 183 ) 184 def testDictSomething(self, case): 185 pass 186 187 @parameterized.named_parameters( 188 {'testcase_name': 'Interesting', 'case': 0}, 189 ('Boring', 1), 190 ) 191 def testMixedSomething(self, case): 192 pass 193 194 def testWithoutParameters(self): 195 pass 196 197 class NamedTests(parameterized.TestCase): 198 """Example tests using PEP-8 style names instead of camel-case.""" 199 200 @parameterized.named_parameters( 201 ('interesting', 0), 202 ) 203 def test_single(self, case): 204 pass 205 206 @parameterized.named_parameters( 207 {'testcase_name': 'interesting', 'case': 0}, 208 ) 209 def test_dict_single(self, case): 210 pass 211 212 @parameterized.named_parameters( 213 ('interesting', 0), 214 ('boring', 1), 215 ) 216 def test_something(self, case): 217 pass 218 219 @parameterized.named_parameters( 220 {'testcase_name': 'interesting', 'case': 0}, 221 {'testcase_name': 'boring', 'case': 1}, 222 ) 223 def test_dict_something(self, case): 224 pass 225 226 @parameterized.named_parameters( 227 {'testcase_name': 'interesting', 'case': 0}, 228 ('boring', 1), 229 ) 230 def test_mixed_something(self, case): 231 pass 232 233 def test_without_parameters(self): 234 pass 235 236 class ChainedTests(parameterized.TestCase): 237 238 @dict_decorator('cone', 'waffle') 239 @dict_decorator('flavor', 'strawberry') 240 def test_chained(self, dictionary): 241 self.assertDictEqual(dictionary, {'cone': 'waffle', 242 'flavor': 'strawberry'}) 243 244 class SingletonListExtraction(parameterized.TestCase): 245 246 @parameterized.parameters( 247 (i, i * 2) for i in range(10)) 248 def test_something(self, unused_1, unused_2): 249 pass 250 251 class SingletonArgumentExtraction(parameterized.TestCase): 252 253 @parameterized.parameters(1, 2, 3, 4, 5, 6) 254 def test_numbers(self, unused_1): 255 pass 256 257 @parameterized.parameters('foo', 'bar', 'baz') 258 def test_strings(self, unused_1): 259 pass 260 261 class SingletonDictArgument(parameterized.TestCase): 262 263 @parameterized.parameters({'op1': 1, 'op2': 2}) 264 def test_something(self, op1, op2): 265 del op1, op2 266 267 @parameterized.parameters( 268 (1, 2, 3), 269 (4, 5, 9)) 270 class DecoratedClass(parameterized.TestCase): 271 272 def test_add(self, arg1, arg2, arg3): 273 self.assertEqual(arg1 + arg2, arg3) 274 275 def test_subtract_fail(self, arg1, arg2, arg3): 276 self.assertEqual(arg3 + arg2, arg1) 277 278 @parameterized.parameters( 279 (a, b, a+b) for a in range(1, 5) for b in range(1, 5)) 280 class GeneratorDecoratedClass(parameterized.TestCase): 281 282 def test_add(self, arg1, arg2, arg3): 283 self.assertEqual(arg1 + arg2, arg3) 284 285 def test_subtract_fail(self, arg1, arg2, arg3): 286 self.assertEqual(arg3 + arg2, arg1) 287 288 @parameterized.parameters( 289 (1, 2, 3), 290 (4, 5, 9), 291 ) 292 class DecoratedBareClass(absltest.TestCase): 293 294 def test_add(self, arg1, arg2, arg3): 295 self.assertEqual(arg1 + arg2, arg3) 296 297 class OtherDecoratorUnnamed(parameterized.TestCase): 298 299 @dummy_decorator 300 @parameterized.parameters((1), (2)) 301 def test_other_then_parameterized(self, arg1): 302 pass 303 304 @parameterized.parameters((1), (2)) 305 @dummy_decorator 306 def test_parameterized_then_other(self, arg1): 307 pass 308 309 class OtherDecoratorNamed(parameterized.TestCase): 310 311 @dummy_decorator 312 @parameterized.named_parameters(('a', 1), ('b', 2)) 313 def test_other_then_parameterized(self, arg1): 314 pass 315 316 @parameterized.named_parameters(('a', 1), ('b', 2)) 317 @dummy_decorator 318 def test_parameterized_then_other(self, arg1): 319 pass 320 321 class OtherDecoratorNamedWithDict(parameterized.TestCase): 322 323 @dummy_decorator 324 @parameterized.named_parameters( 325 {'testcase_name': 'a', 'arg1': 1}, 326 {'testcase_name': 'b', 'arg1': 2}) 327 def test_other_then_parameterized(self, arg1): 328 pass 329 330 @parameterized.named_parameters( 331 {'testcase_name': 'a', 'arg1': 1}, 332 {'testcase_name': 'b', 'arg1': 2}) 333 @dummy_decorator 334 def test_parameterized_then_other(self, arg1): 335 pass 336 337 class UniqueDescriptiveNamesTest(parameterized.TestCase): 338 339 @parameterized.parameters(13, 13) 340 def test_normal(self, number): 341 del number 342 343 class MultiGeneratorsTestCase(parameterized.TestCase): 344 345 @parameterized.parameters((i for i in (1, 2, 3)), (i for i in (3, 2, 1))) 346 def test_sum(self, a, b, c): 347 self.assertEqual(6, sum([a, b, c])) 348 349 class NamedParametersReusableTestCase(parameterized.TestCase): 350 named_params_a = ( 351 {'testcase_name': 'dict_a', 'unused_obj': 0}, 352 ('list_a', 1), 353 ) 354 named_params_b = ( 355 {'testcase_name': 'dict_b', 'unused_obj': 2}, 356 ('list_b', 3), 357 ) 358 named_params_c = ( 359 {'testcase_name': 'dict_c', 'unused_obj': 4}, 360 ('list_b', 5), 361 ) 362 363 @parameterized.named_parameters(*(named_params_a + named_params_b)) 364 def testSomething(self, unused_obj): 365 pass 366 367 @parameterized.named_parameters(*(named_params_a + named_params_c)) 368 def testSomethingElse(self, unused_obj): 369 pass 370 371 class SuperclassTestCase(parameterized.TestCase): 372 373 @parameterized.parameters('foo', 'bar') 374 def test_name(self, name): 375 del name 376 377 class SubclassTestCase(SuperclassTestCase): 378 pass 379 380 @unittest.skipIf( 381 (sys.version_info[:2] == (3, 7) and sys.version_info[2] in {0, 1, 2}), 382 'Python 3.7.0 to 3.7.2 have a bug that breaks this test, see ' 383 'https://bugs.python.org/issue35767') 384 def test_missing_inheritance(self): 385 ts = unittest.makeSuite(self.BadAdditionParams) 386 self.assertEqual(1, ts.countTestCases()) 387 388 res = unittest.TestResult() 389 ts.run(res) 390 self.assertEqual(1, res.testsRun) 391 self.assertFalse(res.wasSuccessful()) 392 self.assertIn('without having inherited', str(res.errors[0])) 393 394 def test_correct_extraction_numbers(self): 395 ts = unittest.makeSuite(self.GoodAdditionParams) 396 self.assertEqual(2, ts.countTestCases()) 397 398 def test_successful_execution(self): 399 ts = unittest.makeSuite(self.GoodAdditionParams) 400 401 res = unittest.TestResult() 402 ts.run(res) 403 self.assertEqual(2, res.testsRun) 404 self.assertTrue(res.wasSuccessful()) 405 406 def test_correct_arguments(self): 407 ts = unittest.makeSuite(self.GoodAdditionParams) 408 res = unittest.TestResult() 409 410 params = set([ 411 (1, 2, 3), 412 (4, 5, 9)]) 413 for test in ts: 414 test(res) 415 self.assertIn(test.arguments, params) 416 params.remove(test.arguments) 417 self.assertEmpty(params) 418 419 def test_recorded_failures(self): 420 ts = unittest.makeSuite(self.MixedAdditionParams) 421 self.assertEqual(2, ts.countTestCases()) 422 423 res = unittest.TestResult() 424 ts.run(res) 425 self.assertEqual(2, res.testsRun) 426 self.assertFalse(res.wasSuccessful()) 427 self.assertLen(res.failures, 1) 428 self.assertEmpty(res.errors) 429 430 def test_short_description(self): 431 ts = unittest.makeSuite(self.GoodAdditionParams) 432 short_desc = list(ts)[0].shortDescription() 433 434 location = unittest.util.strclass(self.GoodAdditionParams).replace( 435 '__main__.', '') 436 expected = ('{}.test_addition0 (1, 2, 3)\n'.format(location) + 437 'test_addition(1, 2, 3)') 438 self.assertEqual(expected, short_desc) 439 440 def test_short_description_addresses_removed(self): 441 ts = unittest.makeSuite(self.ArgumentsWithAddresses) 442 short_desc = list(ts)[0].shortDescription().split('\n') 443 self.assertEqual( 444 'test_something(<object>)', short_desc[1]) 445 short_desc = list(ts)[1].shortDescription().split('\n') 446 self.assertEqual( 447 'test_something(<__main__.MyOwnClass>)', short_desc[1]) 448 449 def test_id(self): 450 ts = unittest.makeSuite(self.ArgumentsWithAddresses) 451 self.assertEqual( 452 (unittest.util.strclass(self.ArgumentsWithAddresses) + 453 '.test_something0 (<object>)'), 454 list(ts)[0].id()) 455 ts = unittest.makeSuite(self.GoodAdditionParams) 456 self.assertEqual( 457 (unittest.util.strclass(self.GoodAdditionParams) + 458 '.test_addition0 (1, 2, 3)'), 459 list(ts)[0].id()) 460 461 def test_str(self): 462 ts = unittest.makeSuite(self.GoodAdditionParams) 463 test = list(ts)[0] 464 465 expected = 'test_addition0 (1, 2, 3) ({})'.format( 466 unittest.util.strclass(self.GoodAdditionParams)) 467 self.assertEqual(expected, str(test)) 468 469 def test_dict_parameters(self): 470 ts = unittest.makeSuite(self.DictionaryArguments) 471 res = unittest.TestResult() 472 ts.run(res) 473 self.assertEqual(2, res.testsRun) 474 self.assertTrue(res.wasSuccessful()) 475 476 def test_no_parameterized_tests(self): 477 ts = unittest.makeSuite(self.NoParameterizedTests) 478 self.assertEqual(4, ts.countTestCases()) 479 short_descs = [x.shortDescription() for x in list(ts)] 480 full_class_name = unittest.util.strclass(self.NoParameterizedTests) 481 full_class_name = full_class_name.replace('__main__.', '') 482 self.assertSameElements( 483 [ 484 '{}.testGenerator'.format(full_class_name), 485 '{}.test_generator'.format(full_class_name), 486 '{}.testNormal'.format(full_class_name), 487 '{}.test_normal'.format(full_class_name), 488 ], 489 short_descs) 490 491 def test_successful_product_test_testgrid(self): 492 493 class GoodProductTestCase(parameterized.TestCase): 494 495 @parameterized.product( 496 num=(0, 20, 80), 497 modulo=(2, 4), 498 expected=(0,) 499 ) 500 def testModuloResult(self, num, modulo, expected): 501 self.assertEqual(expected, num % modulo) 502 503 ts = unittest.makeSuite(GoodProductTestCase) 504 res = unittest.TestResult() 505 ts.run(res) 506 self.assertEqual(ts.countTestCases(), 6) 507 self.assertEqual(res.testsRun, 6) 508 self.assertTrue(res.wasSuccessful()) 509 510 def test_successful_product_test_kwarg_seqs(self): 511 512 class GoodProductTestCase(parameterized.TestCase): 513 514 @parameterized.product((dict(num=0), dict(num=20), dict(num=0)), 515 (dict(modulo=2), dict(modulo=4)), 516 (dict(expected=0),)) 517 def testModuloResult(self, num, modulo, expected): 518 self.assertEqual(expected, num % modulo) 519 520 ts = unittest.makeSuite(GoodProductTestCase) 521 res = unittest.TestResult() 522 ts.run(res) 523 self.assertEqual(ts.countTestCases(), 6) 524 self.assertEqual(res.testsRun, 6) 525 self.assertTrue(res.wasSuccessful()) 526 527 def test_successful_product_test_kwarg_seq_and_testgrid(self): 528 529 class GoodProductTestCase(parameterized.TestCase): 530 531 @parameterized.product((dict( 532 num=5, modulo=3, expected=2), dict(num=7, modulo=4, expected=3)), 533 dtype=(int, float)) 534 def testModuloResult(self, num, dtype, modulo, expected): 535 self.assertEqual(expected, dtype(num) % modulo) 536 537 ts = unittest.makeSuite(GoodProductTestCase) 538 res = unittest.TestResult() 539 ts.run(res) 540 self.assertEqual(ts.countTestCases(), 4) 541 self.assertEqual(res.testsRun, 4) 542 self.assertTrue(res.wasSuccessful()) 543 544 def test_inconsistent_arg_names_in_kwargs_seq(self): 545 with self.assertRaisesRegex(AssertionError, 'must all have the same keys'): 546 547 class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable 548 549 @parameterized.product((dict(num=5, modulo=3), dict(num=7, modula=2)), 550 dtype=(int, float)) 551 def test_something(self): 552 pass # not called because argnames are not the same 553 554 def test_duplicate_arg_names_in_kwargs_seqs(self): 555 with self.assertRaisesRegex(AssertionError, 'must all have distinct'): 556 557 class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable 558 559 @parameterized.product((dict(num=5, modulo=3), dict(num=7, modulo=4)), 560 (dict(foo='bar', num=5), dict(foo='baz', num=7)), 561 dtype=(int, float)) 562 def test_something(self): 563 pass # not called because `num` is specified twice 564 565 def test_duplicate_arg_names_in_kwargs_seq_and_testgrid(self): 566 with self.assertRaisesRegex(AssertionError, 'duplicate argument'): 567 568 class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable 569 570 @parameterized.product( 571 (dict(num=5, modulo=3), dict(num=7, modulo=4)), 572 (dict(foo='bar'), dict(foo='baz')), 573 dtype=(int, float), 574 foo=('a', 'b'), 575 ) 576 def test_something(self): 577 pass # not called because `foo` is specified twice 578 579 def test_product_recorded_failures(self): 580 581 class MixedProductTestCase(parameterized.TestCase): 582 583 @parameterized.product( 584 num=(0, 10, 20), 585 modulo=(2, 4), 586 expected=(0,) 587 ) 588 def testModuloResult(self, num, modulo, expected): 589 self.assertEqual(expected, num % modulo) 590 591 ts = unittest.makeSuite(MixedProductTestCase) 592 self.assertEqual(6, ts.countTestCases()) 593 594 res = unittest.TestResult() 595 ts.run(res) 596 self.assertEqual(res.testsRun, 6) 597 self.assertFalse(res.wasSuccessful()) 598 self.assertLen(res.failures, 1) 599 self.assertEmpty(res.errors) 600 601 def test_mismatched_product_parameter(self): 602 603 class MismatchedProductParam(parameterized.TestCase): 604 605 @parameterized.product( 606 a=(1, 2), 607 mismatch=(1, 2) 608 ) 609 # will fail because of mismatch in parameter names. 610 def test_something(self, a, b): 611 pass 612 613 ts = unittest.makeSuite(MismatchedProductParam) 614 res = unittest.TestResult() 615 ts.run(res) 616 self.assertEqual(res.testsRun, 4) 617 self.assertFalse(res.wasSuccessful()) 618 self.assertLen(res.errors, 4) 619 620 def test_no_test_error_empty_product_parameter(self): 621 with self.assertRaises(parameterized.NoTestsError): 622 623 class EmptyProductParam(parameterized.TestCase): # pylint: disable=unused-variable 624 625 @parameterized.product(arg1=[1, 2], arg2=[]) 626 def test_something(self, arg1, arg2): 627 pass # not called because arg2 has empty list of values. 628 629 def test_bad_product_parameters(self): 630 with self.assertRaisesRegex(AssertionError, 'must be given as list or'): 631 632 class BadProductParams(parameterized.TestCase): # pylint: disable=unused-variable 633 634 @parameterized.product(arg1=[1, 2], arg2='abcd') 635 def test_something(self, arg1, arg2): 636 pass # not called because arg2 is not list or tuple. 637 638 def test_generator_tests_disallowed(self): 639 with self.assertRaisesRegex(RuntimeError, 'generated.*without'): 640 class GeneratorTests(parameterized.TestCase): # pylint: disable=unused-variable 641 test_generator_method = (lambda self: None for _ in range(10)) 642 643 def test_named_parameters_run(self): 644 ts = unittest.makeSuite(self.NamedTests) 645 self.assertEqual(9, ts.countTestCases()) 646 res = unittest.TestResult() 647 ts.run(res) 648 self.assertEqual(9, res.testsRun) 649 self.assertTrue(res.wasSuccessful()) 650 651 def test_named_parameters_id(self): 652 ts = sorted(unittest.makeSuite(self.CamelCaseNamedTests), 653 key=lambda t: t.id()) 654 self.assertLen(ts, 9) 655 full_class_name = unittest.util.strclass(self.CamelCaseNamedTests) 656 self.assertEqual( 657 full_class_name + '.testDictSingleInteresting', 658 ts[0].id()) 659 self.assertEqual( 660 full_class_name + '.testDictSomethingBoring', 661 ts[1].id()) 662 self.assertEqual( 663 full_class_name + '.testDictSomethingInteresting', 664 ts[2].id()) 665 self.assertEqual( 666 full_class_name + '.testMixedSomethingBoring', 667 ts[3].id()) 668 self.assertEqual( 669 full_class_name + '.testMixedSomethingInteresting', 670 ts[4].id()) 671 self.assertEqual( 672 full_class_name + '.testSingleInteresting', 673 ts[5].id()) 674 self.assertEqual( 675 full_class_name + '.testSomethingBoring', 676 ts[6].id()) 677 self.assertEqual( 678 full_class_name + '.testSomethingInteresting', 679 ts[7].id()) 680 self.assertEqual( 681 full_class_name + '.testWithoutParameters', 682 ts[8].id()) 683 684 def test_named_parameters_id_with_underscore_case(self): 685 ts = sorted(unittest.makeSuite(self.NamedTests), 686 key=lambda t: t.id()) 687 self.assertLen(ts, 9) 688 full_class_name = unittest.util.strclass(self.NamedTests) 689 self.assertEqual( 690 full_class_name + '.test_dict_single_interesting', 691 ts[0].id()) 692 self.assertEqual( 693 full_class_name + '.test_dict_something_boring', 694 ts[1].id()) 695 self.assertEqual( 696 full_class_name + '.test_dict_something_interesting', 697 ts[2].id()) 698 self.assertEqual( 699 full_class_name + '.test_mixed_something_boring', 700 ts[3].id()) 701 self.assertEqual( 702 full_class_name + '.test_mixed_something_interesting', 703 ts[4].id()) 704 self.assertEqual( 705 full_class_name + '.test_single_interesting', 706 ts[5].id()) 707 self.assertEqual( 708 full_class_name + '.test_something_boring', 709 ts[6].id()) 710 self.assertEqual( 711 full_class_name + '.test_something_interesting', 712 ts[7].id()) 713 self.assertEqual( 714 full_class_name + '.test_without_parameters', 715 ts[8].id()) 716 717 def test_named_parameters_short_description(self): 718 ts = sorted(unittest.makeSuite(self.NamedTests), 719 key=lambda t: t.id()) 720 actual = {t._testMethodName: t.shortDescription() for t in ts} 721 expected = { 722 'test_dict_single_interesting': 'case=0', 723 'test_dict_something_boring': 'case=1', 724 'test_dict_something_interesting': 'case=0', 725 'test_mixed_something_boring': '1', 726 'test_mixed_something_interesting': 'case=0', 727 'test_something_boring': '1', 728 'test_something_interesting': '0', 729 } 730 for test_name, param_repr in expected.items(): 731 short_desc = actual[test_name].split('\n') 732 self.assertIn(test_name, short_desc[0]) 733 self.assertEqual('{}({})'.format(test_name, param_repr), short_desc[1]) 734 735 def test_load_tuple_named_test(self): 736 loader = unittest.TestLoader() 737 ts = list(loader.loadTestsFromName('NamedTests.test_something_interesting', 738 module=self)) 739 self.assertLen(ts, 1) 740 self.assertEndsWith(ts[0].id(), '.test_something_interesting') 741 742 def test_load_dict_named_test(self): 743 loader = unittest.TestLoader() 744 ts = list( 745 loader.loadTestsFromName( 746 'NamedTests.test_dict_something_interesting', module=self)) 747 self.assertLen(ts, 1) 748 self.assertEndsWith(ts[0].id(), '.test_dict_something_interesting') 749 750 def test_load_mixed_named_test(self): 751 loader = unittest.TestLoader() 752 ts = list( 753 loader.loadTestsFromName( 754 'NamedTests.test_mixed_something_interesting', module=self)) 755 self.assertLen(ts, 1) 756 self.assertEndsWith(ts[0].id(), '.test_mixed_something_interesting') 757 758 def test_duplicate_named_test_fails(self): 759 with self.assertRaises(parameterized.DuplicateTestNameError): 760 761 class _(parameterized.TestCase): 762 763 @parameterized.named_parameters( 764 ('Interesting', 0), 765 ('Interesting', 1), 766 ) 767 def test_something(self, unused_obj): 768 pass 769 770 def test_duplicate_dict_named_test_fails(self): 771 with self.assertRaises(parameterized.DuplicateTestNameError): 772 773 class _(parameterized.TestCase): 774 775 @parameterized.named_parameters( 776 {'testcase_name': 'Interesting', 'unused_obj': 0}, 777 {'testcase_name': 'Interesting', 'unused_obj': 1}, 778 ) 779 def test_dict_something(self, unused_obj): 780 pass 781 782 def test_duplicate_mixed_named_test_fails(self): 783 with self.assertRaises(parameterized.DuplicateTestNameError): 784 785 class _(parameterized.TestCase): 786 787 @parameterized.named_parameters( 788 {'testcase_name': 'Interesting', 'unused_obj': 0}, 789 ('Interesting', 1), 790 ) 791 def test_mixed_something(self, unused_obj): 792 pass 793 794 def test_named_test_with_no_name_fails(self): 795 with self.assertRaises(RuntimeError): 796 797 class _(parameterized.TestCase): 798 799 @parameterized.named_parameters( 800 (0,), 801 ) 802 def test_something(self, unused_obj): 803 pass 804 805 def test_named_test_dict_with_no_name_fails(self): 806 with self.assertRaises(RuntimeError): 807 808 class _(parameterized.TestCase): 809 810 @parameterized.named_parameters( 811 {'unused_obj': 0}, 812 ) 813 def test_something(self, unused_obj): 814 pass 815 816 def test_parameterized_test_iter_has_testcases_property(self): 817 @parameterized.parameters(1, 2, 3, 4, 5, 6) 818 def test_something(unused_self, unused_obj): # pylint: disable=invalid-name 819 pass 820 821 expected_testcases = [1, 2, 3, 4, 5, 6] 822 self.assertTrue(hasattr(test_something, 'testcases')) 823 self.assertCountEqual(expected_testcases, test_something.testcases) 824 825 def test_chained_decorator(self): 826 ts = unittest.makeSuite(self.ChainedTests) 827 self.assertEqual(1, ts.countTestCases()) 828 test = next(t for t in ts) 829 self.assertTrue(hasattr(test, 'test_chained_flavor_strawberry_cone_waffle')) 830 res = unittest.TestResult() 831 832 ts.run(res) 833 self.assertEqual(1, res.testsRun) 834 self.assertTrue(res.wasSuccessful()) 835 836 def test_singleton_list_extraction(self): 837 ts = unittest.makeSuite(self.SingletonListExtraction) 838 res = unittest.TestResult() 839 ts.run(res) 840 self.assertEqual(10, res.testsRun) 841 self.assertTrue(res.wasSuccessful()) 842 843 def test_singleton_argument_extraction(self): 844 ts = unittest.makeSuite(self.SingletonArgumentExtraction) 845 res = unittest.TestResult() 846 ts.run(res) 847 self.assertEqual(9, res.testsRun) 848 self.assertTrue(res.wasSuccessful()) 849 850 def test_singleton_dict_argument(self): 851 ts = unittest.makeSuite(self.SingletonDictArgument) 852 res = unittest.TestResult() 853 ts.run(res) 854 self.assertEqual(1, res.testsRun) 855 self.assertTrue(res.wasSuccessful()) 856 857 def test_decorated_bare_class(self): 858 ts = unittest.makeSuite(self.DecoratedBareClass) 859 res = unittest.TestResult() 860 ts.run(res) 861 self.assertEqual(2, res.testsRun) 862 self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) 863 864 def test_decorated_class(self): 865 ts = unittest.makeSuite(self.DecoratedClass) 866 res = unittest.TestResult() 867 ts.run(res) 868 self.assertEqual(4, res.testsRun) 869 self.assertLen(res.failures, 2) 870 871 def test_generator_decorated_class(self): 872 ts = unittest.makeSuite(self.GeneratorDecoratedClass) 873 res = unittest.TestResult() 874 ts.run(res) 875 self.assertEqual(32, res.testsRun) 876 self.assertLen(res.failures, 16) 877 878 def test_no_duplicate_decorations(self): 879 with self.assertRaises(AssertionError): 880 881 @parameterized.parameters(1, 2, 3, 4) 882 class _(parameterized.TestCase): 883 884 @parameterized.parameters(5, 6, 7, 8) 885 def test_something(self, unused_obj): 886 pass 887 888 def test_double_class_decorations_not_supported(self): 889 890 @parameterized.parameters('foo', 'bar') 891 class SuperclassWithClassDecorator(parameterized.TestCase): 892 893 def test_name(self, name): 894 del name 895 896 with self.assertRaises(AssertionError): 897 898 @parameterized.parameters('foo', 'bar') 899 class SubclassWithClassDecorator(SuperclassWithClassDecorator): 900 pass 901 902 del SubclassWithClassDecorator 903 904 def test_other_decorator_ordering_unnamed(self): 905 ts = unittest.makeSuite(self.OtherDecoratorUnnamed) 906 res = unittest.TestResult() 907 ts.run(res) 908 # Two for when the parameterized tests call the skip wrapper. 909 # One for when the skip wrapper is called first and doesn't iterate. 910 self.assertEqual(3, res.testsRun) 911 self.assertFalse(res.wasSuccessful()) 912 self.assertEmpty(res.failures) 913 # One error from test_other_then_parameterized. 914 self.assertLen(res.errors, 1) 915 916 def test_other_decorator_ordering_named(self): 917 ts = unittest.makeSuite(self.OtherDecoratorNamed) 918 # Verify it generates the test method names from the original test method. 919 for test in ts: # There is only one test. 920 ts_attributes = dir(test) 921 self.assertIn('test_parameterized_then_other_a', ts_attributes) 922 self.assertIn('test_parameterized_then_other_b', ts_attributes) 923 924 res = unittest.TestResult() 925 ts.run(res) 926 # Two for when the parameterized tests call the skip wrapper. 927 # One for when the skip wrapper is called first and doesn't iterate. 928 self.assertEqual(3, res.testsRun) 929 self.assertFalse(res.wasSuccessful()) 930 self.assertEmpty(res.failures) 931 # One error from test_other_then_parameterized. 932 self.assertLen(res.errors, 1) 933 934 def test_other_decorator_ordering_named_with_dict(self): 935 ts = unittest.makeSuite(self.OtherDecoratorNamedWithDict) 936 # Verify it generates the test method names from the original test method. 937 for test in ts: # There is only one test. 938 ts_attributes = dir(test) 939 self.assertIn('test_parameterized_then_other_a', ts_attributes) 940 self.assertIn('test_parameterized_then_other_b', ts_attributes) 941 942 res = unittest.TestResult() 943 ts.run(res) 944 # Two for when the parameterized tests call the skip wrapper. 945 # One for when the skip wrapper is called first and doesn't iterate. 946 self.assertEqual(3, res.testsRun) 947 self.assertFalse(res.wasSuccessful()) 948 self.assertEmpty(res.failures) 949 # One error from test_other_then_parameterized. 950 self.assertLen(res.errors, 1) 951 952 def test_no_test_error_empty_parameters(self): 953 with self.assertRaises(parameterized.NoTestsError): 954 955 @parameterized.parameters() 956 def test_something(): 957 pass 958 959 del test_something 960 961 def test_no_test_error_empty_generator(self): 962 with self.assertRaises(parameterized.NoTestsError): 963 964 @parameterized.parameters((i for i in [])) 965 def test_something(): 966 pass 967 968 del test_something 969 970 def test_unique_descriptive_names(self): 971 972 class RecordSuccessTestsResult(unittest.TestResult): 973 974 def __init__(self, *args, **kwargs): 975 super(RecordSuccessTestsResult, self).__init__(*args, **kwargs) 976 self.successful_tests = [] 977 978 def addSuccess(self, test): 979 self.successful_tests.append(test) 980 981 ts = unittest.makeSuite(self.UniqueDescriptiveNamesTest) 982 res = RecordSuccessTestsResult() 983 ts.run(res) 984 self.assertTrue(res.wasSuccessful()) 985 self.assertEqual(2, res.testsRun) 986 test_ids = [test.id() for test in res.successful_tests] 987 full_class_name = unittest.util.strclass(self.UniqueDescriptiveNamesTest) 988 expected_test_ids = [ 989 full_class_name + '.test_normal0 (13)', 990 full_class_name + '.test_normal1 (13)', 991 ] 992 self.assertTrue(test_ids) 993 self.assertCountEqual(expected_test_ids, test_ids) 994 995 def test_multi_generators(self): 996 ts = unittest.makeSuite(self.MultiGeneratorsTestCase) 997 res = unittest.TestResult() 998 ts.run(res) 999 self.assertEqual(2, res.testsRun) 1000 self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) 1001 1002 def test_named_parameters_reusable(self): 1003 ts = unittest.makeSuite(self.NamedParametersReusableTestCase) 1004 res = unittest.TestResult() 1005 ts.run(res) 1006 self.assertEqual(8, res.testsRun) 1007 self.assertTrue(res.wasSuccessful(), msg=str(res.failures)) 1008 1009 def test_subclass_inherits_superclass_test_params_reprs(self): 1010 self.assertEqual( 1011 {'test_name0': "('foo')", 'test_name1': "('bar')"}, 1012 self.SuperclassTestCase._test_params_reprs) 1013 self.assertEqual( 1014 {'test_name0': "('foo')", 'test_name1': "('bar')"}, 1015 self.SubclassTestCase._test_params_reprs) 1016 1017 1018def _decorate_with_side_effects(func, self): 1019 self.sideeffect = True 1020 func(self) 1021 1022 1023class CoopMetaclassCreationTest(absltest.TestCase): 1024 1025 class TestBase(absltest.TestCase): 1026 1027 # This test simulates a metaclass that sets some attribute ('sideeffect') 1028 # on each member of the class that starts with 'test'. The test code then 1029 # checks that this attribute exists when the custom metaclass and 1030 # TestGeneratorMetaclass are combined with cooperative inheritance. 1031 1032 # The attribute has to be set in the __init__ method of the metaclass, 1033 # since the TestGeneratorMetaclass already overrides __new__. Only one 1034 # base metaclass can override __new__, but all can provide custom __init__ 1035 # methods. 1036 1037 class __metaclass__(type): # pylint: disable=g-bad-name 1038 1039 def __init__(cls, name, bases, dct): 1040 type.__init__(cls, name, bases, dct) 1041 for member_name, obj in dct.items(): 1042 if member_name.startswith('test'): 1043 setattr(cls, member_name, 1044 lambda self, f=obj: _decorate_with_side_effects(f, self)) 1045 1046 class MyParams(parameterized.CoopTestCase(TestBase)): 1047 1048 @parameterized.parameters( 1049 (1, 2, 3), 1050 (4, 5, 9)) 1051 def test_addition(self, op1, op2, result): 1052 self.assertEqual(result, op1 + op2) 1053 1054 class MySuite(unittest.TestSuite): 1055 # Under Python 3.4 the TestCases in the suite's list of tests to run are 1056 # destroyed and replaced with None after successful execution by default. 1057 # This disables that behavior. 1058 _cleanup = False 1059 1060 def test_successful_execution(self): 1061 ts = unittest.makeSuite(self.MyParams) 1062 1063 res = unittest.TestResult() 1064 ts.run(res) 1065 self.assertEqual(2, res.testsRun) 1066 self.assertTrue(res.wasSuccessful()) 1067 1068 def test_metaclass_side_effects(self): 1069 ts = unittest.makeSuite(self.MyParams, suiteClass=self.MySuite) 1070 1071 res = unittest.TestResult() 1072 ts.run(res) 1073 self.assertTrue(list(ts)[0].sideeffect) 1074 1075 1076if __name__ == '__main__': 1077 absltest.main() 1078