Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions launch_testing/launch_testing/junitxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import xml.etree.ElementTree as ET


def unittestResultsToXml(*, name='launch_test', test_results={}):
def unittestResultsToXml(*, name='launch_test', test_results={}, classname_prefix=None):
"""
Serialize multiple unittest.TestResult objects into an XML document.

Expand Down Expand Up @@ -46,12 +46,12 @@ def unittestResultsToXml(*, name='launch_test', test_results={}):
test_suites.set('time', str(round(time, 3)))

for (name, test_result) in test_results.items():
test_suites.append(unittestResultToXml(str(name), test_result))
test_suites.append(unittestResultToXml(str(name), test_result, classname_prefix))

return ET.ElementTree(test_suites)


def unittestResultToXml(name, test_result):
def unittestResultToXml(name, test_result, classname_prefix=None):
"""
Serialize a single unittest.TestResult to an XML element.

Expand All @@ -68,12 +68,12 @@ def unittestResultToXml(name, test_result):
test_suite.set('time', str(round(sum(test_result.testTimes.values()), 3)))

for case in test_result.testCases:
test_suite.append(unittestCaseToXml(test_result, case))
test_suite.append(unittestCaseToXml(test_result, case, classname_prefix))

return test_suite


def unittestCaseToXml(test_result, test_case):
def unittestCaseToXml(test_result, test_case, classname_prefix=None):
"""
Serialize a unittest.TestCase into an XML element.

Expand All @@ -85,6 +85,8 @@ class needs to be a launch_testing.TestResult class
case_xml = ET.Element('testcase')
full_methodname, _, qualifiers = test_case.id().partition(' ')
full_classname, _, methodname = full_methodname.rpartition('.')
if classname_prefix:
full_classname = '{}.{}'.format(classname_prefix, full_classname)
case_xml.set('classname', full_classname)
case_xml.set('name', (methodname + ' ' + qualifiers).strip())
case_xml.set('time', str(round(test_result.testTimes[test_case], 3)))
Expand Down
6 changes: 5 additions & 1 deletion launch_testing/launch_testing/launch_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def add_arguments(parser):
'--package-name', action='store', default=None,
help='Name of the package the test is in. Useful to aggregate xUnit reports.'
)
parser.add_argument(
'--test-name', action='store', default=None,
help='Unique test name to include in xUnit test case class names.'
)
parser.add_argument(
'-v', '--verbose', action='store_true', default=False, help='Run with verbose output'
)
Expand Down Expand Up @@ -116,7 +120,7 @@ def run(parser, args, test_runner_cls=LaunchTestRunner):
xml_report = unittestResultsToXml(
test_results=results, name='{}.{}'.format(
args.package_name, launch_test_file_basename
)
), classname_prefix=args.test_name
)
xml_report.write(args.xmlpath, encoding='utf-8', xml_declaration=True)

Expand Down
21 changes: 20 additions & 1 deletion launch_testing/test/launch_testing/test_xml_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import xml.etree.ElementTree as ET

import ament_index_python
from launch_testing.junitxml import unittestResultToXml
from launch_testing.junitxml import unittestResultsToXml
from launch_testing.test_result import FailResult
from launch_testing.test_result import SkipResult
Expand Down Expand Up @@ -47,7 +48,8 @@ def setUpClass(cls):
'launch_test',
path,
'--junit-xml', os.path.join(cls.tmpdir.name, 'junit.xml'),
'--package-name', 'test_xml_output'
'--package-name', 'test_xml_output',
'--test-name', 'unique_ctest_target'
],
).returncode

Expand All @@ -73,6 +75,10 @@ def test_pre_and_post(self):
case_names = [case.attrib['name'] for case in test_suite]
self.assertIn('test_count_to_four', case_names)
self.assertIn('test_full_output', case_names)
self.assertTrue(all(
case.attrib['classname'].startswith('unique_ctest_target.')
for case in test_suite
))


@pytest.mark.usefixtures('source_test_loader_class_fixture')
Expand Down Expand Up @@ -199,6 +205,19 @@ def test_multiple_test_results(self):
child_names = [chld.attrib['name'] for chld in xml_tree.getroot()]
self.assertEqual(set(child_names), {'launch_1', 'launch_2', 'launch_3'})

def test_classname_prefix_keeps_same_cases_unique(self):
test_result = self.unit_test_result_factory([lambda self: None])
first = unittestResultToXml('launch_1', test_result, 'ctest_target_1')
second = unittestResultToXml('launch_2', test_result, 'ctest_target_2')
self.assertEqual(
'ctest_target_1.test_xml_output.TestHost',
first.find('testcase').attrib['classname'],
)
self.assertEqual(
'ctest_target_2.test_xml_output.TestHost',
second.find('testcase').attrib['classname'],
)

def test_result_that_ran(self):
"""
Test we have output as a result of a test being run.
Expand Down
1 change: 1 addition & 0 deletions launch_testing_ament_cmake/cmake/add_launch_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ function(add_launch_test filename)
"${_launch_test_ARGS}"
"--junit-xml=${_launch_test_RESULT_FILE}"
"--package-name=${PROJECT_NAME}"
"--test-name=${_launch_test_TARGET}"
)

ament_add_test(
Expand Down