自动化测试中,维护测试数据 是一项很重要的工作,为了达到用例和测试数据的分离,我们一般会把数据存储在外部文件 或 数据库,为了简化测试,测试用例编写人员想只需要维护测试数据文件,在用例里通过简单声明,即可随意读取本次测试用例所需要的测试数据,我的思路还是为测试用例自动注入测试数据对象。
代码如下:
定义测试对象标签,只要在用例里的类域加了此标签 测试框架便认为此域变量是个测试数据对象:
package ec.qa.autotest.ui.custom.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author xin.wang
* 自动装配标签
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataObject {
public String DataNode() default "";
}
package ec.qa.autotest.ui.admin.portal.testcases;
import java.util.HashMap;
import org.testng.annotations.Test;
import ec.qa.autotest.ui.admin.portal.pageobject.AddProductLibraryPage;
import ec.qa.autotest.ui.admin.portal.pageobject.NavigationMenu;
import ec.qa.autotest.ui.admin.portal.pageobject.ProductLibraryPage;
import ec.qa.autotest.ui.common.action.AdminLoadingProgress;
import ec.qa.autotest.ui.custom.annotation.AutoInject;
import ec.qa.autotest.ui.custom.annotation.DataObject;
import ec.qa.autotest.ui.testbase.AdminPortalTestBase;
public class AddProductLibraryProtal extends AdminPortalTestBase {
@DataObject(DataNode="AddProductLibraryPage")
private HashMap dataMap;
@Test(invocationCount = 100)
public void addProductLibrary() throws Exception {
}
}
支持同时使用多个数据块的数据:
package ec.qa.autotest.ui.admin.portal.testcases;
import java.util.HashMap;
import org.testng.annotations.Test;
import ec.qa.autotest.ui.admin.portal.pageobject.AddProductLibraryPage;
import ec.qa.autotest.ui.admin.portal.pageobject.NavigationMenu;
import ec.qa.autotest.ui.admin.portal.pageobject.ProductLibraryPage;
import ec.qa.autotest.ui.common.action.AdminLoadingProgress;
import ec.qa.autotest.ui.custom.annotation.AutoInject;
import ec.qa.autotest.ui.custom.annotation.DataObject;
import ec.qa.autotest.ui.testbase.AdminPortalTestBase;
public class AddProductLibraryProtal extends AdminPortalTestBase {
@DataObject(DataNode="AddProductLibraryPage,AdminPortalLoginPage")
private HashMap dataMap;
@Test(invocationCount = 100)
public void addProductLibrary() throws Exception {
}
}
package ec.qa.autotest.ui.admin.portal.testcases;
import java.util.HashMap;
import org.testng.annotations.Test;
import ec.qa.autotest.ui.admin.portal.pageobject.AddProductLibraryPage;
import ec.qa.autotest.ui.admin.portal.pageobject.NavigationMenu;
import ec.qa.autotest.ui.admin.portal.pageobject.ProductLibraryPage;
import ec.qa.autotest.ui.common.action.AdminLoadingProgress;
import ec.qa.autotest.ui.custom.annotation.AutoInject;
import ec.qa.autotest.ui.custom.annotation.DataObject;
import ec.qa.autotest.ui.testbase.AdminPortalTestBase;
public class AddProductLibraryProtal extends AdminPortalTestBase {
@AutoInject
private NavigationMenu menu;
@AutoInject
private ProductLibraryPage porLibrary;
@AutoInject
private AddProductLibraryPage addProLibrary;
@AutoInject
private AdminLoadingProgress adminCommon;
@DataObject(DataNode="AddProductLibraryPage,AdminPortalLoginPage")
private HashMap dataMap;
@Test(invocationCount = 100)
public void addProductLibrary() throws Exception {
System.out.println(dataMap.get("UserName"));
menu.goToProdcutLibPage();
porLibrary.addButtonOnclick();
adminCommon.wiatForLoadingTOComplete();
addProLibrary.AddProduvtLibraryPortal(dataMap.get("ProLibName"),dataMap.get("PLDescription"));
porLibrary.waitForExpectValue(dataMap.get("ProLibName"));
}
}
======测试用例: addProductLibrary 开始执行======
===测试用例运行的浏览器类型:Chrome ===
测试网站地址:
Starting ChromeDriver 2.20.353145 (343b531d31eeb933ec778dbcf7081628a1396067) on port 14786
Only local connections are allowed.
admin
==页面加载中....==
==页面加载已完成!==
=====测试用例: addProductLibrary 运行成功=====
killed the useless process
PASSED: addProductLibrary
===============================================
Default test
Tests run: 1, Failures: 0, Skips: 0
===============================================
===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================
上面自动注入数据对象的实现过程:
定义数据文件格式后,实现XML文件解析程序(DOM4j):
package ec.qa.autotest.ui.utility;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ParseDataXml {
private static String testDataFielsuffix = ".xml";
private static String dataNodeTag = "data-node";
private static String dataNodeID = "id";
private static String dataTag = "data";
private static String dataKey = "key";
private static String dataValue = "value";
public static HashMap getDataNode(String dataNodeIds) throws DocumentException {
String[] dataNodeId = dataNodeIds.split(",");
HashSet nodeSet = new HashSet();
for (String str : dataNodeId) {
nodeSet.add(str);
}
HashMap dataMap = new HashMap();
ArrayList fs = InitPropertiesUtil.getConfigFiles(new File(PropertiesUtil.getProValue("testcase.testdata.path")), testDataFielsuffix);
for (File f : fs) {
setDataNodeMapFromFile(f, nodeSet, dataMap);
}
return dataMap;
}
@SuppressWarnings("unchecked")
public static void setDataNodeMapFromFile(File f, HashSet nodeSet, HashMap dataMap)
throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(f);
Element root = document.getRootElement();
List childList = root.elements(dataNodeTag);
for (Element e : childList) {
if (nodeSet.contains(e.attributeValue(dataNodeID))) {
List dataList = e.elements(dataTag);
for (Element de : dataList) {
dataMap.put(de.attributeValue(dataKey), de.attributeValue(dataValue));
}
nodeSet.remove(e.attributeValue(dataNodeID));
}
}
return;
}
}
protected static Field[] fields = null;
private void getCurClassFields() throws SecurityException, ClassNotFoundException{
String curClassName = TestBase.getTestCaseDeclaringClass();
fields = Class.forName(curClassName).getDeclaredFields();
}
public String getDataObjectAnnValues(Field[] fields){
for(Field f :fields){
if(f.getAnnotation(DataObject.class)!=null){
DataObject ao = f.getAnnotation(DataObject.class);
return ao.DataNode();
}
}
return null;
}
private void fillFieldNameSet(Field[] fields, HashSet fieldSet) {
for (Field f : fields) {
if(f.getAnnotation(DataObject.class) != null){
dataNodeFieldName = f.getType().getSimpleName();
fieldSet.add(f.getType().getSimpleName());
}
}
}
注入方法:
private void injectDataObj(Field[] fields, HashMap pageobjs)
throws IllegalArgumentException, IllegalAccessException {
for (Field f : fields) {
f.setAccessible(true);
f.set(pageobj, pageobjs.get(dataNodeFieldName));
f.setAccessible(false);
}
}
private HashMap initPageObjMap() {
HashMap pageobjs = new HashMap();
HashSet fieldSet = new HashSet();
try {
fillFieldNameSet(fields, fieldSet);
if(getDataObjectAnnValues(fields)!=null){
pageobjs.put(dataNodeFieldName, ParseDataXml.getDataNode(getDataObjectAnnValues(fields)));
}
injectPageObj(fields, pageobjs);
} catch (Exception e) {
e.printStackTrace();
}
return pageobjs;
}
定义类的构造方法:
public class InitDataObject{
protected static Field[] fields = null;
private String dataNodeFieldName;
public InitDataObject(Object ob) throws SecurityException, ClassNotFoundException {
getCurClassFields();
initPageObjMap();
}
@BeforeMethod(alwaysRun = true)
public void initDriver(Method m) throws Exception {
new InitDataObject(this);
}