简体   繁体   中英

How to run multiple test cases in testng with different set of test data from excel file?

I have following testng.xml, my project contains multiple classes each with one @Test testNG Method and its relevant Data Provider (means class I1_DoLoginTest contain one method and its dataprovider, class I2_CreateScenarioTest contain one method and its dataprovider and class I3_RunSimulationTest contain one method and its dataprovider)

Refer Structure of each of these 3 class very similar to this:

 public class I1 { @Test(priority = 1,dataProvider="dp_i1_Login") public void I1_LoginTestCase(){ //Processing data from dataprovider given below } @DataProvider(name="dp_i1_Login") public Object[][] dp_i1_Login() throws Exception{ //return fetching single row data in the form object array from excelsheet //to be processed by test case } }

So basically I have class with dataprovider which provides one row data from at a time, each cell will be passed as a parameter to @Test method of same class and then control moves to next class that is I2_CreateScenarioTest and then I3_RunSimulationTest (Both I2_CreateScenarioTest and I3_RunSimulationTest have same structure as I1_LoginTestCase)
testng.xml structure is as:

 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite guice-stage="DEVELOPMENT" name="Default suite"> <test verbose="2" name="Default test"> <classes> <class name="com.als.I1"/> <class name="com.als.I2"/> <class name="com.als.I3"/> </classes> </test> <!-- Default test --> </suite> <!-- Default suite -->

My problem is execution sequence of all these 3 classes, I have picked 1 row from different excel sheets (refer structure of excel sheet here Excel Sheet )

For example if there are 2 rows in every sheet which provides data then, Current execution of testng suit(testng.xml) is like executing classes as I1-I1-I2-I2-I3-I3 but I want to execute classes like I1-I2-I3-I1-I2-I3.

single method executing its dataprovider's data twice as 2 rows in its respective sheet, but I need to move execution control to second class which is I2 as soon as class I1 reads and process 1st row from excel sheet, and similarly for class I2, I2 also process one row and move to I3 and this whole execution sequence(I1-I2-I3) should be repeat for second rows of their respective sheets, each row in each individual excel sheet collectively represent one test suit data, and second row in each individual excel sheet collectively represent second test suit data. I want execution of testng classes as I1-I2-I3-(for all rows 1)-I1-I2-I3-(for all rows 2) instead of I1-I1-I2-I2-I3-I3(row 1-row 2,row 1-row 2,row 1-row 2)

You cannot do this currently in TestNG. TestNG would basically run through a class which has a @Test test powered by a data provider and iterate all the data provider provided data sets, before it picks up the next class in your <test> tag. If you have enabled parallelism this would happen in parallel but not the way in which you are expecting.

However, you can try doing the following :

Build a test class that is driven by a @Factory annotated constructor and tie this constructor's @Factory annotation to a @DataProvider annotated data provider.

Within your test class house all of your @Test methods which are currently scattered across multiple classes.

This arrangement would cause TestNG to pick a row of data from your data provider, feed it to the constructor to instantiate your test class and after that, your @Test methods can basically work with the data that was injected into it via the constructor. So for every row of data that your data provider gives, a test class instance is created. That is the only way in which you can achieve what you are looking for.

Here's a sample :

import static org.testng.Assert.assertTrue;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Factory;
import org.testng.annotations.Test;

import java.util.HashMap;
import java.util.Map;

public class SampleTestClass {
    private String name;
    private int age;
    private Map<String, Integer> marks;

    @Factory(dataProvider = "getData")
    public SampleTestClass(String name, int age, Map<String, Integer> marks) {
        this.name = name;
        this.age = age;
        this.marks = marks;
    }

    @DataProvider(name = "getData")
    public static Object[][] testData() {
        return new Object[][]{
                {"Amar", 16, marksInSubjects(45, 55, 65)},
                {"Akbar", 16, marksInSubjects(55, 65, 75)},
                {"Antony", 16, marksInSubjects(35, 45, 55)},
        };
    }

    @Test
    public void testName() {
        assertTrue(name != null && !name.trim().isEmpty(), "Should have received a valid name");
    }

    @Test
    public void testAge() {
        assertTrue(age > 0 && age < 30, "Should have received a valid age.");
    }

    @Test(dataProvider = "marks")
    public void testMarks(String subject, int marks) {
        boolean validSubject = subject != null && !"sports".equalsIgnoreCase(subject.trim());
        assertTrue(validSubject, "Should have received a valid subject");
        assertTrue(marks >= 40, this.name + " didn't pass in " + subject);
    }

    @DataProvider(name = "marks")
    public Object[][] getMarks() {
        Object[][] marks = new Object[this.marks.size()][1];
        int index = 0;
        for (Map.Entry<String, Integer> mark : this.marks.entrySet()) {
            marks[index++] = new Object[]{mark.getKey(), mark.getValue()};
        }
        return marks;
    }

    private static Map<String, Integer> marksInSubjects(int m1, int m2, int m3) {
        Map<String, Integer> marks = new HashMap<>();
        marks.put("english", m1);
        marks.put("science", m2);
        marks.put("mathematics", m3);
        return marks;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM