Customizing Test Case Names in DDT for Readable HtmlTestRunner Reports
When conducting API testing using unittest, DDT, and Excel, test reports generated with HtmlTestRunner often display generic test case names such as test_api_1, test_api_2, test_api_3. These names lack clarity and make it difficult to identify specific test scenarios at a glance.
Improving test case naming to something descriptive like test_api_login_success or test_api_password_error would significantly enhance report readability. This modification would allow team members, including non-technical stakeholders, to easily understand which tests passed or failed and take appropriate action without needing to reference Excel line numbers.
The key to implementing this enhancement lies in modifying the mk_test_name function within the DDT source code, which is responsible for generating test case names.
Original mk_test_name Implementation
def mk_test_name(base_name, test_data, case_index=0):
"""
Generate a descriptive name for a test case.
This function creates a unique test name by combining the original test name,
an ordinal index, and a string representation of the test data.
The result is converted into a valid Python identifier by replacing invalid characters.
For complex data structures, we avoid direct string conversion to prevent
inconsistent naming across different test runs (e.g., due to dictionary key ordering).
Simple scalar values are used directly.
A "simple" value is defined as a plain scalar, or a tuple/list containing
only simple values.
"""
# Pad index with leading zeros to maintain ordering
case_index = "{0:0{1}}".format(case_index + 1, index_length)
if not is_simple(test_data):
return "{0}_{1}".format(base_name, case_index)
try:
test_data = str(test_data)
except UnicodeEncodeError:
# Fallback for Python 2
test_data = test_data.encode('ascii', 'backslashreplace')
test_name = "{0}_{1}_{2}".format(base_name, case_index, test_data)
return re.sub(r'\W|^(?=\d)', '_', test_name)
Modified Implementation for Descriptive Naming
To extract meaningful test names from test data, we can modify the mk_test_name function to check if the input data is a dictionary or tuple and extract a 'name' or 'title' field when available.
def mk_test_name_with_labels(base_name, test_data, case_index=0):
"""
Generate descriptive test names by extracting meaningful labels from test data.
This enhanced version checks if the test data is a dictionary or tuple
and attempts to extract a 'name' or 'title' field to create more readable
test case names.
Args:
base_name: The original test method name
test_data: The test data (can be various types)
case_index: The index of the test case in the data set
Returns:
A descriptive test case name
"""
# Pad index with leading zeros to maintain ordering
case_index = "{0:0{1}}".format(case_index + 1, index_length)
# Handle dictionary test data
if isinstance(test_data, dict):
if 'name' in test_data:
return "{0}_{1}_{2}".format(base_name, case_index, test_data['name'])
elif 'title' in test_data:
return "{0}_{1}_{2}".format(base_name, case_index, test_data['title'])
else:
return "{0}_{1}".format(base_name, case_index)
# Handle tuple test data
if isinstance(test_data, tuple) and len(test_data) > 0:
if isinstance(test_data[0], dict) and 'name' in test_data[0]:
return "{0}_{1}_{2}".format(base_name, case_index, test_data[0]['name'])
# Fallback to original implementation for other data types
if not is_simple(test_data):
return "{0}_{1}".format(base_name, case_index)
try:
test_data = str(test_data)
except UnicodeEncodeError:
# Fallback for Python 2
test_data = test_data.encode('ascii', 'backslashreplace')
test_name = "{0}_{1}_{2}".format(base_name, case_index, test_data)
return re.sub(r'\W|^(?=\d)', '_', test_name)
Implementation Notes
To apply this modification, replace the original mk_test_name function in your DDT installation with the enhanced version above. Your test data should include a 'name' or 'title' field when you want descriptive test case names in the report.
For example, with test data structured as:
test_data = [
{"name": "login_success", "username": "user1", "password": "pass1"},
{"name": "password_error", "username": "user2", "password": "wrong"}
]
The resulting test case names in the HtmlTestRunner report will be:
- test_api_1_login_success
- test_api_2_password_error
This approach significantly improves the readability and usefulness of your test reports.