Reputation: 1101
I am using TestNG for my selenium tests. There is a test called "Create Firm" which needs to be run multiple times on my laptop.
So I have written a class called "CreateFirm" for this, and the data for various firms reside in an excel spreadsheet.
At various times, I need to create various sets of firms, which I control using a column in Excel spreadsheet , which holds my computer name.
I use the @Factory to create my "CreateFirm" classes, which has one @Test method to create a Firm.
In excel spreadsheet If i have assigned Firm1,Firm2,Firm3,Firm4 in the same order to my laptop, @Factory creates them in a random order like Firm4,Firm3,Firm1,Firm2
My question is how to get @Factory to create test instances in the order that I want ?
My @Factory method is
@Factory
public Object[] runCreateFirm()
{
//This is where I get the list of test cases assigned to my laptop
this.test_id_list=get_test_ids_for_test_run("Create Firm (class approach).xls", "Global");
Object[] result = new Object[this.test_id_list.size()];
int index=0 ;
for (String firm_id: this.test_id_list)
{
//This is where I get all the test data from the Excel spreadsheet
HashMap<String,String> test_data_row=this.get_row_from_excel("Create Firm (class approach).xls", "Global", "test_case_id", firm_id);
System.out.println("Inside Firm Factory ,index="+index +", test case id="+ test_data_row.get("test_case_id"));
//CreateFirm is the class which will use the data and do all the UI actions to create a Firm
result[index]=new CreateFirm(test_data_row);
index++;
}
return result;
}
XML is
<?xml version="1.0" encoding="UTF-8"?>
<suite name="CreateFirm Suite">
<test name="Create Firm Test" order-by-instances="false">
<classes>
<class name="regressionTests.factory.CreateFirmFactory"/>
</classes>
</test>
</suite>
Upvotes: 0
Views: 3109
Reputation: 41
Referred https://github.com/cbeust/testng/issues/1410 for the solution and got a hint from example given by krmahadevan. Thanks a bunch KR. I am using TestNG plugin version 6.14.0.201802161500 in Eclipse.
Just overriding toString method in the Test Class does the trick. In this toString method return the key parameter e.g. Firm1, Firm2 etc. Please refer following code for a clear understanding.
TestClass.java
import org.testng.annotations.Test;
public class TestClass {
String testcaseName;
public TestClass(String testcaseName) {
this.testcaseName = testcaseName;
}
@Test
public void sendCmd() {
System.out.println("Testcase received "+this.testcaseName);
}
@Override
public String toString() {
return this.testcaseName;
}
}
FactoryClass.java
import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
public class FactoryClass {
@DataProvider
public static String[][] createTestCmds() {
String[][] testData = new String[6][1];
for (int i = 0, j= 6; i < 6 ; i++,j--) {
testData[i][0]="Firm "+i;
}
return testData;
}
@Factory(dataProvider = "createTestCmds")
public Object[] Factory(String testcaseName) {
return new Object[] {new TestClass(testcaseName)};
}
}
Test.java
import java.util.Collections;
import org.testng.TestNG;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;
public class Test {
public static void main(String[] args) {
TestNG testng = new TestNG();
XmlSuite xmlSuite = new XmlSuite();
xmlSuite.setGroupByInstances(true);
xmlSuite.setName("Sample_Test_Suite");
XmlTest xmlTest = new XmlTest(xmlSuite);
xmlTest.setName("Sample_Test");
xmlTest.setClasses(Collections.singletonList(new XmlClass(FactoryClass.class)));
testng.setXmlSuites(Collections.singletonList(xmlSuite));
testng.setVerbose(2);
System.err.println("Printing the suite xml file that would be used.");
System.err.println(xmlSuite.toXml());
testng.run();
}
}
Testcase received Firm 0
Testcase received Firm 1
Testcase received Firm 2
Testcase received Firm 3
Testcase received Firm 4
Testcase received Firm 5
PASSED: sendCmd on Firm 0
PASSED: sendCmd on Firm 1
PASSED: sendCmd on Firm 2
PASSED: sendCmd on Firm 3
PASSED: sendCmd on Firm 4
PASSED: sendCmd on Firm 5
===============================================
Sample_Test
Tests run: 6, Failures: 0, Skips: 0
===============================================
===============================================
Sample_Test_Suite
Total tests run: 6, Failures: 0, Skips: 0
===============================================
This problem I faced. I got a solution as mentioned above.
Upvotes: 0
Reputation: 1101
Managed to write the interceptor method for my requirement. To start with I introduced a new field in my class called "priority" . I couldnt use @Priority because, my test class had only one test method, in which case all my instantiations will have the same priority. So I introduced a new field called priority which will have the order in which which the class should be instantiated. I use that field in the interceptor method to set the order of instantiation
public List<IMethodInstance> intercept(List<IMethodInstance> methods,ITestContext context)
{
List<IMethodInstance> result = new ArrayList<IMethodInstance>();
int array_index=0;
for (IMethodInstance m : methods)
{
result.add(m);
}
//Now iterate through each of these test methods
for (IMethodInstance m : methods)
{
try {
//Get the FIELD object from - Methodobj->method->class->field
Field f = m.getMethod().getRealClass().getField("priority");
//Get the object instance of the method object
array_index=f.getInt(m.getInstance());
}
catch (Exception e) {
e.printStackTrace();
}
result.set(array_index-1, m);
}
return result;
}
Upvotes: 2
Reputation: 15608
The factory instantiates test classes, it doesn't run them. If you need a specific order for your tests, you have a lot of choices between dependencies (groups and methods), priorities and method interceptors.
Upvotes: 1