diff --git a/mobly/base_test.py b/mobly/base_test.py index 03f78223..9eed6af7 100644 --- a/mobly/base_test.py +++ b/mobly/base_test.py @@ -84,8 +84,12 @@ def __init__(self, configs): configs: A config_parser.TestRunConfig object. """ self.tests = [] - if not self.TAG: - self.TAG = self.__class__.__name__ + self._class_name = self.__class__.__name__ + if configs.test_class_name_suffix and self.TAG is None: + self.TAG = '%s_%s' % (self._class_name, + configs.test_class_name_suffix) + elif self.TAG is None: + self.TAG = self._class_name # Set params. self.log_path = configs.log_path self.controller_configs = configs.controller_configs diff --git a/mobly/config_parser.py b/mobly/config_parser.py index 4eed6a1b..aa43c034 100644 --- a/mobly/config_parser.py +++ b/mobly/config_parser.py @@ -169,6 +169,9 @@ class TestRunConfig(object): modules. summary_writer: records.TestSummaryWriter, used to write elements to the test result summary file. + test_class_name_suffix: string, suffix to append to the class name for + reporting. This is used for differentiating the same class + executed with different parameters in a suite. """ def __init__(self): @@ -178,6 +181,7 @@ def __init__(self): self.user_params = None self.register_controller = None self.summary_writer = None + self.test_class_name_suffix = None def copy(self): """Returns a deep copy of the current config. diff --git a/mobly/test_runner.py b/mobly/test_runner.py index 4e4b6668..af834e80 100644 --- a/mobly/test_runner.py +++ b/mobly/test_runner.py @@ -265,9 +265,14 @@ class _TestRunInfo(object): run it with. """ - def __init__(self, config, test_class, tests=None): + def __init__(self, + config, + test_class, + tests=None, + test_class_name_suffix=None): self.config = config self.test_class = test_class + self.test_class_name_suffix = test_class_name_suffix self.tests = tests def __init__(self, log_dir, test_bed_name): @@ -329,7 +334,7 @@ def _teardown_logger(self): logger.kill_test_logger(logging.getLogger()) self._log_path = None - def add_test_class(self, config, test_class, tests=None): + def add_test_class(self, config, test_class, tests=None, name_suffix=None): """Adds tests to the execution plan of this TestRunner. Args: @@ -338,6 +343,9 @@ def add_test_class(self, config, test_class, tests=None): test_class: class, test class to execute. tests: list of strings, optional list of test names within the class to execute. + name_suffix: string, suffix to append to the class name for + reporting. This is used for differentiating the same class + executed with different parameters in a suite. Raises: Error: if the provided config has a log_path or test_bed_name which @@ -356,7 +364,10 @@ class to execute. (self._test_bed_name, config.test_bed_name)) self._test_run_infos.append( TestRunner._TestRunInfo( - config=config, test_class=test_class, tests=tests)) + config=config, + test_class=test_class, + tests=tests, + test_class_name_suffix=name_suffix)) def _run_test_class(self, config, test_class, tests=None): """Instantiates and executes a test class. @@ -370,6 +381,7 @@ def _run_test_class(self, config, test_class, tests=None): test_class: class, test class to execute. tests: Optional list of test names within the class to execute. """ + with test_class(config) as test_instance: try: cls_result = test_instance.run(tests) @@ -402,9 +414,12 @@ def run(self): test_config.register_controller = functools.partial( self._register_controller, test_config) test_config.summary_writer = summary_writer + test_config.test_class_name_suffix = test_run_info.test_class_name_suffix try: - self._run_test_class(test_config, test_run_info.test_class, - test_run_info.tests) + self._run_test_class( + config=test_config, + test_class=test_run_info.test_class, + tests=test_run_info.tests) except signals.TestAbortAll as e: logging.warning( 'Abort all subsequent test classes. Reason: %s', e) @@ -513,8 +528,8 @@ def _register_controller(self, config, module, required=True, logging.warning('No optional debug info found for controller %s. ' 'To provide it, implement get_info in this ' 'controller module.', module_config_name) - logging.debug('Found %d objects for controller %s', - len(objects), module_config_name) + logging.debug('Found %d objects for controller %s', len(objects), + module_config_name) destroy_func = module.destroy self._controller_destructors[module_ref_name] = destroy_func return objects diff --git a/tests/mobly/test_runner_test.py b/tests/mobly/test_runner_test.py index c0ff4b5b..b3692312 100755 --- a/tests/mobly/test_runner_test.py +++ b/tests/mobly/test_runner_test.py @@ -259,8 +259,13 @@ def test_run_two_test_classes(self, mock_get_all, mock_list_adb, self.assertEqual(results['Requested'], 2) self.assertEqual(results['Executed'], 2) self.assertEqual(results['Passed'], 2) + # Tag of the test class defaults to the class name. + record1 = tr.results.executed[0] + record2 = tr.results.executed[1] + self.assertEqual(record1.test_class, 'Integration2Test') + self.assertEqual(record2.test_class, 'IntegrationTest') - def test_run_two_test_classes_different_configs(self): + def test_run_two_test_classes_different_configs_and_aliases(self): """Verifies that running more than one test class in one test run with different configs works properly. """ @@ -272,8 +277,14 @@ def test_run_two_test_classes_different_configs(self): config2 = config1.copy() config2.user_params['icecream'] = 10 tr = test_runner.TestRunner(self.log_dir, self.test_bed_name) - tr.add_test_class(config1, integration_test.IntegrationTest) - tr.add_test_class(config2, integration_test.IntegrationTest) + tr.add_test_class( + config1, + integration_test.IntegrationTest, + name_suffix='FirstConfig') + tr.add_test_class( + config2, + integration_test.IntegrationTest, + name_suffix='SecondConfig') tr.run() results = tr.results.summary_dict() self.assertEqual(results['Requested'], 2) @@ -281,6 +292,10 @@ def test_run_two_test_classes_different_configs(self): self.assertEqual(results['Passed'], 1) self.assertEqual(results['Failed'], 1) self.assertEqual(tr.results.failed[0].details, '10 != 42') + record1 = tr.results.executed[0] + record2 = tr.results.executed[1] + self.assertEqual(record1.test_class, 'IntegrationTest_FirstConfig') + self.assertEqual(record2.test_class, 'IntegrationTest_SecondConfig') def test_run_with_abort_all(self): mock_test_config = self.base_mock_test_config.copy()