@DataProvider(name="testData", parallel = true}
Object[][] data() {
return new Object[][]{{"one"}, {"two"}}; // test data e.g., but its actually read in a @BeforeTest method and returned here.
}
Thats how we all write data providers. But I am facing a problem when I want to decide when to make it parallel or not based on a parameter which is defined in the test suite whose value I can only read during runtime, but the annotations need a constant.
As I am modifying an existing test library where users only need to add a test suite and test data file (array of request and response), I am trying to enable the parallel runs of their test cases (using parallel in data provider with value read from test suite).
So, test suite will have information like
<hostName>google.com</hostName>
<port>8443</port>
<protocol>https</protocol>
Similarly, will add
<runInParallel>true</runInParallel>
And test-data file will be like below which basically is a set of test cases and served via data provider in the library:
[
{
"test_id": 1,
"request": "some-json",
"response": "some-json"
},
{
"test_id": 2,
"request": "some-json",
"response": "some-json"
}
]
Can you suggest me how to achieve this without a nasty hack (no harm to learn that too)?
Currently TestNG does not have this support that you ask for (i.e., be able to read the parallel mode from the <suite>
and then apply the parallel execution strategy for the data provider).
But we can still do this using TestNG as listed below:
7.7.1
)IAnnotationTransfromer
as shown below<listener>
tag or using the service loader mechanism as explained in the official TestNG documentation-Ddp.parallel.mode
The reason why TestNG does not support reading the suite file parameters and apply it to the IAnnotationTransformer
is because the IAnnotationTransformer
gets invoked first so as to help TestNG collect all the methods to be executed and ONLY later does any other suite listener get invoked. Currently we can read the suite parameters ONLY via any of the suite listener.
import java.lang.reflect.Method;
import org.testng.IAnnotationTransformer;
import org.testng.annotations.IDataProviderAnnotation;
public class DataProviderAlteringListener implements IAnnotationTransformer {
@Override
public void transform(IDataProviderAnnotation annotation, Method method) {
boolean runInParallel = Boolean.getBoolean("dp.parallel.mode");
if (runInParallel) {
annotation.setParallel(true);
}
}
}
Quoting the documentation for the service loader part (for the sake of completeness of this answer)
create a file at the location META-INF/services/org.testng.ITestNGListener, which will name the implementation(s)
Here the implementation would basically be the fully qualified class name of DataProviderAlteringListener