More about making a testng.xml at runtime

We would first recommend you read our previous post on how to make testng.xml programmatically, as this post will continue the previous one. We have covered some of the basics, and in this post, we will be focusing on some new and exciting things that we could do while making testng.xml at runtime or programmatically.

We will be covering the below things.

First, let’s make a test class( say CodekruTest ) and some cases that we will use throughout our post and learn some exciting things.

package Test;

import org.testng.Assert;
import org.testng.annotations.Test;

public class CodekruTest {

	@Test
	public void test1() {
		System.out.println("Executing test1");
		Assert.assertTrue(true);
	}

	@Test
	public void test2() {
		System.out.println("Executing test2");
		Assert.assertTrue(true);
	}

	@Test
	public void test3() {
		System.out.println("Executing test3");
		Assert.assertTrue(true);
	}
	
}

How to use included methods functionality while making testng.xml at runtime?

As you can see, we have three test methods( test1, test2, and test3 ) in the CodekruTest class, but what if we only wanted to execute only two test methods ( test1, test3 ) of the class? How do we achieve that?

We would be making an XML file using the <include> tags, and then we would include those two methods within the <include> tag and ignore the third one.

<suite name="codekru">
	<test name="codekruTest">
		<classes>
			<class name="Test.CodekruTest">
				<methods>
					<include name="test1" />
					<include name="test3" />
				</methods>
			</class>
		</classes>
	</test>
</suite>

Now, how do we create the above XML file programmatically?

We have an equivalent of the <include> tag in the XML file which is XmlInclude class in TestNG. So, the syntax to include test methods would be like below –

XmlInclude includedtestMethod1 = new XmlInclude("test1");
XmlInclude includedtestMethod3 = new XmlInclude("test3");

We would add these methods to a list, and that list would further be added to a class.

List<XmlInclude> includedMethodsList = new ArrayList<XmlInclude>();
includedMethodsList.add(includedtestMethod1);
includedMethodsList.add(includedtestMethod3);
xmlClass.setIncludedMethods(includedMethodsList);

The whole program for the above XML file would be as shown below.

import java.util.ArrayList;
import java.util.List;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlInclude;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

public class GenerateAndExecuteXML {

	public static void main(String[] args) {

		XmlSuite suite = new XmlSuite();
		suite.setName("codekru"); // equivalent of <suite> tag

		XmlTest test = new XmlTest(suite);
		test.setName("codekruTest"); // equivalent of <test> tag

		List<XmlClass> classes = new ArrayList<XmlClass>(); // equivalent of <classes> tag
		XmlClass xmlClass = new XmlClass("Test.CodekruTest"); // equivalent of <class> tag

		// including only two test methods of a class
		XmlInclude includedtestMethod1 = new XmlInclude("test1");
		XmlInclude includedtestMethod3 = new XmlInclude("test3");
		List<XmlInclude> includedMethodsList = new ArrayList<XmlInclude>();
		includedMethodsList.add(includedtestMethod1);
		includedMethodsList.add(includedtestMethod3);
		xmlClass.setIncludedMethods(includedMethodsList);

		classes.add(xmlClass);
		test.setXmlClasses(classes);

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

	}
}

Now, you can run the above program, and it will produce the same output as would have been produced by the XML file itself.

Executing test1
Executing test3

===============================================
codekru
Total tests run: 2, Passes: 2, Failures: 0, Skips: 0
How to use excluded methods functionality while making testng.xml at runtime?

Now, we want to exclude a particular test from our class, say we want to exclude the test1 method from our class. We can achieve this by using the <exclude> tag as shown in the below XML, where only the test1() method is added within the <exclude> tag.

<suite name="codekru">
	<test name="codekruTest">
		<classes>
			<class name="Test.CodekruTest">
				<methods>
					<exclude name="test1"/>
				</methods>
			</class>
		</classes>
	</test>
</suite>

Now the question is how we can achieve the same thing using code? TestNG provides us an easy way to do it, but unlike XmlInclude class, we don’t have an XmlExlude class. Instead, we can pass the class a list of excluded methods, as shown below.

		// adding "test1" as an excluded method
		List<String> excludedMethods = new ArrayList<String>();
		excludedMethods.add("test1");
		xmlClass.setExcludedMethods(excludedMethods);

The whole program to make the XML with excluded methods functionality is below.

import java.util.ArrayList;
import java.util.List;

import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

public class Practice {

	public static void main(String[] args) {

		XmlSuite suite = new XmlSuite();
		suite.setName("codekru"); // equivalent of <suite> tag

		XmlTest test = new XmlTest(suite);
		test.setName("codekruTest"); // equivalent of <test> tag

		List<XmlClass> classes = new ArrayList<XmlClass>(); // equivalent of <classes> tag
		XmlClass xmlClass = new XmlClass("Test.CodekruTest"); // equivalent of <class> tag

		// adding "test1" as an excluded method
		List<String> excludedMethods = new ArrayList<String>();
		excludedMethods.add("test1");
		xmlClass.setExcludedMethods(excludedMethods);

		classes.add(xmlClass);
		test.setXmlClasses(classes);

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

	}
}

Now, we can run the above program as a standard java application, and it will produce the same output that the equivalent XML file would have.

Executing test2
Executing test3

===============================================
codekru
Total tests run: 2, Passes: 2, Failures: 0, Skips: 0
Now, how to change the output directory of the reports to a specific directory using the program?

This is also relatively easy with TestNG as it provides us with a method to do the same.

TestNG tng = new TestNG();
tng.setOutputDirectory("D:\\Test"); // pass the path of the directory in the argument where you want to store
				   // the reports 

The whole program to execute a test class and save the reports to a specific directory is shown below.

import java.util.ArrayList;
import java.util.List;

import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

public class Practice {

	public static void main(String[] args) {

		XmlSuite suite = new XmlSuite();
		suite.setName("codekru"); // equivalent of <suite> tag

		XmlTest test = new XmlTest(suite);
		test.setName("codekruTest"); // equivalent of <test> tag

		List<XmlClass> classes = new ArrayList<XmlClass>(); // equivalent of <classes> tag
		XmlClass xmlClass = new XmlClass("Test.CodekruTest"); // equivalent of <class> tag

		classes.add(xmlClass);
		test.setXmlClasses(classes);

		List<XmlSuite> suites = new ArrayList<XmlSuite>();
		suites.add(suite);
		TestNG tng = new TestNG();
		tng.setOutputDirectory("D:\\Test"); // pass the path of the directory in the argument where you want to store
						    // the reports 
		tng.setXmlSuites(suites);
		tng.run();

	}
}

Now, all test methods in the class will run, and test reports are saved in the D:\Test folder instead of the default test-output folder.

How can we run cases in parallel programmatically?

Let’s assume that we want to run the methods of a class in parallel. Then below XML file can help us achieve the same.

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

To do the same using the program, we would only have to add the below line in our code.

test.setParallel(ParallelMode.METHODS);

Here ParallelMode is an enum.

Now, our whole program would be as shown below.

public class GenerateXmlAndExecuteAtRuntime {
	
	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);
		test.setParallel(ParallelMode.METHODS);

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

Output –

Executing test3
Executing test1
Executing test2

===============================================
codekru
Total tests run: 3, Passes: 3, Failures: 0, Skips: 0

And if we wanted to run our classes in parallel, we could have used the below line instead.

test.setParallel(ParallelMode.CLASSES);

We hope that you have liked our article. If you have any doubts or concerns, please feel free to write us in the comments or mail us at admin@codekru.com.

Liked the article? Share this on

Leave a Comment

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