|
6 | 6 | from dataclasses import dataclass |
7 | 7 | from functools import singledispatchmethod |
8 | 8 |
|
| 9 | +from xml.etree.ElementTree import Element, SubElement, tostring |
| 10 | +from xml.dom import minidom |
9 | 11 | from mlflow import MlflowClient |
10 | | - |
11 | 12 | from giskard.client.dtos import SuiteInfo, SuiteTestDTO, TestInputDTO, TestSuiteDTO |
12 | 13 | from giskard.client.giskard_client import GiskardClient |
13 | 14 | from giskard.core.core import TestFunctionMeta |
@@ -156,6 +157,40 @@ def to_wandb(self, run: Optional["wandb.wandb_sdk.wandb_run.Run"] = None) -> Non |
156 | 157 | run.log({"Test suite results/Test-Suite Results": wandb.Table(columns=columns, data=data)}) |
157 | 158 |
|
158 | 159 |
|
| 160 | + def to_junit(self): |
| 161 | + """Convert the test suite result to JUnit XML format.""" |
| 162 | + testsuites = Element('testsuites', {'tests': str(len(self.results))}) |
| 163 | + |
| 164 | + for test_tuple in self.results: |
| 165 | + test_name, test, _ = test_tuple |
| 166 | + testsuite = SubElement(testsuites, 'testsuite', { |
| 167 | + 'name': f"Test {test_name} (metric={test.metric})", |
| 168 | + }) |
| 169 | + testcase = SubElement(testsuite, 'testcase', {'name': test.metric_name, 'time': str(test.metric)}) # replace with actual time |
| 170 | + |
| 171 | + if not test.passed: |
| 172 | + failure = SubElement(testcase, 'failure', { |
| 173 | + 'message': f"Test failed with metric of {test.metric}", |
| 174 | + 'type': "TestFailed" if not test.is_error else "Error" |
| 175 | + }) |
| 176 | + # Add full test result information here |
| 177 | + for k, v in test.__dict__.items(): |
| 178 | + if k != 'messages' and k != 'is_error': |
| 179 | + SubElement(failure, 'detail', {'name': k, 'value': str(v)}) |
| 180 | + for message in test.messages: |
| 181 | + SubElement(failure, 'detail', {'name': 'message', 'value': message}) |
| 182 | + else: |
| 183 | + # Add test result information here |
| 184 | + for k, v in test.__dict__.items(): |
| 185 | + if k != 'messages' and k != 'is_error': |
| 186 | + SubElement(testcase, 'detail', {'name': k, 'value': str(v)}) |
| 187 | + for message in test.messages: |
| 188 | + SubElement(testcase, 'detail', {'name': 'message', 'value': message}) |
| 189 | + |
| 190 | + # Convert to string |
| 191 | + xml_str = minidom.parseString(tostring(testsuites)).toprettyxml(indent=" ") |
| 192 | + return xml_str |
| 193 | + |
159 | 194 | class SuiteInput: |
160 | 195 | """Represents an input parameter for a test suite. |
161 | 196 |
|
|
0 commit comments