How to customize TestNG result xml

Posted on

TestNG generates a default test-results.xml file after running tests. This file contains details about passed, failed, and skipped tests. However, sometimes we need a customized TestNG result XML to fit specific reporting needs, such as:

  • Adding additional information (e.g., execution time, custom messages)
  • Changing the XML structure
  • Filtering test results

In this blog, we'll learn how to customize the TestNG result XML using a custom IReporter implementation.

Default TestNG result xml

When you run a TestNG suite, it generates an XML report (e.g., test-output/testng-results.xml).

A sample default XML looks like this:

XML
Copy
<testng-results>
    <suite name="MySuite">
        <test name="MyTest">
            <class name="SampleTest">
                <test-method name="testMethod" status="PASS"/>
            </class>
        </test>
    </suite>
</testng-results>

Now, let's customize this XML using TestNG's IReporter interface.

Steps to Customize TestNG Result XML


Step 1: Create a Sample Test Class

Create a test class with a simple test case.

Java
Copy
import org.testng.annotations.Test;

public class SampleTest {
    
    @Test
    public void testMethod1() {
        System.out.println("Test 1 executed");
    }

    @Test
    public void testMethod2() {
        System.out.println("Test 2 executed");
    }
}

Step 2: Create a Custom IReporter Class

Now, let's implement IReporter to generate a custom XML report.

Java
Copy
import org.testng.*;
import org.testng.xml.XmlSuite;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

public class CustomTestNGReporter implements IReporter {

    @Override
    public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
        StringBuilder xmlReport = new StringBuilder();
        xmlReport.append("<CustomTestResults>\n");

        for (ISuite suite : suites) {
            xmlReport.append("\t<Suite name=\"").append(suite.getName()).append("\">\n");

            for (ISuiteResult result : suite.getResults().values()) {
                ITestContext context = result.getTestContext();
                xmlReport.append("\t\t<Test name=\"").append(context.getName()).append("\">\n");

                appendTestResults("PassedTests", context.getPassedTests(), xmlReport);
                appendTestResults("FailedTests", context.getFailedTests(), xmlReport);
                appendTestResults("SkippedTests", context.getSkippedTests(), xmlReport);

                xmlReport.append("\t\t</Test>\n");
            }

            xmlReport.append("\t</Suite>\n");
        }

        xmlReport.append("</CustomTestResults>");

        // Write custom XML to a file
        writeToFile(outputDirectory + "/custom-testng-results.xml", xmlReport.toString());
    }

    private void appendTestResults(String tag, IResultMap results, StringBuilder xmlReport) {
        xmlReport.append("\t\t\t<").append(tag).append(">\n");
        for (ITestResult result : results.getAllResults()) {
            xmlReport.append("\t\t\t\t<TestMethod name=\"").append(result.getMethod().getMethodName()).append("\" ");
            xmlReport.append("status=\"").append(result.getStatus()).append("\" ");
            xmlReport.append("timeTaken=\"").append(result.getEndMillis() - result.getStartMillis()).append("ms\" />\n");
        }
        xmlReport.append("\t\t\t</").append(tag).append(">\n");
    }

    private void writeToFile(String filePath, String content) {
        try (FileWriter writer = new FileWriter(new File(filePath))) {
            writer.write(content);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Step 3: Add the Custom Reporter in testng.xml

Modify testng.xml to include our custom reporter.

XML
Copy
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="MySuite">
    <listeners>
        <listener class-name="CustomTestNGReporter"/>
    </listeners>
    <test name="MyTest">
        <classes>
            <class name="SampleTest"/>
        </classes>
    </test>
</suite>

Step 4: Run testng.xml

Run your testng.xml or execute it programmatically:

Java
Copy
import org.testng.TestNG;
import java.util.Arrays;

public class RunTestNG {
    public static void main(String[] args) {
        TestNG testng = new TestNG();
        testng.setTestSuites(Arrays.asList("testng.xml"));
        testng.run();
    }
}

Expected Output

TestNG will generate a custom-testng-results.xml file inside the test-output directory.

A sample custom-testng-results.xml output:

XML
Copy
<CustomTestResults>
    <Suite name="MySuite">
        <Test name="MyTest">
            <PassedTests>
                <TestMethod name="testMethod1" status="1" timeTaken="3ms"/>
            </PassedTests>
            <PassedTests>
                <TestMethod name="testMethod2" status="1" timeTaken="2ms"/>
            </PassedTests>
        </Test>
    </Suite>
</CustomTestResults>