Support alias for test classes when using suite. (#467)
The same test class can be run with different configs.
To report the same class run with different configs, we need to allow users to specify a suffix to differentiate the runs.
diff --git a/mobly/base_test.py b/mobly/base_test.py
index 03f7822..9eed6af 100644
--- a/mobly/base_test.py
+++ b/mobly/base_test.py
@@ -84,8 +84,12 @@
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 4eed6a1..aa43c03 100644
--- a/mobly/config_parser.py
+++ b/mobly/config_parser.py
@@ -169,6 +169,9 @@
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 @@
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 4e4b666..af834e8 100644
--- a/mobly/test_runner.py
+++ b/mobly/test_runner.py
@@ -265,9 +265,14 @@
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 @@
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 @@
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 @@
(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 @@
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 @@
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 @@
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 c0ff4b5..b369231 100755
--- a/tests/mobly/test_runner_test.py
+++ b/tests/mobly/test_runner_test.py
@@ -259,8 +259,13 @@
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 @@
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 @@
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()