esahmo
esahmo

Reputation: 156

Create TestNg Xml file programmatically using Java

I have a following testNg xml file.

Can someone please advice how to create this dynamically using java.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite">
  <test name="Test">
    <groups>
     <run>   
       <include name="PrometheusHome" />
       <include name="AlertMgrHome" />
     </run>
   </groups>
    <classes>
      <class name="com.amex.eag.telemetry.testcases.PrometheusTests"/>
      <class name="com.amex.eag.telemetry.testcases.AlertManagerTests"/>
    </classes>
  </test> 
</suite> 

Upvotes: 3

Views: 4794

Answers (3)

Mehul Aggarwal
Mehul Aggarwal

Reputation: 56

Taking reference from here

Let's suppose that we want to run the below XML file

<suite name="codekru">
<test name="codekru">
    <classes>
        <class name="Test.CodekruTest" />
    </classes>
</test>

Now TestNG provides equivalent of the tags

  • <suite> tag is equivalent with XmlSuite class of TestNG.
  • <test> tag is equivalent with XmlTest class of TestNG.
  • <class> tag is equivalent with XmlClass class of TestNG.

So, keeping that in mind, we can make the above Xml file using the below code

public class GenerateXmlAndExecuteItAtRuntime {
 
public static void main(String[] args) {
    XmlSuite suite = new XmlSuite();
    suite.setName("codekru"); // this means <suite name = "codekru">

    XmlTest test = new XmlTest(suite);
    test.setName("codekru"); // this means <test name = "codekru">
    List<XmlClass> classes = new ArrayList<XmlClass>(); // <classes>
    classes.add(new XmlClass("Test.CodekruTest")); // this means <class name = "Test.CodekruTest">
    test.setXmlClasses(classes);

    List<XmlSuite> suites = new ArrayList<XmlSuite>();
    suites.add(suite);
    TestNG testng = new TestNG();
    testng.setXmlSuites(suites);
    testng.run();
   }
}

More information can be found on these links below

Upvotes: 0

Kishore Mohanavelu
Kishore Mohanavelu

Reputation: 459

TestNG Official Documentation on Programattic Execution If you are looking to run your tests programmatically, it's best to read an existing testng XML file, do some runtime modifications and run it programmatically. This would basically avoid the problem of hardcoding class names and test names in the code. If you are hardcoding test names and class names, then you would need to change the test names and class names every time you need to run a different case. So please avoid hardcoding. Please follow the below approach, it would suit your need.

    List<String> deviceNames = StringUtils.isEmpty(System.getProperty("deviceNames")) ? 
new ArrayList<>() : Arrays.asList(System.getProperty("deviceNames").split(","));
                TestNG tng = new TestNG();
                File initialFile = new File("testng.xml");
                InputStream inputStream = FileUtils.openInputStream(initialFile);
                Parser p = new Parser(inputStream);
                List<XmlSuite> suites = p.parseToList();
                List<XmlSuite> modifiedSuites = new ArrayList<>();
                for (XmlSuite suite : suites) {
                    XmlSuite modifiedSuite = new XmlSuite();
                    modifiedSuite.setParallel(suite.getParallel());
                    modifiedSuite.setThreadCount(deviceNames.size());
                    modifiedSuite.setName(suite.getName());
                    modifiedSuite.setListeners(suite.getListeners());
                    List<XmlTest> tests = suite.getTests();
                    for (XmlTest test : tests) {
                        for (int i = 0; i < deviceNames.size(); i++) {
                            XmlTest modifedtest = new XmlTest(modifiedSuite);
                            HashMap<String, String> parametersMap = new HashMap<>();
                            parametersMap.put("deviceName", deviceNames.get(i));
                            modifedtest.setParameters(parametersMap);
                            modifedtest.setName(test.getName() + "Device - " + deviceNames.get(i) +
                                    ", OS Version - " + platformVersions.get(i));
                            modifedtest.setXmlClasses(test.getXmlClasses());
                        }
                    }
                    modifiedSuites.add(modifiedSuite);
                }
                inputStream.close();
                tng.setXmlSuites(modifiedSuites);
                tng.run();

I am adding runtime parameters to each and every test based on the parameters passed in the maven runtime arguments. You could use the same approach for passing test names or class names as runtime arguments and update your testng XML file as per your need.

Upvotes: 1

Anatoliy Sakhno
Anatoliy Sakhno

Reputation: 156

Adjusted core from here:

 public class DynamicTestNG {
 public void runTestNGTest(Map<String,String> testngParams)
 {   //Create an instance on TestNG 
     TestNG myTestNG = new TestNG();   

     //Create an instance of XML Suite and assign a name for it. 
      XmlSuite mySuite = new XmlSuite(); 
      mySuite.setName("Suite"); 
      mySuite.setParallel(XmlSuite.ParallelMode.METHODS);   

     //Create an instance of XmlTest and assign a name for it.  
     XmlTest myTest = new XmlTest(mySuite); 
     myTest.setName("Test");   
     //add groups
     myTest.addIncludedGroup("PrometheusHome")
     myTest.addIncludedGroup("AlertMgrHome")

     //Add any parameters that you want to set to the Test. 
     myTest.setParameters(testngParams); 

     //Create a list which can contain the classes that you want to run.
     List<XmlClass> myClasses = new ArrayList<XmlClass>();
     myClasses.add(new XmlClass("com.amex.eag.telemetry.testcases.PrometheusTests"));   
     myClasses.add(new XmlClass("com.amex.eag.telemetry.testcases.AlertManagerTests"));   

     //Assign that to the XmlTest Object created earlier. 
     myTest.setXmlClasses(myClasses);   

     //Create a list of XmlTests and add the Xmltest you created earlier to it.
     List<XmlTest> myTests = new ArrayList<XmlTest>(); 
     myTests.add(myTest);   

     //add the list of tests to your Suite. 
     mySuite.setTests(myTests);   

     //Add the suite to the list of suites. 
     List<XmlSuite> mySuites = new ArrayList<XmlSuite>(); 
     mySuites.add(mySuite);   

     //Set the list of Suites to the testNG object you created earlier. 
     myTestNG.setXmlSuites(mySuites);
     mySuite.setFileName("myTemp.xml"); 
     mySuite.setThreadCount(3);   
     myTestNG.run();

     //Create physical XML file based on the virtual XML content 
     for(XmlSuite suite : mySuites) 
     {  
         createXmlFile(suite); 
     }   
     System.out.println("File generated successfully.");   

     //Print the parameter values 
     Map<String,String> params = myTest.getParameters(); 
     for(Map.Entry<String, String> entry : params.entrySet()) 
     { 
       System.out.println(entry.getKey() + " => " + entry.getValue()); 
     }
    }
    //This method will create an Xml file based on the XmlSuite data 
    public void createXmlFile(XmlSuite mSuite) 
    { 
       FileWriter writer; 
       try { 
            writer = new FileWriter(new File("myTemp.xml")); 
            writer.write(mSuite.toXml()); 
            writer.flush(); 
            writer.close(); 
            System.out.println(new File("myTemp.xml").getAbsolutePath());
           } catch (IOException e)
            {
              e.printStackTrace(); 
            }
    }
   //Main Method
   public static void main (String args[]) 
   { 
      DynamicTestNG dt = new DynamicTestNG(); 
      //This Map can hold your testng Parameters. 
      Map<String,String> testngParams = new HashMap<String,String> ();
      testngParams.put("device1", "Desktop"); 
      dt.runTestNGTest(testngParams); 
   }
 }

Upvotes: 3

Related Questions