TestNG数据驱动 testng的功能很强大,利用@DataProvider可以做数据驱动,数据源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本。
@DataProvider注解简介:
@DataProvider标记专门为测试方法提供参数的方法。这类方法必须返回Object[ ][ ]类型的二维数组或者Iterator[],每一行的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 {
private BufferedReader br = null;
//行数
private int rowNum = 0;
//获取次数
private int curRowNo = 0;
//列数
private int columnNum = 0;
//key名
private String[] columnName;
//csv中所有行数据
private List csvList;
//实际想要的行数据
private List csvListNeed;
public CSVData(String fileName, String caseId) {
try {
File directory = new File(".");
String ss = "resources.";
File csv = new File(directory.getCanonicalFile() + "src est" + ss.replaceAll(".", Matcher.quoteReplacement(""))
+ fileName + ".csv");
br = new BufferedReader(new FileReader(csv));
csvList = new ArrayList();
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.length; i++) {
columnName[i] = stringValue[i].toString();
}
this.curRowNo++;
csvListNeed = new ArrayList();
for (int i = 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
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 s = new TreeMap();
String csvCell[] = csvListNeed.get(0).split(",");
for (int i = 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++;
return r;
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove unsupported");
}
}
这个类实现了Iterator迭代器,TestNG调用此类实现的hasNext()、next()方法得到一行数据,在next()方法中可以看到,我把数据是放在Map中的,再把map放在Object[]里,所以测试方法的参数就必须是一个Map。我这里改成了只读取一行,因为一个csv文件的一个caseId只应该有一行。
数据驱动类:
import java.lang.reflect.Method;
import java.util.Iterator;
import org.testng.annotations.DataProvider;
public class DataProviderTest {
@DataProvider
public Iterator dataSource(Method method) {
return (Iterator) new CSVData(method.getDeclaringClass().getSimpleName(), method.getName());
}
}
Method方法是通过反射获取的,总之哪个方法调用我Method就是那个方法。
method.getDeclaringClass().getSimpleName()可以获取方法所属的类的类名。
我这里规定了csv的文件名就是测试类的类名,用例名就是方法名。
return (Iterator) new CSVData(…)就是将CSV读取类读取的结果返回,返回的类型是Iterator的,符合@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 data) {
System.out.println(data);
}
@Test(dataProvider = "dataSource")
public void id1(Map data) {
System.out.println(data);
}
}
输出结果如下:
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[ ]里放的东西,第一个例子里放了两列String,第二个例子里放了Map,所以第一个测试类的测试方法的参数是两个String,第二个测试类的测试方法的参数是Map,必须保持一致才行。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341