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;
publicclass test {
@DataProvider(name = "user")
public Object[][] createUser(Method m) {
System.out.println(m.getName());
returnnew Object[][] { {
}
@Test(dataProvider = "user")
publicvoid verifyUser(String username, String password) {
System.out.println("Verify User : " + username + ":" + password);
assertusername.equals(password);
}
}
如上所示@DataProvider註解了createUser
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;
publicclass CSVData implements Iterator<Object[]> {
private BufferedReader br = null;
//行數
privateintrowNum = 0;
//獲取次數
privateintcurRowNo = 0;
//列數
privateintcolumnNum = 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 (inti = 0; i < stringValue.length; i++) {
columnName[i] = stringValue[i].toString();
}
this.curRowNo++;
csvListNeed = new ArrayList<String>();
for (inti = 1; i < rowNum; i++) {
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
publicboolean hasNext() {
if (this.rowNum == 0 || this.curRowNo >= this.rowNum) {
try {
br.close();
} catch (Exception e) {
e.printStackTrace();
}
returnfalse;
} else {
returntrue;
}
}
@Override
public Object[] next() {
/*
* 將資料放入map
*/
Map<String, String> s = new TreeMap<String, String>();
String csvCell[] = csvListNeed.get(0).split(",");
for (inti = 0; i < this.columnNum; i++) {
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++;
returnr;
}
@Override
publicvoid remove() {
thrownew 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;
publicclass 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;
publicclass DataTest extends DataProviderTest {
@Test(dataProvider = "dataSource")
publicvoid id2(Map<String, String> data) {
System.out.println(data);
}
@Test(dataProvider = "dataSource")
publicvoid 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, [email protected]})
PASSED: id2({caseId=id2, flag=M, property=context, type=java.util.Map, value=a:[email protected]})
總結
通過以上例子可以看到,無論@DataProvider註解的方法返回的是Object[ ][ ]還是Iterator<Object>[],最後測試方法獲得的引數都是Object[ ]裡放的東西,第一個例子裡放了兩列String,第二個例子裡放了Map<String, String>,所以第一個測試類的測試方法的引數是兩個String,第二個測試類的測試方法的引數是Map<String, String>,必須保持一致才行。