Skip to content

Commit

Permalink
Merge pull request #324 from alekseiapa/fix/remove-dut-prefix-from-py…
Browse files Browse the repository at this point in the history
…test-xml-attrib-values

feat(junit-merger): add flag to preserve Python test cases and "is_unity_case" attribute
  • Loading branch information
hfudev authored Nov 29, 2024
2 parents 0550008 + e3856b5 commit 96809ea
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 6 deletions.
4 changes: 2 additions & 2 deletions pytest-embedded-idf/pytest_embedded_idf/unity_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -787,9 +787,9 @@ def get_merge_data(test_cases_attr: t.List[t.Dict]) -> t.Dict:
continue

if k not in output:
output[k] = [f'[dut-{ind}]: {val}']
output[k] = [val]
else:
output[k].append(f'[dut-{ind}]: {val}')
output[k].append(val)

for k, val in output.items():
if k in ('file', 'line'):
Expand Down
90 changes: 90 additions & 0 deletions pytest-embedded-idf/tests/test_idf.py
Original file line number Diff line number Diff line change
Expand Up @@ -897,3 +897,93 @@ def test_erase_all_with_port_cache_case2(dut):
)

result.assert_outcomes(passed=2)


def test_no_preserve_python_tests(testdir):
testdir.makepyfile(r"""
def test_python_case(dut):
dut.run_all_single_board_cases(name=["normal_case1", "multiple_stages_test"])
""")

testdir.runpytest(
'-s',
'--embedded-services', 'esp,idf',
'--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'),
'--log-cli-level', 'DEBUG',
'--junitxml', 'report.xml',
)

junit_report = ET.parse('report.xml').getroot()[0]

assert junit_report.attrib['tests'] == '2'
for testcase in junit_report.findall('testcase'):
assert testcase.attrib['is_unity_case'] == '1'

def test_preserve_python_tests(testdir):
testdir.makepyfile(r"""
def test_python_case(dut):
dut.run_all_single_board_cases(name=["normal_case1", "multiple_stages_test"])
""")

testdir.runpytest(
'-s',
'--embedded-services', 'esp,idf',
'--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'),
'--log-cli-level', 'DEBUG',
'--junitxml', 'report.xml',
'--unity-test-report-mode', 'merge',
)

junit_report = ET.parse('report.xml').getroot()[0]

assert junit_report.attrib['tests'] == '2'
assert junit_report[0].attrib['is_unity_case'] == '0'
for testcase in junit_report[1:]:
assert testcase.attrib['is_unity_case'] == '1'


def test_preserve_python_tests_with_failures(testdir):
testdir.makepyfile(r"""
def test_python_case(dut):
dut.run_all_single_board_cases(name=["normal_case1", "normal_case2"])
""")

testdir.runpytest(
'-s',
'--embedded-services', 'esp,idf',
'--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'),
'--log-cli-level', 'DEBUG',
'--junitxml', 'report.xml',
'--unity-test-report-mode', 'merge',
)

junit_report = ET.parse('report.xml').getroot()[0]

assert junit_report.attrib['failures'] == '1'
assert junit_report[0].attrib['is_unity_case'] == '0' # Python test case is preserved
assert junit_report[1].attrib['is_unity_case'] == '1' # C test case
assert junit_report[1].find('failure') is None # normal_case1 passed
assert junit_report[2].attrib['is_unity_case'] == '1'
assert junit_report[2].find('failure') is not None # normal_case2 failed


def test_python_func_attribute(testdir):
testdir.makepyfile(r"""
def test_python_case(dut):
dut.run_all_single_board_cases(name=["normal_case1", "multiple_stages_test"])
""")

testdir.runpytest(
'-s',
'--embedded-services', 'esp,idf',
'--app-path', os.path.join(testdir.tmpdir, 'unit_test_app_esp32'),
'--log-cli-level', 'DEBUG',
'--junitxml', 'report.xml',
'--unity-test-report-mode', 'merge',
)

junit_report = ET.parse('report.xml').getroot()[0]

assert junit_report[0].attrib['is_unity_case'] == '0' # Python test case
for testcase in junit_report[1:]:
assert testcase.attrib['is_unity_case'] == '1' # Other test cases
16 changes: 14 additions & 2 deletions pytest-embedded/pytest_embedded/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
wokwi_gn,
)
from .log import MessageQueue, PexpectProcess
from .unity import JunitMerger, escape_illegal_xml_chars
from .unity import JunitMerger, UnityTestReportMode, escape_illegal_xml_chars
from .utils import (
SERVICE_LIB_NAMES,
ClassCliOptions,
Expand Down Expand Up @@ -111,6 +111,16 @@ def pytest_addoption(parser):
help='y/yes/true for True and n/no/false for False. '
'Set to True to prettify XML junit report. (Default: False)',
)
parser.addoption(
'--unity-test-report-mode',
choices=[UnityTestReportMode.REPLACE.value, UnityTestReportMode.MERGE.value],
default=UnityTestReportMode.REPLACE.value,
help=(
'Specify the behavior for handling Unity test cases in the main JUnit report. '
"'merge' includes them alongside the parent Python test case. "
"'replace' substitutes the parent Python test case with Unity test cases (default)."
),
)

# supports parametrization
base_group.addoption('--root-logdir', help='set session-based root log dir. (Default: system temp folder)')
Expand Down Expand Up @@ -1183,7 +1193,9 @@ def unity_tester(dut: t.Union['IdfDut', t.Tuple['IdfDut']]) -> t.Optional['CaseT


def pytest_configure(config: Config) -> None:
config.stash[_junit_merger_key] = JunitMerger(config.option.xmlpath)
config.stash[_junit_merger_key] = JunitMerger(
config.option.xmlpath, config.getoption('unity_test_report_mode', default='replace')
)
config.stash[_junit_report_path_key] = config.option.xmlpath

config.stash[_pytest_embedded_key] = PytestEmbedded(
Expand Down
14 changes: 12 additions & 2 deletions pytest-embedded/pytest_embedded/unity.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ class TestFormat(enum.Enum):
FIXTURE = 1


class UnityTestReportMode(str, enum.Enum):
REPLACE = 'replace'
MERGE = 'merge'


class TestCase:
def __init__(self, name: str, result: str, **kwargs):
self.name = name
Expand Down Expand Up @@ -206,8 +211,9 @@ class JunitMerger:
SUB_JUNIT_FILENAME = 'dut.xml'
# multi-dut junit reports should be dut-[INDEX].xml

def __init__(self, main_junit: Optional[str]) -> None:
def __init__(self, main_junit: Optional[str], unity_test_report_mode: Optional[str] = None) -> None:
self.junit_path = main_junit
self.unity_test_report_mode = unity_test_report_mode or UnityTestReportMode.REPLACE.value

self._junit = None

Expand Down Expand Up @@ -291,9 +297,13 @@ def merge(self, junit_files: List[str]):
raise ValueError(f'Could\'t find test case {test_case_name}, dumped into "debug.xml" for debugging')

junit_case_is_fail = junit_case.find('failure') is not None
junit_parent.remove(junit_case)

junit_case.attrib['is_unity_case'] = '0'
if self.unity_test_report_mode == UnityTestReportMode.REPLACE.value:
junit_parent.remove(junit_case)

for case in merging_cases:
case.attrib['is_unity_case'] = '1'
junit_parent.append(case)

junit_parent.attrib['errors'] = self._int_add(
Expand Down

0 comments on commit 96809ea

Please sign in to comment.