TestNG數據驅動

TestNG數據驅動

testng的功能很強大,利用@DataProvider可以做數據驅動,數據源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本。

@DataProvider註解簡介:

@DataProvider標記專門爲測試方法提供參數的方法。這類方法必須返回Object[ ][ ]類型的二維數組或者Iterator<Object>[],每一行Object[],都是測試方法的一個測試數據集,測試方法會爲每個測試數據集執行一次。如果沒有指定參數的名稱,則默認爲方法的名稱,方法的名稱沒有限制。

 

@DataProvider的小例子:

import java.lang.reflect.Method;

 

import org.testng.annotations.DataProvider;

import org.testng.annotations.Test;

 

public class test {

    @DataProvider(name = "user")

    public Object[][] createUser(Method m) {

        System.out.println(m.getName());

        return new Object[][] { { "root""root" }, { "test""root" }, { "test""test" } };

    }

 

    @Test(dataProvider = "user")

    public void verifyUser(String username, String password) {

        System.out.println("Verify User : " + username + ":" + password);

        assert username.equals(password);

    }

 

}

如上所示@DataProvider註解了createUser方法,返回的二位數組裏有三行數據,每行兩列。所以@Test(dataProvider = "user")註解的verifyUser方法有兩個參數,用來接收每一行的兩個數據,如果createUser返回的數據數組的列數和verifyUser的參數個數不同就會報錯的。因爲返回的有三行,所以verifyUser會被執行三次。結果如下:

PASSED: verifyUser("root", "root")

FAILED: verifyUser("test", "root")

PASSED: verifyUser("test", "test")

CSV文件數據讀取和@DataProvider

我自己做了一個以csv爲例的測試架子,部分代碼可通用。

 

CSV文件讀取類(可通用,目錄自己可以修改,也可改變成讀取EXCEL、TXT等文件):

import java.io.BufferedReader;

import java.io.File;

import java.io.FileReader;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

import java.util.Map;

import java.util.TreeMap;

import java.util.regex.Matcher;

 

public class CSVData implements Iterator<Object[]> {

 

    private BufferedReader br        = null;

    //行數

    private int            rowNum    = 0;

    //獲取次數

    private int            curRowNo  = 0;

    //列數

    private int            columnNum = 0;

    //key名

    private String[]       columnName;

    //csv中所有行數據

    private List<String>   csvList;

    //實際想要的行數據

    private List<String>   csvListNeed;

 

    /*

    * 在TestNG中由@DataProvider(dataProvider = "name")修飾的方法

    * 取csv時,調用此類構造方法(此方法會得到列名並將當前行移到下以後)執行後,轉發哦

    * TestNG自己的方法中去,然後由它們調用此類實現的hasNext()、next()方法

    * 得到一行數據,然後返回給由@Test(dataProvider = "name")修飾的方法,如此

    * 反覆到數據讀完爲止

    * 

    * 

    * @param filepath CSV文件名

    * @param casename 用例名

    */

    public CSVData(String fileName, String caseId) {

        try {

            File directory = new File(".");

            String ss = "resources.";

            File csv = new File(directory.getCanonicalFile() + "\\src\\test\\" + ss.replaceAll("\\.", Matcher.quoteReplacement("\\"))

                                + fileName + ".csv");

 

            br = new BufferedReader(new FileReader(csv));

            csvList = new ArrayList<String>();

            while (br.ready()) {

                csvList.add(br.readLine());

                this.rowNum++;

            }

            String stringValue[] = csvList.get(0).split(",");

            this.columnNum = stringValue.length;

 

            columnName = new String[stringValue.length];

 

            for (int i = 0; i < stringValue.lengthi++) {

 

                columnName[i] = stringValue[i].toString();

 

            }

            this.curRowNo++;

            csvListNeed = new ArrayList<String>();

            for (int i = 1; i < rowNumi++) {

                String values[] = csvList.get(i).split(",");

                if (caseId.equals(values[0])) {

                    csvListNeed.add(csvList.get(i));

                }

            }

            this.rowNum = 2;//就取一行

        } catch (Exception e) {

            e.printStackTrace();

        }

    }

 

    @Override

    public boolean hasNext() {

        if (this.rowNum == 0 || this.curRowNo >= this.rowNum) {

            try {

                br.close();

            } catch (Exception e) {

                e.printStackTrace();

            }

            return false;

        } else {

            return true;

        }

    }

 

    @Override

    public Object[] next() {

        /*

        * 將數據放入map 

        */

        Map<String, String> s = new TreeMap<String, String>();

        String csvCell[] = csvListNeed.get(0).split(",");

        for (int i = 0; i < this.columnNumi++) {

            String temp = "";

            try {

                temp = csvCell[i].toString();

            } catch (ArrayIndexOutOfBoundsException ex) {

                temp = "";

            }

            s.put(this.columnName[i], temp);

        }

        Object r[] = new Object[1];

        r[0] = s;

        this.curRowNo++;

        return r;

    }

 

    @Override

    public void remove() {

        throw new UnsupportedOperationException("remove unsupported");

    }

 

}

 

這個類實現了Iterator<Object[]>迭代器,TestNG調用此類實現的hasNext()、next()方法得到一行數據,在next()方法中可以看到,我把數據是放在Map<String, String>中的,再把map放在Object[]裏,所以測試方法的參數就必須是一個Map<String, String>。我這裏改成了只讀取一行,因爲一個csv文件的一個caseId只應該有一行。

 

數據驅動類:

import java.lang.reflect.Method;

import java.util.Iterator;

 

import org.testng.annotations.DataProvider;

 

public class DataProviderTest {

 

    /**

     * @DataProvider的返回值類型只能是Object[][]與Iterator<Object>[]

     * 

     * @param method

     * @return

     */

    @DataProvider

    public Iterator<Object[]> dataSource(Method method) {

        return (Iterator<Object[]>) new CSVData(method.getDeclaringClass().getSimpleName(), method.getName());

    }

 

}

Method方法是通過反射獲取的,總之哪個方法調用我Method就是那個方法。

method.getDeclaringClass().getSimpleName()可以獲取方法所屬的類的類名。

我這裏規定了csv的文件名就是測試類的類名,用例名就是方法名。

return (Iterator<Object[]>) new CSVData(…)就是將CSV讀取類讀取的結果返回,返回的類型是Iterator<Object[]>的,符合@DataProvider的返回值類型要求。當@Test(dataProvider = "dataSource")註解的測試方法執行時就會調用Iterator的hasNext()判斷是否有數據和next()獲取數據。

 

測試類:

 

import java.util.Map;

 

import org.testng.annotations.Test;

 

public class DataTest extends DataProviderTest {

    @Test(dataProvider = "dataSource")

    public void id2(Map<String, String> data) {

        System.out.println(data);

    }

 

    @Test(dataProvider = "dataSource")

    public void id1(Map<String, String> data) {

        System.out.println(data);

    }

 

}

 

DataTest.csv文件如下:

 

輸出結果如下:

PASSED: id1({caseId=id1, flag=Y, property=flowModel, type=com.mybank.bkloanapply.core.model.BaseModel, value=BaseModel.csv@1})

PASSED: id2({caseId=id2, flag=M, property=context, type=java.util.Map, value=a:Object.csv@1})

 

總結

通過以上例子可以看到,無論@DataProvider註解的方法返回的是Object[ ][ ]還是Iterator<Object>[],最後測試方法獲得的參數都是Object[ ]裏放的東西,第一個例子裏放了兩列String,第二個例子裏放了Map<String, String>,所以第一個測試類的測試方法的參數是兩個String,第二個測試類的測試方法的參數是Map<String, String>,必須保持一致才行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章