Compare commits
19 Commits
master
...
hotfix/202
Author | SHA1 | Date |
---|---|---|
彭宇琦 | 1bc0255ebe | |
彭宇琦 | 4adf08bd09 | |
彭宇琦 | 9460e51cea | |
彭宇琦 | 9eac816345 | |
彭宇琦 | 3ab7589976 | |
彭宇琦 | c6cbea3a57 | |
彭宇琦 | 85e6ea99c9 | |
彭宇琦 | 7fc538a2e4 | |
彭宇琦 | 3b1222eddc | |
彭宇琦 | a77ab169ce | |
彭宇琦 | 470b7f217b | |
彭宇琦 | fe2d94cb95 | |
彭宇琦 | b76e758c67 | |
彭宇琦 | 1cf57bd35b | |
彭宇琦 | 5feb22981a | |
彭宇琦 | 4c647ad192 | |
彭宇琦 | 1f951c3390 | |
彭宇琦 | 25695b2320 | |
彭宇琦 | 95ef5bc5c3 |
7
pom.xml
7
pom.xml
|
@ -57,10 +57,11 @@
|
|||
|
||||
<!-- xml解析工具 -->
|
||||
<dependency>
|
||||
<groupId>dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<groupId>org.dom4j</groupId>
|
||||
<artifactId>dom4j</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jaxen</groupId>
|
||||
<artifactId>jaxen</artifactId>
|
||||
|
|
|
@ -140,6 +140,17 @@ public class ElementData {
|
|||
public long getWaitTime() {
|
||||
return waitTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回元素定位方式的个数
|
||||
* <p>
|
||||
* 若定位方式与定位内容不一致时,则返回两者中的最小长度
|
||||
* </p>
|
||||
* @return 元素定位方式的个数
|
||||
*/
|
||||
public int getLocationSize() {
|
||||
return Math.min(byTypeList.size(), valueList.size());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于添加元素定位外链词语
|
||||
|
|
|
@ -265,20 +265,13 @@ public abstract class FindElement {
|
|||
ArrayList<ByType> elementByTypeList = elementData.getByTypeList();
|
||||
ArrayList<String> elementValueList = elementData.getValueList();
|
||||
|
||||
//获取两个列表长度的最小者
|
||||
int minLength = Math.min(elementByTypeList.size(), elementValueList.size());
|
||||
//循环,遍历所有的定位方式,使用根据定位方式,判断页面是否存在定位方式指向的元素
|
||||
for (int index = 0; index < minLength; index++) {
|
||||
//根据当前元素信息,在页面获取元素
|
||||
List<WebElement> elementList = findElement(elementByTypeList.get(index),
|
||||
elementValueList.get(index),
|
||||
elementData.getWaitTime() == -1 ? globalWaitTime : elementData.getWaitTime());
|
||||
|
||||
//若获取到的元素列表为空,则继续循环,调用下一个定位方式
|
||||
if (elementList.size() != 0) {
|
||||
return elementList;
|
||||
}
|
||||
}
|
||||
List<WebElement> elementList = findElement(elementByTypeList, elementValueList,
|
||||
elementData.getWaitTime() == -1 ? globalWaitTime : elementData.getWaitTime());
|
||||
|
||||
//若获取到的元素列表为空,则继续循环,调用下一个定位方式
|
||||
if (elementList.size() != 0) {
|
||||
return elementList;
|
||||
}
|
||||
|
||||
throw new TimeoutException("页面上无相应定位方式的元素,元素名称:" + elementData.getName());
|
||||
}
|
||||
|
@ -286,25 +279,35 @@ public abstract class FindElement {
|
|||
/**
|
||||
* 根据传入的定位方式枚举,以及定位内容,在页面查找
|
||||
* 元素,返回查到的元素列表,若查不到元素,则返回空列表
|
||||
* @param byType {@link ByType}枚举类
|
||||
* @param value 元素定位内容
|
||||
* @param byTypeList {@link ByType}枚举类集合
|
||||
* @param valueList 元素定位内容集合
|
||||
* @param waitTime 元素查找超时时间
|
||||
* @return 页面查找到的{@link WebElement}类对象{@link List}集合
|
||||
*/
|
||||
protected List<WebElement> findElement(ByType byType, String value, long waitTime) {
|
||||
protected List<WebElement> findElement(List<ByType> byTypeList, List<String> valueList, long waitTime) {
|
||||
try {
|
||||
return new WebDriverWait(brower.getDriver(), waitTime, 200)
|
||||
.until(driver -> {
|
||||
try {
|
||||
List<WebElement> webElementList = driver.findElements(getBy(value, byType));
|
||||
if (webElementList != null && webElementList.size() != 0) {
|
||||
return webElementList;
|
||||
} else {
|
||||
return null;
|
||||
int minLength = Math.min(byTypeList.size(), valueList.size());
|
||||
//遍历所有的定位方式与定位内容
|
||||
for (int i = 0; i < minLength; i++) {
|
||||
try {
|
||||
//页面查找元素
|
||||
List<WebElement> webElementList = driver.findElements(getBy(valueList.get(i), byTypeList.get(i)));
|
||||
//若元素组为空或者获取的元素为空,则重新循环;反之,则返回找到元素
|
||||
if (webElementList != null && webElementList.size() != 0) {
|
||||
return webElementList;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
//若抛出异常,则重新循环
|
||||
continue;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
//若循环完毕仍未找到元素,则返回null
|
||||
return null;
|
||||
});
|
||||
} catch (TimeoutException e) {
|
||||
return new ArrayList<WebElement>();
|
||||
|
|
|
@ -84,6 +84,10 @@ public abstract class AbstractEvent {
|
|||
wait.withTimeout(Duration.ofSeconds(waitTime));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置是否将页面移至元素所在的位置
|
||||
* @param isLocationElement 是否将页面移至元素所在的位置
|
||||
*/
|
||||
public void setLocationElement(boolean isLocationElement) {
|
||||
this.isLocationElement = isLocationElement;
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@ public class WaitEvent extends AbstractEvent{
|
|||
* 该方法用于等待指定元素中显示相应的文本,可指定显示文本的关键词,直到显示相应的关键词为止,
|
||||
* 若不传入关键词,则只判断元素加载出文本。若元素未出现,则返回false
|
||||
* @param element {@link Element}对象
|
||||
* @param keys 需要判断的文本
|
||||
* @return 元素是否存在文本或包含指定文本
|
||||
* @throws TimeoutException 等待超时时抛出的异常
|
||||
*/
|
||||
|
|
|
@ -258,9 +258,10 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
}
|
||||
|
||||
/**
|
||||
* 通过条件,点击{@link DataTableKeywordType#SEARCH_BUTTON}映射的按钮,对列表进行搜索。方法中需要接收一个
|
||||
* 返回值为boolean类型的操作,若操作的返回值为false时,则不会点击按钮,可参考以下写法:
|
||||
*
|
||||
* 通过条件,点击{@link DataTableKeywordType#SEARCH_BUTTON}映射的按钮,对列表进行搜索。
|
||||
* <p>
|
||||
* 方法中需要接收一个返回值为boolean类型的操作,若操作的返回值为false时,
|
||||
* 则不会点击按钮,可参考以下写法:
|
||||
* <code><pre>
|
||||
* DataTableEvent test = new DataTableEvent(brower);
|
||||
* test.searchList(() -> {
|
||||
|
@ -268,6 +269,7 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
* return true;
|
||||
* });
|
||||
* </pre></code>
|
||||
* </p>
|
||||
*
|
||||
* @param action 返回值为boolean类型的操作
|
||||
* @return 列表是否有变化
|
||||
|
@ -301,6 +303,15 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于无条件点击{@link DataTableKeywordType#SEARCH_BUTTON}映射的按钮。
|
||||
*
|
||||
* @return列表是否有变化
|
||||
*/
|
||||
public boolean searchList() {
|
||||
return searchList(() -> true);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
|
@ -327,7 +338,6 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
.filter(table -> !table.isEmpty())
|
||||
//若当前为空集合,则抛出异常
|
||||
.orElseThrow(() -> new ControlException("当前行元素为空,无法获取"));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -349,7 +359,7 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
|
||||
return rowTextList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定列的文本,若该列元素异常时,则抛出异常
|
||||
*
|
||||
|
@ -371,6 +381,32 @@ public final class DataTableEvent extends AbstractEvent {
|
|||
|
||||
return listTextList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于以{@link TableData}的形式返回元素列表
|
||||
* @return 元素列表
|
||||
*/
|
||||
public TableData<Element> getElementTable() {
|
||||
|
||||
return new TableData<Element>(elementTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于随机返回指定列表的随机一个元素
|
||||
* @param listName 列表名称
|
||||
* @return 指定列表的随机元素
|
||||
*/
|
||||
public Element getRandomElement(String listName) {
|
||||
//按列表长度获取随机数
|
||||
int listSize = elementTable.getListSize(listName);
|
||||
int randomIndex = new Random().nextInt(listSize);
|
||||
|
||||
//根据随机数返回元素;若当前随机的元素不存在,则返回列表第一个元素
|
||||
//若列表第一个元素仍不存在,则跑出异常
|
||||
return elementTable.getColumnList(listName).get(randomIndex)
|
||||
.orElse(elementTable.getColumnList(listName).get(0)
|
||||
.orElseThrow(() -> new ControlException("当前列元素为空,无法获取")));
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于执行需要断言页面元素的列表操作,在其操作方法前后添加了断言操作
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package com.auxiliary.selenium.location;
|
||||
|
||||
import org.openqa.selenium.By;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <b>文件名:</b>ByType.java
|
||||
|
@ -57,4 +59,30 @@ public enum ByType {
|
|||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据枚举内容,返回相应的{@link By}对象
|
||||
* @param value 元素的定位内容
|
||||
* @return 包含定位内容的元素{@link By}对象
|
||||
*/
|
||||
public By getBy(String value) {
|
||||
switch (this) {
|
||||
case CLASSNAME:
|
||||
return By.className(value);
|
||||
case CSS:
|
||||
return By.cssSelector(value);
|
||||
case ID:
|
||||
return By.id(value);
|
||||
case LINKTEXT:
|
||||
return By.linkText(value);
|
||||
case NAME:
|
||||
return By.name(value);
|
||||
case TAGNAME:
|
||||
return By.tagName(value);
|
||||
case XPATH:
|
||||
return By.xpath(value);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@ public class XmlLocation extends AbstractLocation {
|
|||
try {
|
||||
dom = new SAXReader().read(xmlFile);
|
||||
} catch (DocumentException e) {
|
||||
throw new IncorrectFileException("xml文件异常,文件位置:" + xmlFile.getAbsolutePath());
|
||||
throw new IncorrectFileException("xml文件异常,文件位置:" + xmlFile.getAbsolutePath(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -76,12 +76,9 @@ public class XmlLocation extends AbstractLocation {
|
|||
public ArrayList<ByType> findElementByTypeList(String name) {
|
||||
ArrayList<ByType> byTypeList = new ArrayList<ByType>();
|
||||
//查询并存储元素下的子元素
|
||||
@SuppressWarnings("unchecked")
|
||||
ArrayList<Object> lableElementList = new ArrayList<>(getElementLabelElement(name).elements());
|
||||
ArrayList<Element> lableElementList = new ArrayList<>(getElementLabelElement(name).elements());
|
||||
|
||||
lableElementList.stream()
|
||||
//强转为Element类型
|
||||
.map(lable -> (Element)lable)
|
||||
//获取标签名称
|
||||
.map(lable -> lable.getName())
|
||||
//将名称转换为ByType枚举
|
||||
|
@ -90,7 +87,6 @@ public class XmlLocation extends AbstractLocation {
|
|||
.filter(lable -> lable != null)
|
||||
//存储标签
|
||||
.forEach(byTypeList::add);
|
||||
;
|
||||
|
||||
return byTypeList;
|
||||
}
|
||||
|
@ -98,25 +94,32 @@ public class XmlLocation extends AbstractLocation {
|
|||
@Override
|
||||
public ArrayList<String> findValueList(String name) {
|
||||
ArrayList<String> valueList = new ArrayList<>();
|
||||
//查询元素
|
||||
Element element = getElementLabelElement(name);
|
||||
|
||||
//遍历元素下所有的定位标签,并将其转换为相应的ByType枚举,存储至byTypeList中
|
||||
for (Object byElement : element.elements()) {
|
||||
//判断元素是否启用,若元素未启用,则下一个循环
|
||||
String isUserText = ((Element) byElement).attributeValue("is_user");
|
||||
if (isUserText != null && !Boolean.valueOf(isUserText)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//判断元素是否启用模板,若启用模板,则获取模板内容,并将定位内容进行转换
|
||||
String tempId = ((Element) byElement).attributeValue("temp_id");
|
||||
String value = tempId != null ?
|
||||
getTemplateValue(tempId, toByType(((Element) byElement).getName())) :
|
||||
((Element)byElement).getText();
|
||||
|
||||
valueList.add(replaceValue(((Element) byElement), value));
|
||||
}
|
||||
//查询元素,遍历元素下所有的定位标签,并过滤掉元素标签
|
||||
getElementLabelElement(name).elements().stream().filter(ele -> !"element".equals(ele.getName()))
|
||||
//过滤不启用的标签
|
||||
.filter(ele -> {
|
||||
return Optional.ofNullable(ele.attributeValue("is_user"))
|
||||
.filter(t -> !t.isEmpty())
|
||||
.map(t -> {
|
||||
try {
|
||||
return Boolean.valueOf(t).booleanValue();
|
||||
} catch (Exception e) {
|
||||
return true;
|
||||
}
|
||||
}).orElse(true);
|
||||
//根据值或模板,将定位内容转译,并存储至valueList
|
||||
}).forEach(ele -> {
|
||||
String value = "";
|
||||
String tempId = Optional.ofNullable(ele.attributeValue("temp_id")).orElse("");
|
||||
if (tempId.isEmpty()) {
|
||||
value = ele.getText();
|
||||
} else {
|
||||
value = getTemplateValue(tempId, toByType(ele.getName()));
|
||||
}
|
||||
|
||||
valueList.add(replaceValue(ele, value));
|
||||
});
|
||||
|
||||
return valueList;
|
||||
}
|
||||
|
|
|
@ -1,19 +1,31 @@
|
|||
package com.auxiliary.selenium.page;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.openqa.selenium.NoSuchElementException;
|
||||
import org.openqa.selenium.WebDriver;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.auxiliary.selenium.brower.AbstractBrower;
|
||||
import com.auxiliary.selenium.brower.IncorrectPageException;
|
||||
import com.auxiliary.selenium.element.ElementData;
|
||||
import com.auxiliary.selenium.location.ByType;
|
||||
import com.auxiliary.selenium.location.NoFileLocation;
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>Page.java</p>
|
||||
* <p><b>用途:</b>用于存储对浏览器加载的页面信息以及页面操作</p>
|
||||
* <p><b>编码时间:</b>2020年4月10日上午8:02:45</p>
|
||||
* <p><b>修改时间:</b>2020年10月12日下午8:02:45</p>
|
||||
* <p><b>修改时间:</b>2021年2月18日下午6:12:14</p>
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @version Ver1.1
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
|
@ -27,9 +39,13 @@ public class Page {
|
|||
*/
|
||||
private int loadTime = 120;
|
||||
/**
|
||||
* 用于存储目标站点的title
|
||||
* 用于存储需要断言的内容
|
||||
*/
|
||||
private String assertTitle = "";
|
||||
private HashMap<PageAssertType, List<Object>> assertMap;
|
||||
/**
|
||||
* 标记当前是否启用断言
|
||||
*/
|
||||
private boolean isAssert = false;
|
||||
/**
|
||||
* 用于存储页面的名称
|
||||
*/
|
||||
|
@ -57,6 +73,10 @@ public class Page {
|
|||
this.url = url;
|
||||
this.pageName = pageName;
|
||||
|
||||
assertMap = new HashMap<>(16);
|
||||
//初始化断言的内容
|
||||
Arrays.stream(PageAssertType.values()).forEach(type -> assertMap.put(type, new ArrayList<>()));
|
||||
|
||||
//存储页面信息
|
||||
pageInformationJson.put("页面名称", pageName);
|
||||
pageInformationJson.put("页面站点", url);
|
||||
|
@ -109,14 +129,135 @@ public class Page {
|
|||
|
||||
/**
|
||||
* 用于设置对页面的标题断言
|
||||
* @param assertTitle 标题断言
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>页面断言为一次性断言,故添加的断言内容只累积,即多次添加断言内容,在进行断言时将全部用于判断</li>
|
||||
* <li>设置的断言内容为正则表达式,若设置的断言内容存在正则表达式中的特殊字符,则请自行转译,
|
||||
* 否则可能会得到不符合预期的结果</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* @param titles 标题断言
|
||||
*/
|
||||
public void setAssertTitle(String assertTitle) {
|
||||
this.assertTitle = assertTitle;
|
||||
|
||||
pageInformationJson.put("页面断言", assertTitle);
|
||||
public void setAssertTitle(String...titles) {
|
||||
Optional.ofNullable(titles).filter(ts -> ts.length != 0).ifPresent(ts -> {
|
||||
List<Object> list = assertMap.get(PageAssertType.TITLE);
|
||||
Arrays.stream(ts).forEach(list::add);
|
||||
assertMap.put(PageAssertType.TITLE, list);
|
||||
|
||||
pageInformationJson.put("页面标题断言", list);
|
||||
|
||||
//记录启用了断言
|
||||
isAssert = true;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于设置对页面的html内容断言
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>页面断言为一次性断言,故添加的断言内容只累积,即多次添加断言内容,在进行断言时将全部用于判断</li>
|
||||
* <li>设置的断言内容为正则表达式,若设置的断言内容存在正则表达式中的特殊字符,则请自行转译,
|
||||
* 否则可能会得到不符合预期的结果</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* @param htmls html断言数组
|
||||
*/
|
||||
public void setAssertHtml(String...htmls) {
|
||||
Optional.ofNullable(htmls).filter(ts -> ts.length != 0).ifPresent(ts -> {
|
||||
List<Object> list = assertMap.get(PageAssertType.HTML);
|
||||
Arrays.stream(ts).forEach(list::add);
|
||||
assertMap.put(PageAssertType.HTML, list);
|
||||
|
||||
pageInformationJson.put("页面html断言", list);
|
||||
|
||||
//记录启用了断言
|
||||
isAssert = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置对页面最终跳转的url
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>页面断言为一次性断言,故添加的断言内容只累积,即多次添加断言内容,在进行断言时将全部用于判断</li>
|
||||
* <li>设置的断言内容为正则表达式,若设置的断言内容存在正则表达式中的特殊字符,则请自行转译,
|
||||
* 否则可能会得到不符合预期的结果</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* @param urls url断言数组
|
||||
*/
|
||||
public void setAssertUrl(String...urls) {
|
||||
Optional.ofNullable(urls).filter(ts -> ts.length != 0).ifPresent(ts -> {
|
||||
List<Object> list = assertMap.get(PageAssertType.URL);
|
||||
Arrays.stream(ts).forEach(list::add);
|
||||
assertMap.put(PageAssertType.URL, list);
|
||||
|
||||
pageInformationJson.put("页面url断言", list);
|
||||
|
||||
//记录启用了断言
|
||||
isAssert = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置对页面的文本内容断言
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>页面断言为一次性断言,故添加的断言内容只累积,即多次添加断言内容,在进行断言时将全部用于判断</li>
|
||||
* <li>页面文本断言不支持正则表达式,需要指定确定的关键词,否则可能会得到不符合预期的结果</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* @param texts 页面文本断言数组
|
||||
*/
|
||||
public void setAssertText(String...texts) {
|
||||
Optional.ofNullable(texts).filter(ts -> ts.length != 0).ifPresent(ts -> {
|
||||
List<Object> list = assertMap.get(PageAssertType.TEXT);
|
||||
//将文本转换为ElementData类,以元素的形式进行断言
|
||||
Arrays.stream(texts).map(text -> {
|
||||
NoFileLocation nf = new NoFileLocation();
|
||||
nf.putElementLocation("文本元素", ByType.XPATH, "//*[contains(text(), '" + text + "')]");
|
||||
|
||||
ElementData el = new ElementData("文本元素", nf);
|
||||
return el;
|
||||
}).forEach(list::add);
|
||||
assertMap.put(PageAssertType.TEXT, list);
|
||||
|
||||
pageInformationJson.put("页面文本断言", list);
|
||||
|
||||
//记录启用了断言
|
||||
isAssert = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置对页面的元素断言
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>页面断言为一次性断言,故添加的断言内容只累积,即多次添加断言内容,在进行断言时将全部用于判断</li>
|
||||
* <li>设置的断言内容为正则表达式,若设置的断言内容存在正则表达式中的特殊字符,则请自行转译,
|
||||
* 否则可能会得到不符合预期的结果</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
* @param elements 元素断言数组
|
||||
*/
|
||||
public void setAssertElement(ElementData...elements) {
|
||||
Optional.ofNullable(elements).filter(ts -> ts.length != 0).ifPresent(ts -> {
|
||||
List<Object> list = assertMap.get(PageAssertType.ELEMENT);
|
||||
Arrays.stream(elements).filter(e -> e != null).forEach(list::add);
|
||||
assertMap.put(PageAssertType.ELEMENT, list);
|
||||
|
||||
pageInformationJson.put("页面元素断言", list);
|
||||
|
||||
//记录启用了断言
|
||||
isAssert = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置对页面自动加载次数的限制
|
||||
* @param rafreshCount 加载次数限制
|
||||
|
@ -176,21 +317,119 @@ public class Page {
|
|||
/**
|
||||
* 用于对加载的页面信息与断言对比 ,返回对比结果
|
||||
* @param driver WebDriver对象
|
||||
* @return
|
||||
* @return 断言是否成功
|
||||
*/
|
||||
private boolean judgeAssert(WebDriver driver) {
|
||||
//若页面断言为空,则直接返回true
|
||||
if (assertTitle.isEmpty()) {
|
||||
if (driver == null) {
|
||||
throw new IncorrectPageException("未指定WebDriver对象");
|
||||
}
|
||||
|
||||
//判断当前是否启用了断言
|
||||
if (!isAssert) {
|
||||
return true;
|
||||
} else {
|
||||
//若页面断言不为空且页面信息与断言不相同,则返回false
|
||||
if (!driver.getTitle().equals(assertTitle)) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
//遍历断言内容的key值
|
||||
for (PageAssertType key : assertMap.keySet()) {
|
||||
//若当前未设置断言,则跳过该判断
|
||||
if (assertMap.get(key).size() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//根据关键词,对页面进行断言
|
||||
switch (key) {
|
||||
case TITLE:
|
||||
//获取页面标题,判断标题是否符合所有的正则,若存在不符合的,则返回false
|
||||
if (!assertTextContent(driver.getTitle(), key)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case HTML:
|
||||
//获取页面html,判断标题是否符合所有的正则,若存在不符合的,则返回false
|
||||
if (!assertTextContent(driver.getPageSource(), key)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case URL:
|
||||
//获取页面url,判断标题是否符合所有的正则,若存在不符合的,则返回false
|
||||
if (!assertTextContent(driver.getCurrentUrl(), key)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
//文本与元素判断的机制一致
|
||||
case TEXT:
|
||||
case ELEMENT:
|
||||
//读取需要判断的元素,若存在不符合的,则返回false
|
||||
if (!assertElementContent(driver, key)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对页面文本相关的内容进行断言的方法
|
||||
* @param content 文本内容
|
||||
* @param key 断言类型
|
||||
* @return 断言是否成功
|
||||
*/
|
||||
private boolean assertTextContent(String content, PageAssertType key) {
|
||||
for (Object assertObj : assertMap.get(key)) {
|
||||
//设置当前值为正则,传入的内容为需要判断的字符串
|
||||
Matcher match = Pattern.compile((String) assertObj).matcher(content);
|
||||
//若通过该正则,在内容中无法找到,则返回false
|
||||
if (!match.find()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//若通过所有判断,则返回true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对页面元素相关的内容进行断言的方法
|
||||
* @param driver 页面WebDriver对象
|
||||
* @param key 断言类型
|
||||
* @return 断言是否成功
|
||||
*/
|
||||
private boolean assertElementContent(WebDriver driver, PageAssertType key) {
|
||||
for (Object assertObj : assertMap.get(key)) {
|
||||
//将Object类转换为ElementData类
|
||||
ElementData e = (ElementData) assertObj;
|
||||
//获取元素的定位方式
|
||||
List<ByType> byTypeList = e.getByTypeList();
|
||||
List<String> valueList = e.getValueList();
|
||||
|
||||
//遍历元素的定位方式,拼接定位方式为By对象
|
||||
boolean isSuccess = true;
|
||||
for (int i = 0; i < e.getLocationSize(); i++) {
|
||||
try {
|
||||
driver.findElement(byTypeList.get(i).getBy(valueList.get(i)));
|
||||
isSuccess = true;
|
||||
} catch (NoSuchElementException ex) {
|
||||
isSuccess = false;
|
||||
}
|
||||
}
|
||||
|
||||
//判断当前查找完所有元素定位方式后是否能在页面找到元素,
|
||||
//若不能找到,则直接返回false;否则,进行下一个判断
|
||||
if (!isSuccess) {
|
||||
return false;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
//若通过所有判断,则返回true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
|
@ -228,4 +467,40 @@ public class Page {
|
|||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>Page.java</p>
|
||||
* <p><b>用途:</b>
|
||||
* 指定页面断言的条件枚举
|
||||
* </p>
|
||||
* <p><b>编码时间:</b>2021年2月18日下午5:25:34</p>
|
||||
* <p><b>修改时间:</b>2021年2月18日下午5:25:34</p>
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
*
|
||||
*/
|
||||
public enum PageAssertType {
|
||||
/**
|
||||
* 断言页面标题
|
||||
*/
|
||||
TITLE,
|
||||
/**
|
||||
* 断言页面html代码
|
||||
*/
|
||||
HTML,
|
||||
/**
|
||||
* 断言页面最终跳转的url
|
||||
*/
|
||||
URL,
|
||||
/**
|
||||
* 断言页面文本
|
||||
*/
|
||||
TEXT,
|
||||
/**
|
||||
* 断言页面元素
|
||||
*/
|
||||
ELEMENT
|
||||
;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,10 +101,6 @@ public class Screenshot {
|
|||
* 该方法用于创建截图并保存到相应的路径下,通过指定的截图文件名称和类中存储的WebDriver对象、截图保存路径来创建截图
|
||||
*
|
||||
* @param imageName 指定的截图文件名
|
||||
* @throws IOException 文件流状态不正确时抛出的异常
|
||||
* @throws WebDriverException WebDriver引用错误时抛出的异常
|
||||
* @throws NullPointerException WebDriver为空时抛出的异常
|
||||
* @throws UndefinedDirectoryException 截图保存路径或截图名称为指定时抛出的异常
|
||||
*/
|
||||
public synchronized File creatImage(String imageName) {
|
||||
// 调用无参方法
|
||||
|
@ -150,7 +146,7 @@ public class Screenshot {
|
|||
}
|
||||
|
||||
//判断是否传入文件名,若未传入文件名,则指定当前时间戳为文件名
|
||||
File imageFile = new File(savePathFolder + Optional.ofNullable(fileName).filter(text -> !text.isEmpty())
|
||||
File imageFile = new File(savePathFolder + "/" + Optional.ofNullable(fileName).filter(text -> !text.isEmpty())
|
||||
.orElse(String.valueOf(Time.parse().getMilliSecond())) + ".png");
|
||||
|
||||
// 截图,并将得到的截图转移到指定的目录下
|
||||
|
|
|
@ -14,10 +14,19 @@ import org.dom4j.io.SAXReader;
|
|||
import com.auxiliary.testcase.file.IncorrectFileException;
|
||||
|
||||
/**
|
||||
* <p><b>文件名:</b>Case.java</p>
|
||||
* <p><b>用途:</b>定义测试用例模板类能返回的基本字段,提供其相应的get与set方法,但该方法不允许包外调用</p>
|
||||
* <p><b>编码时间:</b>2020年3月3日下午8:07:23</p>
|
||||
* <p><b>修改时间:</b>2020年3月4日 07:39:23</p>
|
||||
* <p>
|
||||
* <b>文件名:</b>Case.java
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>用途:</b>定义测试用例模板类能返回的基本字段,提供其相应的get与set方法,但该方法不允许包外调用
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>编码时间:</b>2020年3月3日下午8:07:23
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2020年3月4日 07:39:23
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
* @version Ver1.0
|
||||
* @since JDK 1.8
|
||||
|
@ -36,12 +45,12 @@ public abstract class Case {
|
|||
* 用于指向用例标签中的id属性
|
||||
*/
|
||||
public static final String ATTRIBUTE_ID = "id";
|
||||
|
||||
|
||||
/**
|
||||
* 用于标记获取标签下所有的文本
|
||||
*/
|
||||
protected final String ALL = "-1:getAllText";
|
||||
|
||||
|
||||
/**
|
||||
* 用于存储需要替换的词语的开始标记
|
||||
*/
|
||||
|
@ -50,29 +59,30 @@ public abstract class Case {
|
|||
* 用于存储需要替换的词语的结束标记
|
||||
*/
|
||||
protected final String END_SIGN = "}*";
|
||||
|
||||
|
||||
/**
|
||||
* 用于存储传入到正则表达式中的开始标记
|
||||
*/
|
||||
protected final String START_SIGN_REGIX = "\\*\\{";
|
||||
|
||||
|
||||
/**
|
||||
* 用于指向测试用例xml文件的Document对象
|
||||
*/
|
||||
protected Document configXml;
|
||||
|
||||
protected Document configXml;
|
||||
|
||||
/**
|
||||
* 存储xml文件中其需要替换的词语
|
||||
*/
|
||||
protected HashMap<String, String> wordMap = new HashMap<String, String>(16);
|
||||
|
||||
|
||||
/**
|
||||
* 存储字段的文本内容
|
||||
*/
|
||||
protected HashMap<String, ArrayList<String>> fieldTextMap = new HashMap<String, ArrayList<String>>(16);
|
||||
|
||||
|
||||
/**
|
||||
* 根据用例xml文件来构造Case类
|
||||
*
|
||||
* @param configXmlFile xml配置文件
|
||||
* @throws IncorrectFileException 文件格式或路径不正确时抛出的异常
|
||||
*/
|
||||
|
@ -81,200 +91,204 @@ public abstract class Case {
|
|||
try {
|
||||
configXml = new SAXReader().read(configXmlFile);
|
||||
} catch (DocumentException e) {
|
||||
throw new IncorrectFileException("用例xml文件有误" );
|
||||
throw new IncorrectFileException("用例xml文件有误");
|
||||
}
|
||||
|
||||
//查找并存储替换的词语
|
||||
|
||||
// 查找并存储替换的词语
|
||||
saveWord();
|
||||
//保存字段的词语
|
||||
// 保存字段的词语
|
||||
saveField();
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置需要替换的词语
|
||||
*
|
||||
* @param word 测试用例xml库中需要替换的词语
|
||||
* @param text 被替换的词语
|
||||
*/
|
||||
public void setReplaceWord(String word, String text) {
|
||||
//判断该词语是否存在于textMap中,若不存在,则抛出异常
|
||||
// 判断该词语是否存在于textMap中,若不存在,则抛出异常
|
||||
if (!wordMap.containsKey(word)) {
|
||||
throw new IncorrectFileException("未找到需要替换的词语:" + word);
|
||||
}
|
||||
//存储替换的词语
|
||||
// 存储替换的词语
|
||||
wordMap.put(word, text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 返回字段内容
|
||||
*
|
||||
* @return 字段内容
|
||||
*/
|
||||
public HashMap<String, ArrayList<String>> getFieldTextMap() {
|
||||
return fieldTextMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于替换文本中需要替换的单词,返回替换后的文本
|
||||
*
|
||||
* @param text 需要替换的文本
|
||||
* @return 替换后的文本
|
||||
*/
|
||||
protected String replaceText(String text) {
|
||||
StringBuilder sb = new StringBuilder(text);
|
||||
//存储替换符的位置
|
||||
// 存储替换符的位置
|
||||
int index = 0;
|
||||
//循环,替换content中所有需要替换的信息
|
||||
while( (index = sb.indexOf(START_SIGN)) != -1 ) {
|
||||
//存储待替换的变量名
|
||||
// 循环,替换content中所有需要替换的信息
|
||||
while ((index = sb.indexOf(START_SIGN)) != -1) {
|
||||
// 存储待替换的变量名
|
||||
String var = "";
|
||||
try {
|
||||
var = sb.substring(index + START_SIGN.length(), sb.indexOf(END_SIGN));
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
throw new CaseContentException("词语替换错误,无效的标记字符:" + text);
|
||||
}
|
||||
//替换该变量名
|
||||
// 替换该变量名
|
||||
sb.replace(index, sb.indexOf(END_SIGN) + END_SIGN.length(), wordMap.get(var));
|
||||
}
|
||||
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于获取用例xml中对应用例的标签内的文本,并返回替换词语后的文本
|
||||
* @param caseName 用例名称
|
||||
*
|
||||
* @param caseName 用例名称
|
||||
* @param labelType 标签枚举{@link LabelType}
|
||||
* @param id 对应标签的id属性
|
||||
* @param id 对应标签的id属性
|
||||
* @return 标签中存储的文本,并进行处理
|
||||
*/
|
||||
protected String getLabelText(String caseName, LabelType labelType, String id) {
|
||||
//返回处理替换的单词后相应的文本
|
||||
// 返回处理替换的单词后相应的文本
|
||||
return getLabelText(caseName, labelType.getName(), id);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于获取用例xml中对应用例的标签内的文本,并返回替换词语后的文本
|
||||
* @param caseName 用例名称
|
||||
*
|
||||
* @param caseName 用例名称
|
||||
* @param labelName 标签名称
|
||||
* @param id 对应标签的id属性
|
||||
* @param id 对应标签的id属性
|
||||
* @return 标签中存储的文本,并进行处理
|
||||
*/
|
||||
protected String getLabelText(String caseName, String labelName, String id) {
|
||||
//拼接xpath,规则"//case[@name='caseName']//标签名称[@id='id']"
|
||||
String xpath = "//" + LabelType.CASE.getName() +
|
||||
"[@" + ATTRIBUTE_NAME + "='" +
|
||||
caseName + "']//" + labelName +
|
||||
"[@" + ATTRIBUTE_ID + "='" + id +"']";
|
||||
|
||||
//获取相应的文本内容
|
||||
Element textElement = (Element)(configXml.selectSingleNode(xpath));
|
||||
//判断获取的内容是否为空,为空则跑出异常
|
||||
|
||||
//判断集合是否存在元素,若不存在元素,则抛出异常
|
||||
// 拼接xpath,规则"//case[@name='caseName']//标签名称[@id='id']"
|
||||
String xpath = "//" + LabelType.CASE.getName() + "[@" + ATTRIBUTE_NAME + "='" + caseName + "']//" + labelName
|
||||
+ "[@" + ATTRIBUTE_ID + "='" + id + "']";
|
||||
|
||||
// 获取相应的文本内容
|
||||
Element textElement = (Element) (configXml.selectSingleNode(xpath));
|
||||
// 判断获取的内容是否为空,为空则跑出异常
|
||||
|
||||
// 判断集合是否存在元素,若不存在元素,则抛出异常
|
||||
if (textElement == null) {
|
||||
throw new LabelNotFoundException("用例集“" + caseName + "”中不存在id为“" + id + "”的“" + labelName + "”标签");
|
||||
}
|
||||
|
||||
//返回处理替换的单词后相应的文本
|
||||
|
||||
// 返回处理替换的单词后相应的文本
|
||||
return replaceText(textElement.attributeValue(ATTRIBUTE_VALUE));
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于获取用例xml中对应用例的标签内所有的文本,并返回替换词语后的文本
|
||||
* @param caseName 用例名称
|
||||
*
|
||||
* @param caseName 用例名称
|
||||
* @param labelType 标签枚举
|
||||
* @return 标签中存储的文本,并进行处理
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected ArrayList<String> getAllLabelText(String caseName, LabelType labelType) {
|
||||
//拼接xpath,规则"//case[@name='caseName']//标签名称[@id='id']"
|
||||
String xpath = "//" + LabelType.CASE.getName() +
|
||||
"[@" + ATTRIBUTE_NAME + "='" +
|
||||
caseName + "']//" + labelType.getName();
|
||||
// 拼接xpath,规则"//case[@name='caseName']//标签名称[@id='id']"
|
||||
String xpath = "//" + LabelType.CASE.getName() + "[@" + ATTRIBUTE_NAME + "='" + caseName + "']//"
|
||||
+ labelType.getName();
|
||||
|
||||
//获取所有的节点
|
||||
List<Element> textElements = configXml.selectNodes(xpath);
|
||||
//存储节点中的value属性内的文本
|
||||
ArrayList<String> texts = new ArrayList<String>();
|
||||
//存储节点值
|
||||
for (int i = 0; i < textElements.size(); i++) {
|
||||
texts.add(replaceText(textElements.get(i).attributeValue(ATTRIBUTE_VALUE)));
|
||||
}
|
||||
|
||||
// 存储节点中的value属性内的文本
|
||||
ArrayList<String> texts = new ArrayList<String>();
|
||||
// 获取所有的节点
|
||||
configXml.selectNodes(xpath).stream()
|
||||
.map(e -> (Element) e)
|
||||
.map(e -> e.attributeValue(ATTRIBUTE_VALUE))
|
||||
.map(this::replaceText)
|
||||
.forEach(texts::add);;
|
||||
|
||||
return texts;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于获取并存储需要替换的词语
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void saveWord() {
|
||||
//获取xml中包含value的元素,并将其中包含需要替换的词语存储至wordMap
|
||||
List<Element> textElement = configXml.selectNodes("//*[@" + ATTRIBUTE_VALUE + "]");
|
||||
textElement.stream().
|
||||
//获取元素的value属性,将其转换为文本对象
|
||||
map(e -> e.attributeValue(ATTRIBUTE_VALUE)).
|
||||
//筛选包含*{的文本
|
||||
filter(e -> e.indexOf(START_SIGN) > -1).forEach(e -> {
|
||||
//对文本按照*{切割,并筛选包含}*的文本
|
||||
Arrays.asList(e.split(START_SIGN_REGIX)).stream().filter(s -> s.indexOf(END_SIGN) > -1).
|
||||
forEach(s -> {
|
||||
//将需要存储的替换词语存入textMap中
|
||||
wordMap.put(s.substring(0, s.indexOf(END_SIGN)), "");
|
||||
});
|
||||
});
|
||||
// 获取xml中包含value的元素,并将其中包含需要替换的词语存储至wordMap
|
||||
configXml.selectNodes("//*[@" + ATTRIBUTE_VALUE + "]").stream().map(e -> (Element) e)
|
||||
// 获取元素的value属性,将其转换为文本对象
|
||||
.map(e -> e.attributeValue(ATTRIBUTE_VALUE))
|
||||
// 筛选包含*{的文本
|
||||
.filter(e -> e.indexOf(START_SIGN) > -1).forEach(e -> {
|
||||
// 对文本按照*{切割,并筛选包含}*的文本
|
||||
Arrays.asList(e.split(START_SIGN_REGIX)).stream().filter(s -> s.indexOf(END_SIGN) > -1)
|
||||
.forEach(s -> {
|
||||
// 将需要存储的替换词语存入textMap中
|
||||
wordMap.put(s.substring(0, s.indexOf(END_SIGN)), "");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于保存xml文件中的字段
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void saveField() {
|
||||
//获取case标签下所有的标签,存储至fieldTextMap,以初始化所有的字段名称
|
||||
((List<Element>) (configXml.getRootElement().elements("case"))).forEach(caseElement -> {
|
||||
((List<Element>) caseElement.elements()).forEach(labelElement -> {
|
||||
//去掉末尾的s
|
||||
// 获取case标签下所有的标签,存储至fieldTextMap,以初始化所有的字段名称
|
||||
configXml.getRootElement().elements("case").forEach(caseElement -> {
|
||||
caseElement.elements().forEach(labelElement -> {
|
||||
// 去掉末尾的s
|
||||
String name = labelElement.getName();
|
||||
fieldTextMap.put(name.substring(0, name.length() - 1), new ArrayList<String>());
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于添加一行文本
|
||||
*
|
||||
* @param labelType 标签名称(枚举)
|
||||
* @param text 相应内容
|
||||
* @param text 相应内容
|
||||
*/
|
||||
protected void addFieldText(LabelType labelType, String text) {
|
||||
fieldTextMap.get(labelType.getName()).add(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于添加多行文本
|
||||
*
|
||||
* @param labelName 标签名称
|
||||
* @param texts 相应内容
|
||||
* @param texts 相应内容
|
||||
*/
|
||||
protected void addFieldText(String labelName, List<String> texts) {
|
||||
fieldTextMap.get(labelName).addAll(texts);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于添加一行文本
|
||||
*
|
||||
* @param labelName 标签名称
|
||||
* @param text 相应内容
|
||||
* @param text 相应内容
|
||||
*/
|
||||
protected void addFieldText(String labelName, String text) {
|
||||
fieldTextMap.get(labelName).add(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于添加多行文本
|
||||
*
|
||||
* @param label 标签名称(枚举)
|
||||
* @param texts 相应内容
|
||||
*/
|
||||
protected void addFieldText(LabelType label, List<String> texts) {
|
||||
fieldTextMap.get(label.getName()).addAll(texts);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于清空字段的内容,以避免存储上一次输入的用例
|
||||
*/
|
||||
|
@ -283,29 +297,28 @@ public abstract class Case {
|
|||
fieldTextMap.get(key).clear();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 由于添加与参数相关的数据时需要将关联的字段(如步骤及结果)都添加至其中,
|
||||
* 若后期关联字段增加,则代码量将是成倍的增加,故将关联的内容提取出来,在
|
||||
* 外部进行添加,之后修改关联字段时只需修改该方法即可。若传入-1,则表示
|
||||
* 获取xml中该标签下的所有的信息<br>
|
||||
|
||||
/**
|
||||
* 由于添加与参数相关的数据时需要将关联的字段(如步骤及结果)都添加至其中, 若后期关联字段增加,则代码量将是成倍的增加,故将关联的内容提取出来,在
|
||||
* 外部进行添加,之后修改关联字段时只需修改该方法即可。若传入-1,则表示 获取xml中该标签下的所有的信息<br>
|
||||
* 参数表:
|
||||
* <ol>
|
||||
* <li>步骤</li>
|
||||
* <li>预期</li>
|
||||
* </ol>
|
||||
*
|
||||
* @param caseName 读取的用例名称
|
||||
* @param ids id参数串
|
||||
* @param ids id参数串
|
||||
*/
|
||||
protected void relevanceAddData(String caseName, String...ids) {
|
||||
//添加步骤
|
||||
protected void relevanceAddData(String caseName, String... ids) {
|
||||
// 添加步骤
|
||||
if (ids[0].equals(ALL)) {
|
||||
addFieldText(LabelType.STEP, getAllLabelText(caseName, LabelType.STEP));
|
||||
} else {
|
||||
addFieldText(LabelType.STEP, getLabelText(caseName, LabelType.STEP, ids[0]));
|
||||
}
|
||||
|
||||
//添加预期
|
||||
|
||||
// 添加预期
|
||||
if (ids[1].equals(ALL)) {
|
||||
addFieldText(LabelType.EXCEPT, getAllLabelText(caseName, LabelType.EXCEPT));
|
||||
} else {
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.auxiliary.tool.data;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
@ -20,7 +21,7 @@ import java.util.stream.Collectors;
|
|||
* <b>编码时间:</b>2020年12月22日上午8:27:07
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2020年12月22日上午8:27:07
|
||||
* <b>修改时间:</b>2021年2月20日上午7:20:37
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
|
@ -145,10 +146,10 @@ public class ListUtil {
|
|||
/**
|
||||
* 用于对列表中的数据类型进行转换,返回新数据类型的列表
|
||||
*
|
||||
* @param <T> 原数据类型
|
||||
* @param <U> 新数据类型
|
||||
* @param <T> 原数据类型
|
||||
* @param <U> 新数据类型
|
||||
* @param tableData 原数据类型表
|
||||
* @param mapper 数据转换方式
|
||||
* @param mapper 数据转换方式
|
||||
* @return 转换后的数据类型表
|
||||
*/
|
||||
public static <T, U> TableData<U> changeTable(TableData<T> tableData, Function<T, U> mapper) {
|
||||
|
@ -156,6 +157,76 @@ public class ListUtil {
|
|||
tableData.columnForEach((key, value) -> newTable.addColumn(key, changeList(value, mapper).stream()
|
||||
.map(dataOptional -> dataOptional.orElse(null)).collect(Collectors.toList())));
|
||||
return newTable;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于对集合中的元素进行去重
|
||||
* <p>
|
||||
* <b>注意:</b>被比较的泛型对象去重按照equals()方法进行比较,需要正确实现equals()方法,才能达到去重的目的
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 需要去重的数据类型
|
||||
* @param list 需要去重的集合
|
||||
* @return 去重后的集合
|
||||
*/
|
||||
public static <T> List<Optional<T>> removeRepetition(List<Optional<T>> list) {
|
||||
LinkedHashSet<Optional<T>> set = new LinkedHashSet<>();
|
||||
Optional.ofNullable(list).filter(l -> !l.isEmpty()).ifPresent(l -> l.forEach(set::add));
|
||||
|
||||
return new ArrayList<Optional<T>>(set);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于根据指定的条件行对表中的数据进行去重
|
||||
* <p>
|
||||
* 方法需要指定列名,表示以指定的列为基准,对数据进行去重。类似于数据库中指定字段为主键或联合主键。
|
||||
* 当指定的列的数据重复时,将舍弃该数据所在行的整行数据,达到去重的目的
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>注意:</b>
|
||||
* <ol>
|
||||
* <li>被比较的泛型对象去重按照equals()方法进行比较,需要正确实现equals()方法</li>
|
||||
* <li>被舍弃的数据不区分其他内容,只保留第一次存储的数据</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @param <T> 需要去重的数据类型
|
||||
* @param tableData 需要去重的表
|
||||
* @param columns 作为条件的列名称
|
||||
* @return 去重后的表
|
||||
*/
|
||||
public static <T> TableData<T> removeRepetition(TableData<T> tableData, String... columns) {
|
||||
//若传入的条件为空,则直接返回传入的tableData
|
||||
if (!Optional.ofNullable(columns).filter(cs -> cs.length != 0).isPresent()) {
|
||||
return tableData;
|
||||
}
|
||||
|
||||
//定义新的表数据,并初始化其标题
|
||||
TableData<T> nowTable = new TableData<>();
|
||||
|
||||
//按行遍历tableData的所有数据,过滤掉与nowTable中指定行数据一致的行数据,之后添加未被过滤的数据
|
||||
Optional.ofNullable(tableData).filter(td -> !td.isEmpty()).ifPresent(td -> {
|
||||
nowTable.addTitle(tableData.getColumnName());
|
||||
td.rowStream().filter(list -> {
|
||||
boolean isRepeat = true;
|
||||
for (String column : columns) {
|
||||
//获取指定列数据,若新表中该列的数据包含了当前的数据,则返回false
|
||||
if (nowTable.getColumnList(column).contains(list.get(tableData.getFieldIndex(column)))) {
|
||||
isRepeat = true;
|
||||
continue;
|
||||
} else {
|
||||
isRepeat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//返回不重复的结果
|
||||
return !isRepeat;
|
||||
//由于返回的元素为封装类对象,需要对元素脱壳处理。处理方式为直接返回即可
|
||||
}).map(list -> list.stream().map(e -> e.get()).collect(Collectors.toList())).forEach(nowTable::addRow);
|
||||
});
|
||||
|
||||
return nowTable;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.stream.Stream;
|
|||
* <b>编码时间:</b>2020年12月17日上午8:24:47
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>修改时间:</b>2020年12月17日上午8:24:47
|
||||
* <b>修改时间:</b>2021年2月19日下午6:39:48
|
||||
* </p>
|
||||
*
|
||||
* @author 彭宇琦
|
||||
|
@ -66,6 +66,10 @@ public class TableData<T> {
|
|||
public TableData(Map<String, ? extends List<T>> tableMap) {
|
||||
tableMap.forEach(this::addColumn);
|
||||
}
|
||||
|
||||
public TableData(TableData<T> tableData) {
|
||||
this.addTable(tableData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于设置是否对传入的数据列表的个数进行严格校验,即在调用{@link #getData(int, int, List)}等获取数据的方法时,
|
||||
|
@ -363,8 +367,8 @@ public class TableData<T> {
|
|||
* @return 指定列的所有数据
|
||||
*/
|
||||
public ArrayList<Optional<T>> getColumnList(String columnName) {
|
||||
columnName = Optional.ofNullable(columnName).filter(tableMap::containsKey)
|
||||
.orElseThrow(() -> new IllegalDataException("不存在的元素列"));
|
||||
Optional.ofNullable(columnName).filter(tableMap::containsKey)
|
||||
.orElseThrow(() -> new IllegalDataException("不存在的元素列:" + columnName));
|
||||
|
||||
ArrayList<Optional<T>> columnDataList = new ArrayList<>();
|
||||
columnDataList.addAll(tableMap.get(columnName));
|
||||
|
@ -389,7 +393,7 @@ public class TableData<T> {
|
|||
public Optional<T> getFirstData() {
|
||||
return getFirstColumn().get(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 用于获取指定列与指定列的数据,并以传入的字段顺序,将获取到的每列数据进行存储
|
||||
* <p>
|
||||
|
@ -549,7 +553,7 @@ public class TableData<T> {
|
|||
public void columnForEach(BiConsumer<String, List<Optional<T>>> action) {
|
||||
tableMap.forEach(action);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 刷新表中最长与最短列的元素个数,用于清空或删除表时的计算
|
||||
*/
|
||||
|
@ -587,4 +591,9 @@ public class TableData<T> {
|
|||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[" + tableMap + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -465,7 +465,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @throws IOException 流异常时抛出的异常
|
||||
* @throws IncorrectFileException 当模板文件内容异常时抛出的异常
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public void writeFile() throws IOException {
|
||||
// 定义输入流,用于读取模版文件
|
||||
FileInputStream fip = new FileInputStream(tempFile);
|
||||
|
@ -507,7 +506,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param caseElement case标签对应的elemenet对象
|
||||
* @return 当前行号
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeContent(int index, XSSFSheet xs, Element caseElement) {
|
||||
// 获取字段元素,需要获取配置xml文件中的以及用例xml文件中的字段
|
||||
List<Element> fieldElements = caseElement.elements("field");
|
||||
|
@ -804,7 +802,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
*
|
||||
* @param sheetName sheet的name属性
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void getAllColumnId() {
|
||||
// 清空fieldMap中的内容
|
||||
// fieldMap.clear();
|
||||
|
@ -1148,7 +1145,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param content 标记中记录的内容
|
||||
* @return 类本身
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public FieldMark fieldComment(String sheetName, String field, String content) {
|
||||
// 查找nowSheetName指向的sheet中的与uuid一致的单元格
|
||||
Element caseElement = getCaseElement(sheetName);
|
||||
|
@ -1183,7 +1179,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param markColorsType {@link MarkColorsType}类枚举
|
||||
* @return 类本身
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public FieldMark changeFieldBackground(String sheetName, String field, MarkColorsType markColorsType) {
|
||||
// 查找nowSheetName指向的sheet中的与uuid一致的单元格
|
||||
Element caseElement = getCaseElement(sheetName);
|
||||
|
@ -1216,7 +1211,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param markColorsType {@link MarkColorsType}类枚举
|
||||
* @return 类本身
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public FieldMark changeRowBackground(String sheetName, MarkColorsType markColorsType) {
|
||||
// 查找nowSheetName指向的sheet中的与uuid一致的单元格
|
||||
Element caseElement = getCaseElement(sheetName);
|
||||
|
@ -1244,7 +1238,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param markColorsType {@link MarkColorsType}类枚举
|
||||
* @return 类本身
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public FieldMark changeRowTextColor(String sheetName, MarkColorsType markColorsType) {
|
||||
// 查找nowSheetName指向的sheet中的与uuid一致的单元格
|
||||
Element caseElement = getCaseElement(sheetName);
|
||||
|
@ -1310,7 +1303,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> {
|
|||
* @param markColorsType {@link MarkColorsType}类枚举
|
||||
* @return 类本身
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public FieldMark changeTextColor(String sheetName, String field, int startIndex, int endIndex,
|
||||
MarkColorsType markColorsType) {
|
||||
// 查找nowSheetName指向的sheet中的与uuid一致的单元格
|
||||
|
|
|
@ -239,7 +239,6 @@ public class CreateExcelFile {
|
|||
*
|
||||
* @param xw 指向excel文件对象
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void createDataValidation(XSSFWorkbook xw) {
|
||||
// 读取所有sheet标签
|
||||
List<Element> xmlSheetList = xml.getRootElement().elements("sheet");
|
||||
|
@ -336,7 +335,6 @@ public class CreateExcelFile {
|
|||
* @param rowIndex
|
||||
* @param columnIndex
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private void writeDataValidity(Element datasElement, XSSFSheet dataSheet, int rowIndex, int columnIndex) {
|
||||
// 添加数据,获取相应datas下的所有data标签
|
||||
List<Element> dataElementList = datasElement.elements();
|
||||
|
|
Loading…
Reference in New Issue