From f09a67d5fc0be0393862bee6800834437aa13b68 Mon Sep 17 00:00:00 2001 From: Ankita Saxena Date: Mon, 1 Jul 2019 12:54:56 +0530 Subject: [PATCH] Fix #6888: Run tests split by classes (#7040) * Run tests split by classes * Fix Test/Tests issue * Fix naming * Fix names and comments * Fix docstring * Fix path issue * Add coverage path to avoid circleci failure * Try clearing cache * Try fixing coverage issue * Check path * Remove extra path * Remove restore and save cache * Remove print * Try fixing ci * Remove cache comments * Revert to lexical form --- core/domain/exp_jobs_one_off_test.py | 2 +- extensions/answer_summarizers/models_test.py | 8 ++-- scripts/backend_tests.py | 44 ++++++++++++++++---- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/core/domain/exp_jobs_one_off_test.py b/core/domain/exp_jobs_one_off_test.py index a0b8cff3800a..766704e6b3c6 100644 --- a/core/domain/exp_jobs_one_off_test.py +++ b/core/domain/exp_jobs_one_off_test.py @@ -2178,7 +2178,7 @@ def test_no_action_is_performed_for_deleted_exploration(self): self, exp_jobs_one_off.TranslatorToVoiceArtistOneOffJob) -class TestDeleteStateIdMappingModelsOneOffJob(test_utils.GenericTestBase): +class DeleteStateIdMappingModelsOneOffJobTests(test_utils.GenericTestBase): """Tests the state ID mapping deletion job.""" def test_job_deletes_all_instances_of_model(self): exp_models.StateIdMappingModel.create( diff --git a/extensions/answer_summarizers/models_test.py b/extensions/answer_summarizers/models_test.py index f83d87608b12..7871b0b9001e 100644 --- a/extensions/answer_summarizers/models_test.py +++ b/extensions/answer_summarizers/models_test.py @@ -92,7 +92,7 @@ def _perform_calculation(self, state_answers_dict): return state_answers_calc_output.calculation_output -class AnswerFrequenciesUnitTestCase(CalculationUnitTestBase): +class AnswerFrequenciesUnitTests(CalculationUnitTestBase): """Tests for arbitrary answer frequency calculations.""" CALCULATION_ID = 'AnswerFrequencies' @@ -149,7 +149,7 @@ def test_answers_with_ties(self): self.assertEqual(actual_calc_output.to_raw_type(), expected_calc_output) -class Top5AnswerFrequenciesUnitTestCase(CalculationUnitTestBase): +class Top5AnswerFrequenciesUnitTests(CalculationUnitTestBase): """Tests for Top 5 answer frequency calculations.""" CALCULATION_ID = 'Top5AnswerFrequencies' @@ -194,7 +194,7 @@ def test_top5_with_ties(self): self.assertEqual(actual_calc_output.to_raw_type(), expected_calc_output) -class Top10AnswerFrequenciesUnitTestCase(CalculationUnitTestBase): +class Top10AnswerFrequenciesUnitTests(CalculationUnitTestBase): """Tests for Top 10 answer frequency calculations.""" CALCULATION_ID = 'Top10AnswerFrequencies' @@ -248,7 +248,7 @@ def test_top10_with_ties(self): self.assertEqual(actual_calc_output.to_raw_type(), expected_calc_output) -class FrequencyCommonlySubmittedElementsUnitTestCase(CalculationUnitTestBase): +class FrequencyCommonlySubmittedElementsUnitTests(CalculationUnitTestBase): """This calculation only works on answers which are all lists.""" CALCULATION_ID = 'FrequencyCommonlySubmittedElements' diff --git a/scripts/backend_tests.py b/scripts/backend_tests.py index c40151d3e43d..c3a834e24367 100644 --- a/scripts/backend_tests.py +++ b/scripts/backend_tests.py @@ -209,9 +209,35 @@ def _get_all_test_targets(test_path=None, include_load_tests=True): """Returns a list of test targets for all classes under test_path containing tests. """ - def _convert_to_test_target(path): - """Remove the .py suffix and replace all slashes with periods.""" - return os.path.relpath(path, os.getcwd())[:-3].replace('/', '.') + def _get_test_target_classes(path): + """Returns a list of all test classes in a given test file path. + + Args: + path: str. The path of the test file from which all test classes + are to be extracted. + + Returns: + list. A list of all test classes in a given test file path. + """ + class_names = [] + with open(path, 'r') as f: + lines = f.readlines() + for line in lines: + if line.startswith('class'): + start_index = line.find(' ') + 1 + end_index = line.find('Tests(') + if end_index >= 0: + class_names.append(line[start_index:end_index + 5]) + else: + end_index = line.find('Test(') + if end_index >= 0: + class_names.append(line[start_index:end_index + 4]) + + test_target_path = os.path.relpath( + path, os.getcwd())[:-3].replace('/', '.') + return [ + '%s.%s' % (test_target_path, class_name) + for class_name in class_names] base_path = os.path.join(os.getcwd(), test_path or '') result = [] @@ -220,20 +246,20 @@ def _convert_to_test_target(path): if any([s in root for s in excluded_dirs]): continue if root.endswith('_test.py'): - result.append(_convert_to_test_target( - os.path.join(base_path, root))) + result = result + ( + _get_test_target_classes(os.path.join(base_path, root))) for subroot, _, files in os.walk(os.path.join(base_path, root)): if _LOAD_TESTS_DIR in subroot and include_load_tests: for f in files: if f.endswith('_test.py'): - result.append(_convert_to_test_target( - os.path.join(subroot, f))) + result = result + ( + _get_test_target_classes(os.path.join(subroot, f))) for f in files: if (f.endswith('_test.py') and os.path.join('core', 'tests') not in subroot): - result.append(_convert_to_test_target( - os.path.join(subroot, f))) + result = result + ( + _get_test_target_classes(os.path.join(subroot, f))) return result