Here's how you do it.
- You first build an implementation of
org.testng.IAnnotationTransformer
and org.testng.IAlterSuiteListener
- Within this implementation's constructor, you read/parse the JSON/CSV/XML/YAML file that contains the method to group mapping.
- Within the
transform()
method, you filter out methods that match the incoming method and then add the groups as found in the data source file from (2).
- Within the
alter()
you read a JVM argument that hints at which groups to be filtered and then apply that filter accordingly.
Here's a full fledged sample that uses the Google Gson library for json parsing.
Here's my test class
package com.rationaleemotions.runtime;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.annotations.Test;
public class DemoClass1 {
@Test
public void testMethod1() {
printer();
}
@Test
public void testMethod2() {
printer();
}
private static void printer() {
ITestResult itr = Reporter.getCurrentTestResult();
System.err.println(itr.getMethod().getQualifiedName() + " belongs to the groups " +
Arrays.stream(itr.getMethod().getGroups()).collect(Collectors.toList()));
}
}
Here's how the listener would look like
package com.rationaleemotions.runtime;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.List;
import java.util.stream.StreamSupport;
import org.testng.IAlterSuiteListener;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.ITestAnnotation;
import org.testng.xml.XmlGroups;
import org.testng.xml.XmlRun;
import org.testng.xml.XmlSuite;
public class GroupChanger implements IAnnotationTransformer, IAlterSuiteListener {
private JsonArray json;
public GroupChanger() throws FileNotFoundException {
String mapping = System.getProperty("mapping.file", "src/test/resources/file.json");
if (!mapping.trim().isEmpty()) {
json = JsonParser.parseReader(new FileReader(mapping))
.getAsJsonArray();
}
}
@Override
public void alter(List<XmlSuite> suites) {
String groupsToRun = System.getProperty("groups", "g1");
if (groupsToRun.equalsIgnoreCase("*")) {
//Execute everything. So don't add groups filtering in the suite file
return;
}
for (XmlSuite suite: suites) {
XmlGroups xmlGroups = new XmlGroups();
XmlRun xmlRun = new XmlRun();
for (String group : groupsToRun.split(",")) {
xmlRun.onInclude(group);
}
xmlGroups.setRun(xmlRun);
suite.setGroups(xmlGroups);
}
}
@Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor,
Method testMethod) {
if (testMethod == null) {
return;
}
if (json == null) {
return;
}
String fqmn = testMethod.getDeclaringClass().getCanonicalName() + "." + testMethod.getName();
StreamSupport.stream(json.spliterator(), true)
.filter(each -> methodName(each).equalsIgnoreCase(fqmn))
.findFirst()
.ifPresent(each -> {
System.err.println("Found " + each);
annotation.setGroups(groups(each));
});
}
private static String methodName(JsonElement each) {
return each.getAsJsonObject().get("method").getAsString();
}
private static String[] groups(JsonElement each) {
return each.getAsJsonObject().get("groupName").getAsString().split(",");
}
}
Here's how the suite file would look like
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="groups_suite" verbose="2">
<listeners>
<listener class-name="com.rationaleemotions.runtime.GroupChanger"/>
</listeners>
<test name="groups_test" verbose="2">
<classes>
<class name="com.rationaleemotions.runtime.DemoClass1"/>
</classes>
</test>
</suite>
Here's how the json mapping would look like
[
{
"method": "com.rationaleemotions.runtime.DemoClass1.testMethod1",
"groupName": "g1"
},
{
"method": "com.rationaleemotions.runtime.DemoClass1.testMethod2",
"groupName": "g2"
}
]