Selenium WebDriver – How To Create TestNG Suite XML From Spreadsheet

Overview:

If we use testNG framework, it could be difficult to maintain the testNG suite xml for a huge project where we have thousands of test cases. For such projects, it is convenient to maintain the tests in a spreadsheet & create the testNG suite xml from the spreadsheet.

In this article, let’s see how we could create the testNG suite XML file at run time!

Sample Spreadsheet:

Lets assume, I keep all my test cases in a spreadsheet as shown here.

  • Description column is used to provide high level description of the test. It is used as the value of the name tag in testNG suite xml.
  • There is an Active indicator to run only Active (marked as ‘Y’) test cases. We might not want to run all.
  • There is a Module column to group the tests. For ex: All tests related to Order module should be executed.
  • ClassName column shows the list of classes (comma separated) to be executed as part of the test.
  • Data column (you could add more coulmns for data) is used to pass the data as the parameter to the test in the testNG suite XML.

testng-xls-1

I would want to query the above spreadsheet to get the specific tests. For example, If I need to execute all the active and order module tests, I would be using SQL as shown here.

Select * from TestCase where Active = 'Y' and Module = 'Order';

 Fillo:

To query the spreadsheet, I have been using Fillo for the past few years. It is just a Java API to query xls, xlsx files. The advantage of using Fillo here is, it treats your spreadsheet as a database and each sheet as a table of  the database.

Check here for the maven dependency and some sample code to use the library.

Suite Object Implementation:

First lets create a class diagram for the testNG suite xml. We could expect the testNG suite xml in the below format

<suite name="suite-name">
   <test name="test-name">
      <parameter name="param-name" value="param-value" />
      <classes>
         <class name="com.testautomationguru.test.Test1" />
     <class name="com.testautomationguru.test.Test2" />
      </classes>
   </test>
</suite>

So, our class hierarchy will be as shown here.

suite (name)
	test (name)
		parameter (name, value)
		classes
			class (name)

For the above model, test, class, parameter could be Lists.

I add the below mvn dependencies in my java project.

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.0.pr4</version>
</dependency>
<dependency>
    <groupId>com.codoid.products</groupId>
    <artifactId>fillo</artifactId>
    <version>1.15</version>
</dependency>

I create a Suite.java to represent the above class hierarchy – I would create an instance of this class by reading the spreadsheet, so that I could export this as a testNG xml.

@JacksonXmlRootElement(localName = "suite")
public class Suite {

    @JacksonXmlProperty(isAttribute = true)
    private String name;

    @JacksonXmlProperty(localName = "test")
    @JacksonXmlElementWrapper(useWrapping = false)
    private List < Test > tests;

    public Suite(String name) {
        this.name = name;
        this.tests = new ArrayList < Suite.Test > ();
    }

    public void addTest(String testname, String paramName, String paramValue, String className) {
        Test test = new Test(testname);
        test.addParam(paramName, paramValue);
        Pattern.compile(",").splitAsStream(className).forEach(test::addClass);
        this.tests.add(test);
    }

    class Test {

        @JacksonXmlProperty(isAttribute = true)
        private String name;

        @JacksonXmlProperty(localName = "parameter")
        private Parameter param;

        @JacksonXmlProperty(localName = "classes")
        private Classes klasses;

        public Test(String name) {
            this.name = name;
            klasses = new Classes();
        }

        public void addParam(String name, String value) {
            param = new Parameter(name, value);
        }

        public void addClass(String name) {
            klasses.assClasses(name);
        }

    }

    class Parameter {
        @JacksonXmlProperty(isAttribute = true)
        private String name;

        @JacksonXmlProperty(isAttribute = true)
        private String value;

        public Parameter(String name, String value) {
            this.name = name;
            this.value = value;
        }

    }

    class Classes {

        @JacksonXmlProperty(localName = "class")
        @JacksonXmlElementWrapper(useWrapping = false)
        private List < Class > classes;

        public Classes() {
            this.classes = new ArrayList < Suite.Class > ();
        }

        public void assClasses(String name) {
            this.classes.add(new Class(name));
        }
    }

    class Class {

        @JacksonXmlProperty(isAttribute = true)
        private String name;

        Class(String name) {
            this.name = name;
        }

    }

}

XLS Reader:

I create a sample XLS reader as shown here using Fillo. I query the spreadsheet and then create the xml.

public class XLSReader {

    private final Fillo fillo;
    private final String filePath;

    private Connection connection;

    public XLSReader(String filePath) {
        fillo = new Fillo();
        this.filePath = filePath;
    }

    public void getTests(String query) {
        try {
            connection = fillo.getConnection(this.filePath);
            Recordset recordset = connection.executeQuery(query);
            this.createSuite(recordset);
        } catch (FilloException e) {
            e.printStackTrace();
        } finally {
            connection.close();
        }
    }

    private void createSuite(Recordset recordset) {
        XmlMapper xmlMapper = new XmlMapper();
        Suite suite = new Suite("TesTautomationGuru");
        try {
            while (recordset.next()) {

                String testName = recordset.getField("TestCaseDescription");
                String className = recordset.getField("ClassName");
                String param = "Data";
                String paramValue = recordset.getField("Data");

                suite.addTest(testName, param, paramValue, className);
            }
            xmlMapper.writeValue(new File("c:/testng-suite.xml"), suite);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            recordset.close();
        }
    }

}

TestNG Suite XML:

Simply executing specific query will fetch corresponding tests and create a testng xml at run time as shown here.

XLSReader suite = new XLSReader("tests.xls");
suite.getTests("select * from TestCase where module='Order'");

testng xml output:

<suite name="TesTautomationGuru">
   <test name="Testcase Description 1">
      <parameter name="Data" value="data1" />
      <classes>
         <class name="com.testautomationguru.test.Test1" />
         <class name="com.testautomationguru.test.Test2" />
      </classes>
   </test>
   <test name="Testcase Description 2">
      <parameter name="Data" value="data2" />
      <classes>
         <class name="com.testautomationguru.test.Test3" />
         <class name="com.testautomationguru.test.Test4" />
      </classes>
   </test>
   <test name="Testcase Description 3">
      <parameter name="Data" value="data3" />
      <classes>
         <class name="com.testautomationguru.test.Test5" />
      </classes>
   </test>
   <test name="Testcase Description 4">
      <parameter name="Data" value="data4" />
      <classes>
         <class name="com.testautomationguru.test.Test6" />
      </classes>
   </test>
   <test name="Testcase Description 5">
      <parameter name="Data" value="data5" />
      <classes>
         <class name="com.testautomationguru.test.Test7" />
      </classes>
   </test>
   <test name="Testcase Description 6">
      <parameter name="Data" value="data6" />
      <classes>
         <class name="com.testautomationguru.test.Test8" />
      </classes>
   </test>
   <test name="Testcase Description 7">
      <parameter name="Data" value="data7" />
      <classes>
         <class name="com.testautomationguru.test.Test9" />
      </classes>
   </test>
</suite>

Summary:

Above approach for creating testNG suite xml at run time saves a lot of time in maintaining the suite file for big projects where we could have thousands of test cases.  We maintain all the tests in a spreadsheet and simply tag the module names to logically group the tests. So that I could use SQL to filter specific tests I need to execute.

Happy Testing & Subscribe 🙂

 

 

Share This:

4 thoughts on “Selenium WebDriver – How To Create TestNG Suite XML From Spreadsheet

  1. Hi Expert,
    my requirement is the same as you given the solution but I am trying your code and it’s not working for me, I am getting below error while execution. Please help

    Error:
    [RemoteTestNG] detected TestNG version 6.14.3

    ===============================================
    Default test

    Tests run: 0, Failures: 0, Skips: 0

    ===============================================
    Default suite

    Total tests run: 0, Failures: 0, Skips: 0

    [TestNG] No tests found. Nothing was run
    Usage: [options] The XML suite files to run

    1. Aim of this post is to give someone an idea. not to provide the code which will work for everyone. In your case, you can have multiple data parameters and update suite accordingly.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.