I am writing unit tests in Java with TestNG 6.14.3 using @DataProvider
What I want to achieve:
What I have tried:
I have added an extra parameter and followed this guide,
the issue with that is that now I have an unused parameter caseName
in every test which I do not want.
Create a custom DataProvider
annotation which ignore the first parameter, this did not work since I can not find a way to integrate it with TestNG
.
My questions:
Thank you!
One solution might be to declare a String
array of names in the test class and take then in order. This would work if you are NOT running your test in parallel.
Otherwise, you may make use of @Factory
annotation, which could take the input from data provider and then create the test object.
@Factory(dataProvider = "data")
public Object[] createInstances(String val, String name) {
return new Object[] { new MyTest(name) };
}
@DataProvider
public Object[][] data() {
return new Object[][] { { "a", "one" }, { "b", "two" } };
}
So you need a name
field in your test class, which would be set using the constructor. Combining the code suggested in the link to set the test name you could do as:
public class MyTest implements ITest {
private String name;
private ThreadLocal<String> testName = new ThreadLocal<>();
public MyTest() {
}
public MyTest(String name) {
this.name = name;
}
@Factory(dataProvider = "data")
public Object[] createInstances(String name) {
return new Object[] { new MyTest(name) };
}
@DataProvider
public Object[][] data() {
return new Object[][] { { "one" }, { "two" } };
}
@BeforeMethod
public void beforeMethod(Method method) {
testName.set(method.getName() + "_" + name);
}
@Test
public void test() {
System.out.println(name);
}
@Override
public String getTestName() {
return testName.get();
}
}
EDIT: Without using a Factory
, this could be achieved as below. This requires setting the relevant details in the ITestContext
:
@DataProvider
public Object[][] data(ITestContext ctx) {
ctx.setAttribute("names", new String[]{"one", "two"});
ctx.setAttribute("index", 0);
return new Object[][] { {"val1", "data1"}, {"val2", "data2"} };
}
Now in the beforeMethod
inject ITestContext
as well:
@BeforeMethod
public void beforeMethod(ITestContext ctx, Method method) {
testName.set(method.getName() + "_" + getName(ctx));
}
// Create a helper method getName.
private static String getName(ITestContext ctx) {
int index = (int) ctx.getAttribute("index");
// get the name based on the current index.
String name = ((String[]) ctx.getAttribute("names"))[index++];
// update the attribute with the incremented index.
ctx.setAttribute("index", index);
return name;
}
@Test(dataProvider = "data")
public void yourTest(String val, String data) {
// .............
}
NOTE: This will not work as expected when test is run parallelly.