From 49c25fa57f5cc3a1a4693434102086972e3c3248 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Sat, 22 Aug 2020 14:44:28 +0800
Subject: [PATCH 1/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B6=85=E9=93=BE?=
=?UTF-8?q?=E6=8E=A5=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../tool/file/excel/AbstractWriteExcel.java | 562 +++++++++++-------
1 file changed, 356 insertions(+), 206 deletions(-)
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
index 2695072..f2a2f44 100644
--- a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
+++ b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
@@ -3,6 +3,7 @@ package pres.auxiliary.tool.file.excel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -37,8 +38,6 @@ import org.dom4j.io.SAXReader;
import pres.auxiliary.tool.regex.RegexType;
import pres.auxiliary.work.selenium.datadriven.ListFileRead;
-import pres.auxiliary.work.selenium.xml.UndefinedElementException;
-import pres.auxiliary.work.testcase.file.FieldType;
import pres.auxiliary.work.testcase.file.IncorrectFileException;
import pres.auxiliary.work.testcase.file.MarkColorsType;
import pres.auxiliary.work.testcase.templet.LabelNotFoundException;
@@ -71,34 +70,39 @@ public abstract class AbstractWriteExcel> {
/**
* 用于对待替换词语的标记
*/
- private final String WORD_SIGN = "\\#";
+ protected final String WORD_SIGN = "\\#";
/**
* 用于存储一条用例的信息,第一个参数指向配置文件中的字段id,第二个字段为xml文件中字段的相应信息
*/
- protected HashMap fieldMap = new HashMap<>(16);
-// protected HashMap> fieldMap = new HashMap<>(16);
+// protected HashMap fieldMap = new HashMap<>(16);
+ protected HashMap> fieldMap = new HashMap<>(16);
/**
* 用于存储所有用例均使用的字段常值
*/
- private HashMap constValueMap = new HashMap<>(16);
-// private HashMap> constValueMap = new HashMap<>(16);
+// private HashMap constValueMap = new HashMap<>(16);
+ protected HashMap> constValueMap = new HashMap<>(16);
/**
* 用于存储待替换的词语以及被替换的词语
*/
- private HashMap replaceWordMap = new HashMap<>(16);
+ protected HashMap replaceWordMap = new HashMap<>(16);
+
+ /**
+ * 用于存储当前用例中正在编写的
+ */
+ protected ArrayList writeSheetNameList = new ArrayList<>();
/**
* 用于存储当前对应的sheet名称
*/
- private String sheetName = "";
+ protected String nowSheetName = "";
/**
* 指向模板文件
*/
- private File tempFile;
+ protected File tempFile;
/**
* 指向配置文件的Document对象
@@ -144,7 +148,8 @@ public abstract class AbstractWriteExcel> {
}
// 获取xml文件中的第一个sheet标签,则将该标签的name属性内容传入getColumnId中
- switchSheet(configXml.getRootElement().element("sheet").attributeValue("name"));
+// switchSheet(configXml.getRootElement().element("sheet").attributeValue("name"));
+ getAllColumnId();
// 创建存储字段内容的document类对象
contentXml = DocumentHelper.createDocument();
@@ -159,20 +164,24 @@ public abstract class AbstractWriteExcel> {
*
* @param sheetName xml配置文件中sheet的name字段内容
*/
- public void switchSheet(String sheetName) {
+ @SuppressWarnings("unchecked")
+ public T switchSheet(String sheetName) {
// 每次切换sheet时,要重新获取一次sheet下的字段id。
// 切换sheet后需要清空预设字段中的内容
// 重新获取id,包括清空fieldMap
- getColumnId(sheetName);
+// getColumnId(sheetName);
// 清空常值map
- constValueMap.clear();
+// constValueMap.clear();
// 清空标记map
// fieldMarkMap.clear();
// 清空预设字段枚举值
// Arrays.stream(FieldType.values()).forEach(e -> e.setValue(""));
// 将相应的sheet标签的name属性存储至sheetName中
- this.sheetName = sheetName;
+ this.nowSheetName = sheetName;
+ writeSheetNameList.add(sheetName);
+
+ return (T) this;
}
@@ -187,12 +196,19 @@ public abstract class AbstractWriteExcel> {
public void setFieldValue(String field, String content) {
// 为保证在写用例的时候也能生效,故将值设置进入fieldMap
//为保证内容被重复添加,故需要清空原始内容
- clearContent(field);
- addContent(field, content);
+// clearContent(field);
+// addContent(field, content);
// 先将值设置入fieldMap中可以保证field字段是存在于fieldMap中,以减少此处再做判断
// 将字段内容写入caseValueMap
- constValueMap.put(field, content);
+// constValueMap.put(field, content);
+ //若当前sheetName中不存在常量,则先构造HashMap
+ if (!constValueMap.containsKey(nowSheetName)) {
+ constValueMap.put(nowSheetName, new HashMap(16));
+ }
+
+ //添加常量
+ constValueMap.get(nowSheetName).put(field, content);
}
/**
@@ -222,7 +238,7 @@ public abstract class AbstractWriteExcel> {
* @throws LabelNotFoundException 当在sheet标签中查不到相应的单元格id不存在时抛出的异常
*/
public T addContent(String field, String... contents) {
- return insertContent(field, fieldMap.get(field).content.size(), contents);
+ return insertContent(field, fieldMap.get(nowSheetName).get(field).content.size(), contents);
}
/**
@@ -235,14 +251,14 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public T removeContent(String field, int...indexs) {
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
//移除相关的内容,若输入的序号不存在,则不进行
Arrays.stream(indexs).forEach(index -> {
try {
- fieldMap.get(field).content.remove(index);
+ fieldMap.get(nowSheetName).get(field).content.remove(index);
} catch (Exception e) {
}
});
@@ -269,30 +285,36 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public T insertContent(String field, int index, String... contents) {
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
+ //若writeSheetNameList中未存储内容,则将当前的sheet名称存储到writeSheetNameList中,
+ //用于记录当前sheet有内容更新
+ if (writeSheetNameList.isEmpty()) {
+ writeSheetNameList.add(nowSheetName);
+ }
+
//若未传值或传入null,则直接结束
if (contents == null || contents.length == 0) {
return (T) this;
}
//若传入的下标大于相应的最大段落数时,则直接结束
- if (index > fieldMap.get(field).content.size()) {
+ if (index > fieldMap.get(nowSheetName).get(field).content.size()) {
return (T) this;
}
- if (fieldMap.get(field).datas.size() != 0) {
+ if (fieldMap.get(nowSheetName).get(field).datas.size() != 0) {
//查找数据有效性,若当前字段存在数据有效性,则将数据有效性转义,若添加的字段无法转义,则存储原内容
- contents = dataValidityChange(contents, fieldMap.get(field));
+ contents = dataValidityChange(contents, fieldMap.get(nowSheetName).get(field));
}
// 查找特殊词语,并对词语进行替换
contents = replaceWord(contents);
// 将字段内容写入fieldMap,若插入的下标不正确,则不做任何处理
try {
- fieldMap.get(field).content.addAll(index, Arrays.asList(contents));
+ fieldMap.get(nowSheetName).get(field).content.addAll(index, Arrays.asList(contents));
} catch (Exception e) {
}
@@ -314,7 +336,7 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public T replaceContent(String field, int index, String... contents) {
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
@@ -324,7 +346,7 @@ public abstract class AbstractWriteExcel> {
}
//若传入的下标大于相应的最大段落数时,则直接结束
- if (index >= fieldMap.get(field).content.size()) {
+ if (index >= fieldMap.get(nowSheetName).get(field).content.size()) {
return (T) this;
}
@@ -345,11 +367,11 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public T clearContent(String field) {
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
- fieldMap.get(field).content.clear();
+ fieldMap.get(nowSheetName).get(field).content.clear();
return (T) this;
}
@@ -359,6 +381,7 @@ public abstract class AbstractWriteExcel> {
*/
@SuppressWarnings("unchecked")
public FieldMark end() {
+ /*
// 写入到caseXml中
// 获取所有的sheet标签, 并筛选出name属性为sheetName的标签
List sheetList = ((List) (contentXml.getRootElement().elements("sheet"))).stream()
@@ -370,51 +393,70 @@ public abstract class AbstractWriteExcel> {
} else {
sheetElement = contentXml.getRootElement().addElement("sheet").addAttribute("name", sheetName);
}
+ */
- // 创建case标签
+ //生成case标签的uuid
String caseUuid = UUID.randomUUID().toString();
- Element caseElement = sheetElement.addElement("case").addAttribute("id", caseUuid);
- // 为fieldMap中的所有key创建field标签,并记录相应的value
- fieldMap.forEach((id, field) -> {
- //判断字段是否需要进行编号,若需要编号,则调用编号方法
- if (field.serialNumber) {
- addSerialNumber(field);
+ // 创建case标签
+ writeSheetNameList.forEach(sheetName -> {
+ // 写入到caseXml中
+ // 获取所有的sheet标签, 并筛选出name属性为sheetName的标签
+ Element sheetElement = null;
+ for (Element element : ((List) (contentXml.getRootElement().elements("sheet")))) {
+ if (element.attributeValue("name").equals(sheetName)) {
+ sheetElement = element;
+ }
}
- // 添加field标签,并设置name属性(字段名称),mark属性(备注内容)
- // dom4j当属性值传入null时,则直接不会创建该属性,故此处无需做判断字段id是否在fieldMarkMap中
- Element fieldElement = caseElement.addElement("field").addAttribute("name", id);
-
- //若字段上存在超链接,则在xml上加上超链接属性
- /*
- if (!field.link.isEmpty()) {
- fieldElement.addAttribute("link", field.link);
+ // 判断是否存在sheet标签,若不存在,则创建相应的标签
+ if (sheetElement == null) {
+ sheetElement = contentXml.getRootElement().addElement("sheet").addAttribute("name", sheetName);
}
- */
- // 判断当前是否有添加内容,若未添加内容,则创建一个value属性为空的text标签
- if (field.content != null) {
- // 读取所有texts(字符串数组)的所有内容,并为每一元素创建一个text标签,将值加入属性中
- field.content.forEach(text -> {
- fieldElement.addElement("text").addAttribute("value", text);
- });
- } else {
- fieldElement.addElement("text").addAttribute("value", "");
- }
- });
-
- // 清空fieldMap中的内容
- clearFieldContent();
- // 将字段常值设置入fieldMap中,若抛出异常,则不进行处理
- if (constValueMap != null && constValueMap.size() != 0) {
- constValueMap.forEach((field, content) -> {
- try {
- addContent(field, content);
- } catch (LabelNotFoundException e) {
+ Element caseElement = sheetElement.addElement("case").addAttribute("id", caseUuid);
+ // 为fieldMap中的所有key创建field标签,并记录相应的value
+ fieldMap.get(nowSheetName).forEach((id, field) -> {
+ //判断字段是否需要进行编号,若需要编号,则调用编号方法
+ if (field.serialNumber) {
+ addSerialNumber(field);
+ }
+
+ // 添加field标签,并设置name属性(字段名称),mark属性(备注内容)
+ // dom4j当属性值传入null时,则直接不会创建该属性,故此处无需做判断字段id是否在fieldMarkMap中
+ Element fieldElement = caseElement.addElement("field").addAttribute("name", id);
+
+ // 判断当前是否有添加内容,若未添加内容,则创建一个value属性为空的text标签
+ if (field.content != null && !field.content.isEmpty()) {
+ // 读取所有texts(字符串数组)的所有内容,并为每一元素创建一个text标签,将值加入属性中
+ field.content.forEach(text -> {
+ fieldElement.addElement("text").addAttribute("value", text);
+ });
+ } else {
+ //判断当前字段是否存在于constValueMap中,若存在,则填写constValueMap中的内容
+ if (constValueMap != null && constValueMap.get(nowSheetName) != null && constValueMap.get(nowSheetName).containsKey(field.id)) {
+ //TODO 解决常值只能添加一个问题时需要修改此处代码
+ fieldElement.addElement("text").addAttribute("value", dataValidityChange(new String[] {constValueMap.get(nowSheetName).get(field.id)}, field)[0]);
+ } else {
+ fieldElement.addElement("text").addAttribute("value", "");
+ }
}
});
- }
+ // 清空fieldMap中的内容
+ clearFieldContent();
+ // 将字段常值设置入fieldMap中,若抛出异常,则不进行处理
+ /*
+ if (constValueMap != null && constValueMap.size() != 0) {
+ constValueMap.get(nowSheetName).forEach((field, content) -> {
+ try {
+ addContent(field, content);
+ } catch (LabelNotFoundException e) {
+ }
+ });
+ }
+ */
+ });
+
return new FieldMark(caseUuid);
}
@@ -475,7 +517,7 @@ public abstract class AbstractWriteExcel> {
// 获取相应的Field对象
String fieldId = fieldElement.attributeValue("name");
// 获取字段的field对象
- Field field = fieldMap.get(fieldId);
+ Field field = fieldMap.get(nowSheetName).get(fieldId);
// 获取text标签
List textList = fieldElement.elements("text");
@@ -633,39 +675,6 @@ public abstract class AbstractWriteExcel> {
}
}
- /**
- * 将xml文件中编写的文档内部超链接内容进行转换
- * @param linkContent 链接内容
- * @return 转换后的在poi使用的超链接代码
- */
- protected String getDocumentLinkPath(String linkContent) {
- String[] linkContents = linkContent.split("|");
- int length = linkContents.length;
-
- //若切分后,其长度小于2位,则抛出异常
- if (length < 2) {
- throw new IncorrectIndexException("文档内部链接编写错误,缺少分隔符“|”:" + linkContent);
- }
-
- //获取超链接的sheet名称
- String linkSheetName = linkContents[0];
- //根据sheet名称以及字段id,获取该字段在sheet中的列数字下标,并将数字下标转换为英文下标
- String linkColumnIndex = num2CharIndex(getColumnNumIndex(linkSheetName, linkContents[1]));
-
- String linkRowIndex = "";
- //判断当前linkContents是否存在链接行数(即第三个元素)且链接的文本为数字
- //若符合规则,则将linkRowIndex设置为当前编写的内容
- //若不符合规则,则将linkRowIndex设置为当前sheet的最后一行
- if (length > 2 && linkContents[2].matches("[0-9]+")) {
- linkRowIndex = linkContents[2];
- } else {
- linkRowIndex = String.valueOf(xw.getSheet(linkSheetName).getLastRowNum());
- }
-
- //返回文档链接的内容
- return "'" + sheetName + "'!" + linkColumnIndex + linkRowIndex;
- }
-
/**
* 返回文本中字段对应的样式,可在该方法中添加字段需要添加的相应样式
*
@@ -759,7 +768,7 @@ public abstract class AbstractWriteExcel> {
* 清空fieldMap内的存储字段信息,不清除字段
*/
private void clearFieldContent() {
- fieldMap.forEach((key, value) -> value.clearContent());
+ fieldMap.get(nowSheetName).forEach((key, value) -> value.clearContent());
}
/**
@@ -768,43 +777,51 @@ public abstract class AbstractWriteExcel> {
* @param sheetName sheet的name属性
*/
@SuppressWarnings("unchecked")
- private void getColumnId(String sheetName) {
+ private void getAllColumnId() {
// 清空fieldMap中的内容
- fieldMap.clear();
+// fieldMap.clear();
// 获取相应的sheet标签元素
- Element sheetElement = (Element) (configXml.selectSingleNode("//sheet[@name='" + sheetName + "']"));
- // 获取相应的sheet标签下的column标签
- List column = sheetElement.elements("column");
+// Element sheetElement = (Element) (configXml.selectSingleNode("//sheet[@name='" + sheetName + "']"));
+ configXml.getRootElement().elements("sheet").forEach(sheetElement -> {
+ // 获取相应的sheet标签下的column标签
+ List column = ((Element) sheetElement).elements("column");
- // 初始化fieldMap中的字段及其值
- for (int index = 0; index < column.size(); index++) {
- // 查找xml文件中数据有效性标签
- List datasList = sheetElement.elements("datas");
- ArrayList datas = new ArrayList();
- // 遍历所有的数据有效性标签,若存在,则存储相应的数据有效性
- for (Element datasElemenet : datasList) {
- if (datasElemenet.attributeValue("id").equals(column.get(index).attributeValue("id"))) {
- //存储当前的数据有效性的内容
- ((List)(datasElemenet.elements())).forEach(textElement -> {
- //判断数据有效性的存放位置,并按照相应的方法读取数据有效性
- if ("file".equalsIgnoreCase(textElement.getName())) {
- datas.addAll(getFileDataValidity(textElement));
- } else {
- datas.add(getLabelDataValidity(textElement));
- }
- });
- break;
+ // 初始化fieldMap中的字段及其值
+ for (int index = 0; index < column.size(); index++) {
+ // 查找xml文件中数据有效性标签
+ List datasList = ((Element) sheetElement).elements("datas");
+ ArrayList datas = new ArrayList();
+ // 遍历所有的数据有效性标签,若存在,则存储相应的数据有效性
+ for (Element datasElemenet : datasList) {
+ if (datasElemenet.attributeValue("id").equals(column.get(index).attributeValue("id"))) {
+ //存储当前的数据有效性的内容
+ ((List)(datasElemenet.elements())).forEach(textElement -> {
+ //判断数据有效性的存放位置,并按照相应的方法读取数据有效性
+ if ("file".equalsIgnoreCase(textElement.getName())) {
+ datas.addAll(getFileDataValidity(textElement));
+ } else {
+ datas.add(getLabelDataValidity(textElement));
+ }
+ });
+ break;
+ }
}
+
+ //若fieldMap中不存在sheetName,则添加相应的内容
+ String sheetName = ((Element) sheetElement).attributeValue("name");
+ if (!fieldMap.containsKey(sheetName)) {
+ fieldMap.put(sheetName, new HashMap(16));
+ }
+ nowSheetName = sheetName;
+
+ // 存储字段信息
+ fieldMap.get(sheetName).put(column.get(index).attributeValue("id"),
+ new Field(column.get(index).attributeValue("id"), column.get(index).attributeValue("align"), index,
+ column.get(index).attributeValue("row_text"), datas,
+ Boolean.valueOf(column.get(index).attributeValue("index"))));
}
-
- // 存储字段信息
- fieldMap.put(column.get(index).attributeValue("id"),
- new Field(column.get(index).attributeValue("id"), column.get(index).attributeValue("align"), index,
- column.get(index).attributeValue("row_text"), datas,
- Boolean.valueOf(column.get(index).attributeValue("index")),
- column.get(index).attributeValue("link")));
- }
+ });
}
/**
@@ -907,33 +924,6 @@ public abstract class AbstractWriteExcel> {
}
}
- /**
- * 用于根据xml配置文件中的标签元素下标,返回其在excel中对应的字母
- * @param sheetName sheet标签的name属性值
- * @param columenId columen标签的id属性值
- * @return 对应columen在excel中的列标字母
- */
- /*
- protected String getColumn(String sheetName, String columenId) {
- //根据sheet名称获取相应的sheet元素
- Element sheetElement = (Element) configXml.selectSingleNode("//sheet[@name='" + sheetName +"']");
-
- //查找元素下所有column标签
- List> columnElementList = sheetElement.elements("column");
- //遍历columnElementList,根据columenId反推对应的元素所在的下标
- int index = 0;
- for (; index < columnElementList.size(); index++) {
- if (((Element) columnElementList.get(index)).attributeValue("id").equals(columenId)) {
- break;
- }
- }
-
- //根据下标,计算列表元素相应的字母,并以字符串的形式返回
- //A的ascii为65
- return String.valueOf((char) (65 + index));
- }
- */
-
/**
* 用于根据xml文件中columenId字段所在的位置,推出字段在excel中的数字下标
* @param sheetName 字段所在的sheet名称
@@ -1020,12 +1010,28 @@ public abstract class AbstractWriteExcel> {
return numberIndex;
}
+ /**
+ * 用于将传入的下标转换为poi识别的下标,主要用于处理负数下标问题,以方便其他的方法的调用。
+ * 若传入的下标大于总长度,则输出总长度-1,若负数的绝对值超过总长度,则输出0
+ * @param length 总行数或总列数
+ * @param index 传入的下标
+ * @return 能被poi识别的下标
+ */
+ protected int getPoiIndex(int length, int index) {
+ //判断下标的绝对值是否大于总长度,若大于总长度,则根据index的正负来判断返回值
+ if (Math.abs(index) > length) {
+ return index > 0 ? length - 1 : 0;
+ }
+
+ //若下标绝对值小于length,则判断下标正负,正数则直接返回,负数,则通过总长度
+ //减去下标(由于下标是负数,故计算时用总长度加上下标)
+ return index > 0 ? index : length + index;
+ }
+
/**
* 用于测试fieldMap中的内容,编码结束后删除
*/
- /*
- * public HashMap getCharMap() { return fieldMap; }
- */
+ public HashMap.Field>> getCharMap() { return fieldMap; }
/**
* 用于测试rank中的内容,编码结束后删除
@@ -1037,14 +1043,14 @@ public abstract class AbstractWriteExcel> {
/**
* 用于测试caseXml文件,编码结束后删除
*/
-// public File getCaseXml() throws IOException {
-// File file = new File("src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml");
-// FileWriter fw = new FileWriter(file);
-// caseXml.write(fw);
-// fw.close();
-//
-// return file;
-// }
+ public File getCaseXml() throws IOException {
+ File file = new File("src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml");
+ FileWriter fw = new FileWriter(file);
+ contentXml.write(fw);
+ fw.close();
+
+ return file;
+ }
/**
*
@@ -1067,7 +1073,8 @@ public abstract class AbstractWriteExcel> {
*/
public class FieldMark {
// 用于存储case标签元素
- Element caseElement;
+// Element caseElement;
+ String uuid;
/**
* 构造类,但不允许外部进行构造
@@ -1075,20 +1082,34 @@ public abstract class AbstractWriteExcel> {
* @param uuid 用例的uuid
*/
private FieldMark(String uuid) {
- caseElement = ((Element) (contentXml.selectSingleNode("//*[@id='" + uuid + "']")));
+ this.uuid = uuid;
}
/**
- * 向单元格(字段)上添加一个标记(备注),以记录内容
+ * 向当前指向的sheet中的单元格(字段)上添加一个标记(备注),以记录内容
+ *
+ * @param field 字段id
+ * @param content 标记中记录的内容
+ * @return 类本身
+ */
+ public FieldMark fieldComment(String field, String content) {
+ return fieldComment(nowSheetName, field, content);
+ }
+
+ /**
+ * 向sheet中的单元格(字段)上添加一个标记(备注),以记录内容
*
* @param field 字段id
* @param content 标记中记录的内容
* @return 类本身
*/
@SuppressWarnings("unchecked")
- public FieldMark fieldComment(String field, String content) {
+ public FieldMark fieldComment(String sheetName, String field, String content) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
@@ -1100,84 +1121,155 @@ public abstract class AbstractWriteExcel> {
}
/**
- * 用于对字段所在的单元格的背景色进行修改
+ * 用于对当前指向的sheet中字段所在的单元格的背景色进行修改
*
* @param field 字段id
- * @param colors {@link MarkColorsType}类枚举
+ * @param markColorsType {@link MarkColorsType}类枚举
+ * @return 类本身
+ */
+ public FieldMark changeFieldBackground(String field, MarkColorsType markColorsType) {
+ return changeFieldBackground(nowSheetName, field, markColorsType);
+ }
+
+ /**
+ * 用于对指定sheet中字段所在的单元格的背景色进行修改
+ *
+ * @param field 字段id
+ * @param markColorsType {@link MarkColorsType}类枚举
* @return 类本身
*/
@SuppressWarnings("unchecked")
- public FieldMark changeFieldBackground(String field, MarkColorsType color) {
+ public FieldMark changeFieldBackground(String sheetName, String field, MarkColorsType markColorsType) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
// 向包含uuid的标签下添加相应的属性
((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field))
- .forEach(e -> e.addAttribute("background", String.valueOf(color.getColorsValue())));
+ .forEach(e -> e.addAttribute("background", String.valueOf(markColorsType.getColorsValue())));
return this;
}
/**
- * 对整行用例的背景色进行更改(标记)
+ * 对当前指向的sheet的整行用例的背景色进行更改(标记)
*
- * @param colors {@link MarkColorsType}类枚举
+ * @param markColorsType {@link MarkColorsType}类枚举
+ * @return 类本身
+ */
+ public FieldMark changeRowBackground(MarkColorsType markColorsType) {
+ return changeRowBackground(nowSheetName, markColorsType);
+ }
+
+ /**
+ * 对指定sheet的整行用例的背景色进行更改(标记)
+ *
+ * @param markColorsType {@link MarkColorsType}类枚举
* @return 类本身
*/
@SuppressWarnings("unchecked")
- public FieldMark changeRowBackground(MarkColorsType color) {
+ public FieldMark changeRowBackground(String sheetName, MarkColorsType markColorsType) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+
// 将case下所有标签的name属性传至fieldBackground方法
((List) (caseElement.elements())).stream()
- .forEach(e -> changeFieldBackground(e.attributeValue("name"), color));
+ .forEach(e -> changeFieldBackground(e.attributeValue("name"), markColorsType));
return this;
}
/**
- * 该方法用于对整行用例文本的颜色进行标记
+ * 该方法用于对当前指向的sheet的整行用例文本的颜色进行标记
*
- * @param color {@link MarkColorsType}类枚举
+ * @param markColorsType {@link MarkColorsType}类枚举
+ * @return 类本身
+ */
+ public FieldMark changeRowTextColor(MarkColorsType markColorsType) {
+ return changeRowTextColor(nowSheetName, markColorsType);
+ }
+
+ /**
+ * 该方法用于对指定的sheet中整行用例文本的颜色进行标记
+ *
+ * @param markColorsType {@link MarkColorsType}类枚举
* @return 类本身
*/
@SuppressWarnings("unchecked")
- public FieldMark changeRowTextColor(MarkColorsType color) {
+ public FieldMark changeRowTextColor(String sheetName, MarkColorsType markColorsType) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+
// 将case下所有标签的name属性传至fieldBackground方法
((List) (caseElement.elements())).forEach(fieldElement -> {
List textElements = fieldElement.elements();
- changeTextColor(fieldElement.attributeValue("name"), 0, textElements.size(), color);
+ changeTextColor(fieldElement.attributeValue("name"), 0, textElements.size(), markColorsType);
});
return this;
}
/**
- * 用于对字段的文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
+ * 用于对当前指向的sheet字段的文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
* 若下标大于最大段落数时,则编辑最后一段。若所传字段下不存在文本标签,则不进行标记
*
* @param field 字段id
* @param index 字段文本的段标(段落)
- * @param colors {@link MarkColorsType}类枚举
+ * @param markColorsType {@link MarkColorsType}类枚举
* @return 类本身
*/
- public FieldMark changeTextColor(String field, int index, MarkColorsType color) {
- return changeTextColor(field, index, index, color);
+ public FieldMark changeTextColor(String field, int index, MarkColorsType markColorsType) {
+ return changeTextColor(nowSheetName, field, index, index, markColorsType);
+ }
+
+ /**
+ * 用于对指定的sheet字段的文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
+ * 若下标大于最大段落数时,则编辑最后一段。若所传字段下不存在文本标签,则不进行标记
+ *
+ * @param field 字段id
+ * @param index 字段文本的段标(段落)
+ * @param markColorsType {@link MarkColorsType}类枚举
+ * @return 类本身
+ */
+ public FieldMark changeTextColor(String sheetName, String field, int index, MarkColorsType markColorsType) {
+ return changeTextColor(sheetName, field, index, index, markColorsType);
}
/**
- * 用于对字段的多段文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
+ * 用于对当前指向的sheet中字段的多段文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
* 若下标大于最大段落数时,则编辑最后一段。若所传字段下不存在文本标签,则不进行标记。
* 注意,标记的段落包括开始段落,但不包括结束段落;若开始与结束的段落数相同,则标记对应的一行
*
* @param field 字段id
* @param startIndex 字段文本的开始段标(段落)
* @param endIndex 字段文本的结束段标(段落)
- * @param color {@link MarkColorsType}类枚举
+ * @param markColorsType {@link MarkColorsType}类枚举
+ * @return 类本身
+ */
+ public FieldMark changeTextColor(String field, int startIndex, int endIndex, MarkColorsType markColorsType) {
+ return changeTextColor(nowSheetName, field, startIndex, endIndex, markColorsType);
+ }
+
+ /**
+ * 用于对指定的sheet字段的多段文本进行颜色标记,下标从0开始计算,若下标小于0时,则标记第一段;
+ * 若下标大于最大段落数时,则编辑最后一段。若所传字段下不存在文本标签,则不进行标记。
+ * 注意,标记的段落包括开始段落,但不包括结束段落;若开始与结束的段落数相同,则标记对应的一行
+ *
+ * @param field 字段id
+ * @param startIndex 字段文本的开始段标(段落)
+ * @param endIndex 字段文本的结束段标(段落)
+ * @param markColorsType {@link MarkColorsType}类枚举
* @return 类本身
*/
@SuppressWarnings("unchecked")
- public FieldMark changeTextColor(String field, int startIndex, int endIndex, MarkColorsType color) {
+ public FieldMark changeTextColor(String sheetName, String field, int startIndex, int endIndex, MarkColorsType markColorsType) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+
// 获取case下的name属性与所传参数相同的field标签
((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field))
.forEach(fieldElement -> {
@@ -1193,7 +1285,7 @@ public abstract class AbstractWriteExcel> {
bigIndex = bigIndex == smallIndex ? (bigIndex + 1) : bigIndex;
for (int index = smallIndex; index < bigIndex; index++) {
- setTextColor(textElements, index, color);
+ setTextColor(textElements, index, markColorsType);
}
}
});
@@ -1205,14 +1297,15 @@ public abstract class AbstractWriteExcel> {
*
* @param textElements 字段标签下的文本标签
* @param index 标签的位置
- * @param color 颜色
+ * @param markColorsType 颜色
* @return 颜色是否正常进行设置,即传入的index是否正常
*/
- private void setTextColor(List textElements, int index, MarkColorsType color) {
+ private void setTextColor(List textElements, int index, MarkColorsType markColorsType) {
// 判断传入的index参数:
// 若参数小于0,则标记第一个标签
// 若参数大于0且小于text最大标签数,则标记相应的标签
// 若参数大于text最大标签数,则标记最后一个标签
+ /*
Element textElement;
if (index < 0) {
textElement = textElements.get(0);
@@ -1221,7 +1314,69 @@ public abstract class AbstractWriteExcel> {
} else {
textElement = textElements.get(textElements.size() - 1);
}
- textElement.addAttribute("colors", String.valueOf(color.getColorsValue()));
+ */
+
+ Element textElement = textElements.get(getPoiIndex(textElements.size(), index));
+ textElement.addAttribute("colors", String.valueOf(markColorsType.getColorsValue()));
+ }
+
+ /**
+ * 用于向当前指向的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式,详情可
+ * 参见{@link #fieldLink(String, String, String)}
+ * @param field 字段id
+ * @param linkContent 需要链接的内容
+ * @return 类本身
+ */
+ public FieldMark fieldLink(String field, String linkContent) {
+ return fieldLink(nowSheetName, field, linkContent);
+ }
+
+ /**
+ * 用于向指定的的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式,包括:
+ *
+ * @param field 字段id
+ * @param linkContent 需要链接的内容
+ * @return 类本身
+ */
+ public FieldMark fieldLink(String sheetName, String field, String linkContent) {
+ //查找nowSheetName指向的sheet中的与uuid一致的单元格
+ Element caseElement = getElement(sheetName);
+ }
+
+ /**
+ * 用于根据链接内容,返回相应的超链接类型名称
+ * @param linkContent 标签中link属性的内容
+ * @return 超链接类型名称
+ */
+ private String getlinkText(String linkContent) {
+ String fileRegex = "(([a-zA-Z]:(\\/|\\\\))|(\\.(\\/|\\\\)))([^/:*?<>\\\"|\\\\]+(\\/|\\\\)?)+[^/:*?<>\\\"|\\\\].[^/:*?<>\\\"|\\\\]";
+ String domRegex = "'[^\\\\\\/\\?\\*\\[\\]]{1,31}'![A-Za-z]+\\d+";
+
+ //根据链接内容,与相应的正则进行判断,根据结果,返回相应的HyperlinkType类
+ if (RegexType.URL.judgeString(linkContent)) {
+ return "url=" + linkContent;
+ } else if (RegexType.EMAIL.judgeString(linkContent)) {
+ return "email=" + linkContent;
+ } else if (linkContent.matches(fileRegex)) {
+ return "file=" + linkContent;
+ } else if (linkContent.matches(domRegex)) {
+ return "dom=" + linkContent;
+ } else {
+ throw new IncorrectIndexException("无法识别的超链接:" + linkContent);
+ }
+ }
+
+ /**
+ * 用于根据指定的sheet名称获取其下相应的case标签,并返回其元素
+ * @param sheetName sheet名称
+ * @return 指定sheet名称下的case标签元素
+ */
+ private Element getElement(String sheetName) {
+ if (writeSheetNameList.contains(sheetName)) {
+ throw new IncorrectIndexException("不存在的sheet名称:" + sheetName);
+ }
+
+ return ((Element) (contentXml.selectSingleNode("//sheet[@name='" + sheetName +"']/case[@id='" + uuid + "']")));
}
}
@@ -1265,10 +1420,6 @@ public abstract class AbstractWriteExcel> {
* 用于标记是否对字段进行编号
*/
public boolean serialNumber = false;
- /**
- * 用于标记超链接内容
- */
- public String link;
/**
* 用于存储字段在用例中对应的内容
@@ -1291,14 +1442,13 @@ public abstract class AbstractWriteExcel> {
* @param numberSign 字段是否需要编号
* @param link 超链接内容
*/
- public Field(String id, String align, int index, String rowText, ArrayList datas, boolean numberSign, String link) {
+ public Field(String id, String align, int index, String rowText, ArrayList datas, boolean numberSign) {
this.id = id;
this.align = align;
this.index = index;
this.datas = datas;
this.rowText = rowText == null ? -1 : Integer.valueOf(rowText);
this.serialNumber = numberSign;
- this.link = link == null ? "" : link;
}
/**
@@ -1409,7 +1559,7 @@ public abstract class AbstractWriteExcel> {
}
// 拼接当前数据在数据有效性页中的名称(sheetName来自外层类)
- String dataCellTitle = sheetName + CreateExcelFile.SIGN + id;
+ String dataCellTitle = nowSheetName + CreateExcelFile.SIGN + id;
// 遍历第一行相应的单元格,查看是否存在与sheetName相同的
int cellindex = 0;
for (; cellindex < xr.getLastCellNum(); cellindex++) {
From 272dba9db8b6f3489b3bf2f4606feea077926290 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Sat, 22 Aug 2020 14:45:30 +0800
Subject: [PATCH 2/7] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BA=86=E5=86=99?=
=?UTF-8?q?=E5=85=A5excel=E6=96=B9=E6=B3=95=EF=BC=8C=E5=B9=B6=E5=AF=B9?=
=?UTF-8?q?=E5=85=B6=E4=BB=96=E5=AD=90=E7=B1=BB=E8=BF=9B=E8=A1=8C=E8=B0=83?=
=?UTF-8?q?=E6=95=B4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Result/测试用例.xlsx | Bin 0 -> 6213 bytes
.../work/selenium/tool/ExcelRecord.java | 29 ++++++
.../testcase/file/AbstractTestCaseWrite.java | 2 +-
.../testcase/file/BasicTestCaseWrite.java | 5 +-
.../testcase/file/CommonTestCaseWrite.java | 7 +-
.../work/testcase/file/JiraTestCaseWrite.java | 5 +-
.../auxiliary/work/testcase/templet/Case.java | 67 ++++++++----
.../testcase/file/BasicTestCaseWriteTest.java | 4 +-
.../work/testcase/用例xml文件.xml | 2 +
src/test/java/pres/readme/code/MyCase.java | 97 ++++++++++++++++++
src/test/java/pres/readme/code/MyCase.xml | 50 +++++++++
.../java/pres/readme/code/TestWriteCase.java | 13 ++-
12 files changed, 254 insertions(+), 27 deletions(-)
create mode 100644 Result/测试用例.xlsx
create mode 100644 src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
create mode 100644 src/test/java/pres/readme/code/MyCase.java
create mode 100644 src/test/java/pres/readme/code/MyCase.xml
diff --git a/Result/测试用例.xlsx b/Result/测试用例.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..58f37a87bbb10f2b5569ce0b3b492d87b36294c0
GIT binary patch
literal 6213
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
literal 0
HcmV?d00001
diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java b/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
index e1e77aa..a863d6e 100644
--- a/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
+++ b/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
@@ -47,4 +47,33 @@ public class ExcelRecord extends AbstractWriteExcel {
this.brower = brower;
}
+ /**
+ * 将xml文件中编写的文档内部超链接内容进行转换
+ * @param linkContent 链接内容
+ * @return 转换后的在poi使用的超链接代码
+ */
+ private String getDocumentLinkPath(String linkContent) {
+ String[] linkContents = linkContent.split("|");
+ int length = linkContents.length;
+
+ //获取超链接的sheet名称
+ String linkSheetName = linkContents[0];
+ //根据sheet名称以及字段id,获取该字段在sheet中的列数字下标,并将数字下标转换为英文下标
+ String linkColumnIndex = num2CharIndex(getColumnNumIndex(linkSheetName, linkContents[1]));
+
+ String linkRowIndex = "";
+ //获取当前表格的最后一行元素个数
+ int lastIndex = xw.getSheet(linkSheetName).getLastRowNum();
+ //判断当前linkContents是否存在链接行数(即第三个元素)且链接的文本为数字
+ //若符合规则,则将linkRowIndex设置为当前编写的内容
+ //若不符合规则,则将linkRowIndex设置为当前sheet的最后一行
+ if (length > 2) {
+ linkRowIndex = String.valueOf(getPoiIndex(lastIndex + 1, Integer.valueOf(linkContents[2])));
+ } else {
+ linkRowIndex = String.valueOf(lastIndex);
+ }
+
+ //返回文档链接的内容
+ return "'" + nowSheetName + "'!" + linkColumnIndex + linkRowIndex;
+ }
}
diff --git a/src/main/java/pres/auxiliary/work/testcase/file/AbstractTestCaseWrite.java b/src/main/java/pres/auxiliary/work/testcase/file/AbstractTestCaseWrite.java
index e28cede..2104ab1 100644
--- a/src/main/java/pres/auxiliary/work/testcase/file/AbstractTestCaseWrite.java
+++ b/src/main/java/pres/auxiliary/work/testcase/file/AbstractTestCaseWrite.java
@@ -71,7 +71,7 @@ public abstract class AbstractTestCaseWrite>
*/
public void relevanceCase(String field, String labelType) {
// 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.containsKey(field)) {
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
}
diff --git a/src/main/java/pres/auxiliary/work/testcase/file/BasicTestCaseWrite.java b/src/main/java/pres/auxiliary/work/testcase/file/BasicTestCaseWrite.java
index 876e2c5..ae0f59f 100644
--- a/src/main/java/pres/auxiliary/work/testcase/file/BasicTestCaseWrite.java
+++ b/src/main/java/pres/auxiliary/work/testcase/file/BasicTestCaseWrite.java
@@ -2,6 +2,8 @@ package pres.auxiliary.work.testcase.file;
import java.io.File;
+import org.dom4j.DocumentException;
+
/**
* 文件名:BasicTestCaseWrite.java
* 用途:在无相应的测试用例文件类时,可使用本类,对自定义的一个测试用例模板进行编辑
@@ -19,9 +21,10 @@ public class BasicTestCaseWrite extends AbstractTestCaseWrite文件名:CommonTestCaseWrite.java
* 用途:定义了测试用例中一些基本方法的添加,如添加步骤、预期方法等,使编码时更加直观
@@ -21,9 +23,10 @@ public abstract class CommonTestCaseWrite> exte
*
* @param configFile 测试文件模板xml配置文件类对象
* @param caseFile 测试用例文件类对象
+ * @throws DocumentException
* @throws IncorrectFileException 文件格式或路径不正确时抛出的异常
*/
- public CommonTestCaseWrite(File configFile, File caseFile) {
+ public CommonTestCaseWrite(File configFile, File caseFile) throws DocumentException {
super(configFile, caseFile);
}
@@ -117,7 +120,7 @@ public abstract class CommonTestCaseWrite> exte
//1.命中一个结果,则直接存入结果
//2.命中多个结果或未命中结果,则以“/key1/key2/key3/.../keyN”的形式拼接字符串
//获取数据有效性
- ArrayList dataList = fieldMap.get(getModuleName()).matchDataValidation(keys);
+ ArrayList dataList = fieldMap.get(nowSheetName).get(getModuleName()).matchDataValidation(keys);
//存储最终得到的模块信息
StringBuilder dataText = new StringBuilder();
if (dataList.size() == 1) {
diff --git a/src/main/java/pres/auxiliary/work/testcase/file/JiraTestCaseWrite.java b/src/main/java/pres/auxiliary/work/testcase/file/JiraTestCaseWrite.java
index c8e824a..2fe90f2 100644
--- a/src/main/java/pres/auxiliary/work/testcase/file/JiraTestCaseWrite.java
+++ b/src/main/java/pres/auxiliary/work/testcase/file/JiraTestCaseWrite.java
@@ -2,6 +2,8 @@ package pres.auxiliary.work.testcase.file;
import java.io.File;
+import org.dom4j.DocumentException;
+
import pres.auxiliary.work.testcase.templet.LabelType;
/**
@@ -24,9 +26,10 @@ public class JiraTestCaseWrite extends CommonTestCaseWrite {
*
* @param configFile 测试文件模板xml配置文件类对象
* @param caseFile 测试用例文件类对象
+ * @throws DocumentException
* @throws IncorrectFileException 文件格式或路径不正确时抛出的异常
*/
- public JiraTestCaseWrite(File configFile, File caseFile) {
+ public JiraTestCaseWrite(File configFile, File caseFile) throws DocumentException {
super(configFile, caseFile);
//TODO 添加与测试用例模板的关联,若测试用例模板字段有所改变,则在此改变关联字段
diff --git a/src/main/java/pres/auxiliary/work/testcase/templet/Case.java b/src/main/java/pres/auxiliary/work/testcase/templet/Case.java
index ca2fae9..0074b70 100644
--- a/src/main/java/pres/auxiliary/work/testcase/templet/Case.java
+++ b/src/main/java/pres/auxiliary/work/testcase/templet/Case.java
@@ -27,16 +27,16 @@ public abstract class Case {
/**
* 用于标记获取标签下所有的文本
*/
- final String ALL = "-1:getAllText";
+ protected final String ALL = "-1:getAllText";
/**
* 用于存储需要替换的词语的开始标记
*/
- final String START_SIGN = "*{";
+ protected final String START_SIGN = "*{";
/**
* 用于存储需要替换的词语的结束标记
*/
- final String END_SIGN = "}*";
+ protected final String END_SIGN = "}*";
/**
* 用于存储传入到正则表达式中的开始标记
@@ -46,17 +46,17 @@ public abstract class Case {
/**
* 用于指向测试用例xml文件的Document对象
*/
- Document configXml;
+ protected Document configXml;
/**
* 存储xml文件中其需要替换的词语
*/
- HashMap wordMap = new HashMap(16);
+ protected HashMap wordMap = new HashMap(16);
/**
* 存储字段的文本内容
*/
- HashMap> fieldTextMap = new HashMap>(16);
+ protected HashMap> fieldTextMap = new HashMap>(16);
/**
* 根据用例xml文件来构造Case类
@@ -96,7 +96,7 @@ public abstract class Case {
* @param text 需要替换的文本
* @return 替换后的文本
*/
- String replaceText(String text) {
+ protected String replaceText(String text) {
StringBuilder sb = new StringBuilder(text);
//存储替换符的位置
int index = 0;
@@ -119,11 +119,24 @@ public abstract class Case {
/**
* 用于获取用例xml中对应用例的标签内的文本,并返回替换词语后的文本
* @param caseName 用例名称
- * @param label 标签枚举
+ * @param labelType 标签枚举{@link LabelType}
* @param id 对应标签的id属性
* @return 标签中存储的文本,并进行处理
*/
- String getLabelText(String caseName, LabelType label, String id) {
+ protected String getLabelText(String caseName, LabelType labelType, String id) {
+ //返回处理替换的单词后相应的文本
+ return getLabelText(caseName, labelType.getName(), id);
+
+ }
+
+ /**
+ * 用于获取用例xml中对应用例的标签内的文本,并返回替换词语后的文本
+ * @param caseName 用例名称
+ * @param labelName 标签名称
+ * @param id 对应标签的id属性
+ * @return 标签中存储的文本,并进行处理
+ */
+ protected String getLabelText(String caseName, String labelName, String id) {
//定位case标签的名称属性名
String caseLabelNameAttribute = "name";
//定位标签中能指向调用用例的属性(id)
@@ -134,7 +147,7 @@ public abstract class Case {
//拼接xpath,规则"//case[@name='caseName']//标签名称[@id='id']"
String xpath = "//" + LabelType.CASE.getName() +
"[@" + caseLabelNameAttribute + "='" +
- caseName + "']//" + label.getName() +
+ caseName + "']//" + labelName +
"[@" + labelIdAttribute + "='" + id +"']";
//获取相应的文本内容
@@ -143,7 +156,7 @@ public abstract class Case {
//判断集合是否存在元素,若不存在元素,则抛出异常
if (textElement == null) {
- throw new LabelNotFoundException("不存在的标签:<" + label.getName() + " " + labelIdAttribute + "='" + id +"'...>");
+ throw new LabelNotFoundException("不存在的标签:<" + labelName + " " + labelIdAttribute + "='" + id +"'...>");
}
//返回处理替换的单词后相应的文本
@@ -158,7 +171,7 @@ public abstract class Case {
* @return 标签中存储的文本,并进行处理
*/
@SuppressWarnings("unchecked")
- ArrayList getAllLabelText(String caseName, LabelType label) {
+ protected ArrayList getAllLabelText(String caseName, LabelType label) {
//定位case标签的名称属性名
String caseLabelNameAttribute = "name";
//定位相应标签中存储用例内容的属性
@@ -209,7 +222,7 @@ public abstract class Case {
* 用于保存xml文件中的字段
*/
@SuppressWarnings("unchecked")
- void saveField() {
+ protected void saveField() {
//获取case标签下所有的标签,存储至fieldTextMap,以初始化所有的字段名称
((List) (configXml.getRootElement().elements("case"))).forEach(caseElement -> {
((List) caseElement.elements()).forEach(labelElement -> {
@@ -225,23 +238,41 @@ public abstract class Case {
* @param label 标签名称(枚举)
* @param text 相应内容
*/
- void addFieldText(LabelType label, String text) {
+ protected void addFieldText(LabelType label, String text) {
fieldTextMap.get(label.getName()).add(text);
}
+ /**
+ * 用于添加多行文本
+ * @param label 标签名称
+ * @param texts 相应内容
+ */
+ protected void addFieldText(String labelName, List texts) {
+ fieldTextMap.get(labelName).addAll(texts);
+ }
+
+ /**
+ * 用于添加一行文本
+ * @param label 标签名称
+ * @param text 相应内容
+ */
+ protected void addFieldText(String labelName, String text) {
+ fieldTextMap.get(labelName).add(text);
+ }
+
/**
* 用于添加多行文本
* @param label 标签名称(枚举)
* @param texts 相应内容
*/
- void addFieldText(LabelType label, List texts) {
+ protected void addFieldText(LabelType label, List texts) {
fieldTextMap.get(label.getName()).addAll(texts);
}
/**
* 用于清空字段的内容,以避免存储上一次输入的用例
*/
- void clearFieldText() {
+ protected void clearFieldText() {
fieldTextMap.forEach((key, value) -> {
fieldTextMap.get(key).clear();
});
@@ -255,7 +286,7 @@ public abstract class Case {
return fieldTextMap;
}
- /**`
+ /**
* 由于添加与参数相关的数据时需要将关联的字段(如步骤及结果)都添加至其中,
* 若后期关联字段增加,则代码量将是成倍的增加,故将关联的内容提取出来,在
* 外部进行添加,之后修改关联字段时只需修改该方法即可。若传入-1,则表示
@@ -268,7 +299,7 @@ public abstract class Case {
* @param caseName 读取的用例名称
* @param ids id参数串
*/
- 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));
diff --git a/src/test/java/pres/auxiliary/work/testcase/file/BasicTestCaseWriteTest.java b/src/test/java/pres/auxiliary/work/testcase/file/BasicTestCaseWriteTest.java
index 6242cc0..b0f3c3c 100644
--- a/src/test/java/pres/auxiliary/work/testcase/file/BasicTestCaseWriteTest.java
+++ b/src/test/java/pres/auxiliary/work/testcase/file/BasicTestCaseWriteTest.java
@@ -73,9 +73,7 @@ public class BasicTestCaseWriteTest {
public void openFolder() throws IOException {
wtc.writeFile();
System.out.println("----------------------------");
-// System.out.println("优先级:");
-// Arrays.stream(wtc.getRank()).forEach(System.out::println);
-// wtc.getCaseXml();
+ wtc.getCaseXml();
// java.awt.Desktop.getDesktop().open(wtc.getCaseXml());
java.awt.Desktop.getDesktop().open(tempFile.getParentFile());
java.awt.Desktop.getDesktop().open(tempFile);
diff --git a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
new file mode 100644
index 0000000..e6279a6
--- /dev/null
+++ b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/src/test/java/pres/readme/code/MyCase.java b/src/test/java/pres/readme/code/MyCase.java
new file mode 100644
index 0000000..70e01e2
--- /dev/null
+++ b/src/test/java/pres/readme/code/MyCase.java
@@ -0,0 +1,97 @@
+package pres.readme.code;
+
+import java.io.File;
+
+import pres.auxiliary.work.testcase.templet.Case;
+import pres.auxiliary.work.testcase.templet.LabelType;
+
+public class MyCase extends Case {
+
+ public MyCase(File configXmlFile) {
+ super(configXmlFile);
+ }
+
+ /**
+ * 用于生成app上浏览列表的测试用例
+ * @return 类本身
+ */
+ public Case myCase1() {
+ //清空字段的内容
+ clearFieldText();
+ // 存储case标签的name属性内容
+ String caseName = "myTest001";
+
+ //存储标题信息
+ addFieldText(LabelType.TITLE, getLabelText(caseName, LabelType.TITLE, "1"));
+
+ //添加步骤与预期
+ relevanceAddData(caseName, ALL, ALL);
+
+ //存储前置条件信息
+ addFieldText(LabelType.PRECONDITION, getAllLabelText(caseName, LabelType.PRECONDITION));
+
+ //存储关键词信息
+ addFieldText(LabelType.KEY, getLabelText(caseName, LabelType.KEY, "1"));
+ //存储优先级信息
+ addFieldText(LabelType.RANK, getLabelText(caseName, LabelType.RANK, "1"));
+
+ return this;
+ }
+
+ /**
+ * 用于生成web上列表的测试用例
+ * @return 类本身
+ */
+ public Case myCase2(String word) {
+ //清空字段的内容
+ clearFieldText();
+ // 存储case标签的name属性内容
+ String caseName = "myTest002";
+
+ wordMap.put("词语", word);
+ //存储标题信息
+ addFieldText(LabelType.TITLE, getLabelText(caseName, LabelType.TITLE, "1"));
+
+ //添加步骤与预期
+ relevanceAddData(caseName, ALL, ALL);
+
+ //存储前置条件信息
+ addFieldText(LabelType.PRECONDITION, getAllLabelText(caseName, LabelType.PRECONDITION));
+
+ //存储关键词信息
+ addFieldText(LabelType.KEY, getLabelText(caseName, LabelType.KEY, "1"));
+ //存储优先级信息
+ addFieldText(LabelType.RANK, getLabelText(caseName, LabelType.RANK, "1"));
+
+ return this;
+ }
+
+ /**
+ * 用于生成web上列表的测试用例
+ * @return 类本身
+ */
+ public Case myCase3() {
+ //清空字段的内容
+ clearFieldText();
+ // 存储case标签的name属性内容
+ String caseName = "myTest001";
+
+ //添加替换词语
+ wordMap.put("条件", "混合");
+ //存储标题信息
+ addFieldText(LabelType.TITLE, getLabelText(caseName, LabelType.TITLE, "1"));
+
+ //添加步骤与预期
+ relevanceAddData(caseName, ALL, ALL);
+
+ //存储前置条件信息
+ addFieldText(LabelType.PRECONDITION, getAllLabelText(caseName, LabelType.PRECONDITION));
+
+ //存储关键词信息
+ addFieldText(LabelType.KEY, getLabelText(caseName, LabelType.KEY, "1"));
+ //存储优先级信息
+ addFieldText(LabelType.RANK, getLabelText(caseName, LabelType.RANK, "1"));
+
+ return this;
+ }
+}
diff --git a/src/test/java/pres/readme/code/MyCase.xml b/src/test/java/pres/readme/code/MyCase.xml
new file mode 100644
index 0000000..e3cbfdf
--- /dev/null
+++ b/src/test/java/pres/readme/code/MyCase.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/pres/readme/code/TestWriteCase.java b/src/test/java/pres/readme/code/TestWriteCase.java
index 9fe68dc..974f34e 100644
--- a/src/test/java/pres/readme/code/TestWriteCase.java
+++ b/src/test/java/pres/readme/code/TestWriteCase.java
@@ -10,7 +10,6 @@ import org.testng.annotations.Test;
import pres.auxiliary.tool.file.excel.CreateExcelFile;
import pres.auxiliary.work.testcase.file.BasicTestCaseWrite;
-import pres.auxiliary.work.testcase.file.JiraTestCaseWrite.JiraFieldIdType;
import pres.auxiliary.work.testcase.templet.InformationCase;
import pres.auxiliary.work.testcase.templet.LabelType;
@@ -71,6 +70,7 @@ public class TestWriteCase {
@AfterClass
public void openFolder() throws IOException {
+ java.awt.Desktop.getDesktop().open(wtc.getCaseXml());
//将测试用例内容写入到文件中
wtc.writeFile();
}
@@ -79,5 +79,16 @@ public class TestWriteCase {
public void addCase() {
wtc.addCase(ic.addBasicTextboxCase("姓名", false, true, false)).end();
wtc.addCase(ic.addIdCardCase("身份证", true, false, false)).end();
+
+ wtc.setFieldValue("模块", "/测试项目/账号管理/创建账号2");
+ wtc.addCase(ic.addIdCardCase("护照号", true, false, false)).end();
+ }
+
+ @Test
+ public void myCaseTest() {
+ MyCase mc = new MyCase(new File("src/test/java/pres/readme/code/MyCase.xml"));
+ wtc.addCase(mc.myCase1()).end();
+ wtc.addCase(mc.myCase2("测试")).end();
+ wtc.addCase(mc.myCase3()).end();
}
}
From 3709379f205fcfa34b6bec65caed77d4fcd46566 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Sat, 22 Aug 2020 21:20:26 +0800
Subject: [PATCH 3/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B6=85=E9=93=BE?=
=?UTF-8?q?=E6=8E=A5=E4=BB=A5=E5=8F=8A=E7=9B=B8=E5=BA=94=E7=9A=84=E6=B5=8B?=
=?UTF-8?q?=E8=AF=95=E6=96=B9=E6=B3=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../tool/file/excel/AbstractWriteExcel.java | 198 +++++++++++-------
.../auxiliary/tool/file/excel/LinkType.java | 52 +++++
.../tool/file/excel/NoSuchTypeException.java | 38 ++++
.../tool/file/excel/WriteExcelTest.java | 47 +++++
.../tool/file/excel/WriteExcelTest.xml | 24 +++
.../testcase/file/JiraTestCaseWriteTest.java | 2 +-
6 files changed, 290 insertions(+), 71 deletions(-)
create mode 100644 src/main/java/pres/auxiliary/tool/file/excel/LinkType.java
create mode 100644 src/main/java/pres/auxiliary/tool/file/excel/NoSuchTypeException.java
create mode 100644 src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.java
create mode 100644 src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xml
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
index f2a2f44..6086c5c 100644
--- a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
+++ b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
@@ -19,6 +19,7 @@ import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFCell;
@@ -238,7 +239,7 @@ public abstract class AbstractWriteExcel> {
* @throws LabelNotFoundException 当在sheet标签中查不到相应的单元格id不存在时抛出的异常
*/
public T addContent(String field, String... contents) {
- return insertContent(field, fieldMap.get(nowSheetName).get(field).content.size(), contents);
+ return insertContent(field, -1, contents);
}
/**
@@ -284,27 +285,25 @@ public abstract class AbstractWriteExcel> {
*/
@SuppressWarnings("unchecked")
public T insertContent(String field, int index, String... contents) {
- // 判断字段是否存在,若不存在,则抛出异常
- if (!fieldMap.get(nowSheetName).containsKey(field)) {
- throw new LabelNotFoundException("当前sheet不存在的标签id:" + field);
- }
-
//若writeSheetNameList中未存储内容,则将当前的sheet名称存储到writeSheetNameList中,
//用于记录当前sheet有内容更新
- if (writeSheetNameList.isEmpty()) {
+ if (!writeSheetNameList.contains(nowSheetName)) {
writeSheetNameList.add(nowSheetName);
}
+
+ // 判断字段是否存在,若不存在,则抛出异常
+ if (!fieldMap.get(nowSheetName).containsKey(field)) {
+ throw new LabelNotFoundException("当前“" + nowSheetName + "”sheet中不存在标签id:" + field);
+ }
//若未传值或传入null,则直接结束
if (contents == null || contents.length == 0) {
return (T) this;
}
- //若传入的下标大于相应的最大段落数时,则直接结束
- if (index > fieldMap.get(nowSheetName).get(field).content.size()) {
- return (T) this;
- }
-
+ //还原下标
+ index = getPoiIndex(fieldMap.get(nowSheetName).get(field).content.size(), index);
+
if (fieldMap.get(nowSheetName).get(field).datas.size() != 0) {
//查找数据有效性,若当前字段存在数据有效性,则将数据有效性转义,若添加的字段无法转义,则存储原内容
contents = dataValidityChange(contents, fieldMap.get(nowSheetName).get(field));
@@ -405,6 +404,7 @@ public abstract class AbstractWriteExcel> {
for (Element element : ((List) (contentXml.getRootElement().elements("sheet")))) {
if (element.attributeValue("name").equals(sheetName)) {
sheetElement = element;
+ break;
}
}
@@ -415,7 +415,7 @@ public abstract class AbstractWriteExcel> {
Element caseElement = sheetElement.addElement("case").addAttribute("id", caseUuid);
// 为fieldMap中的所有key创建field标签,并记录相应的value
- fieldMap.get(nowSheetName).forEach((id, field) -> {
+ fieldMap.get(sheetName).forEach((id, field) -> {
//判断字段是否需要进行编号,若需要编号,则调用编号方法
if (field.serialNumber) {
addSerialNumber(field);
@@ -423,7 +423,7 @@ public abstract class AbstractWriteExcel> {
// 添加field标签,并设置name属性(字段名称),mark属性(备注内容)
// dom4j当属性值传入null时,则直接不会创建该属性,故此处无需做判断字段id是否在fieldMarkMap中
- Element fieldElement = caseElement.addElement("field").addAttribute("name", id);
+ Element fieldElement = caseElement.addElement("field").addAttribute("id", id).addAttribute("name", field.name);
// 判断当前是否有添加内容,若未添加内容,则创建一个value属性为空的text标签
if (field.content != null && !field.content.isEmpty()) {
@@ -515,9 +515,9 @@ public abstract class AbstractWriteExcel> {
// 遍历所有的field标签,将标签的内容写入到文件中
for (Element fieldElement : fieldElements) {
// 获取相应的Field对象
- String fieldId = fieldElement.attributeValue("name");
+ String fieldId = fieldElement.attributeValue("id");
// 获取字段的field对象
- Field field = fieldMap.get(nowSheetName).get(fieldId);
+ Field field = fieldMap.get(xs.getSheetName()).get(fieldId);
// 获取text标签
List textList = fieldElement.elements("text");
@@ -527,9 +527,6 @@ public abstract class AbstractWriteExcel> {
} else {
writeSpecificField(xs, fieldElement, fieldId, field, textList, index);
}
-
- //TODO 根据field中的link字段,添加超链接信息
-
}
}
@@ -561,6 +558,8 @@ public abstract class AbstractWriteExcel> {
field.addDataValidation(xs, index, index);
// 向单元格中添加Comment注解
addComment(xs, xc, fieldElement);
+ //向单元格中添加超链接
+ addLink(xc, fieldElement.attributeValue("link"));
// 将字段内容写入单元格
writeText(xc, textList);
@@ -610,6 +609,8 @@ public abstract class AbstractWriteExcel> {
field.addDataValidation(xs, index, index);
// 向单元格中添加Comment注解
addComment(xs, xc, fieldElement);
+ //向单元格中添加超链接
+ addLink(xc, fieldElement.attributeValue("link"));
// 存储裁剪后的text元素
ArrayList subTextList = new ArrayList();
@@ -631,10 +632,9 @@ public abstract class AbstractWriteExcel> {
}
/**
- * 用于添加超链接内容
- * @param xc
- * @param excel
- * @param linkContent
+ * 用于根据超链接内容,向单元格中添加超链接
+ * @param xc 单元格对象
+ * @param linkContent 超链接内容(形式“超链接类型=超链接内容”)
*/
private void addLink(XSSFCell xc, String linkContent) {
//若不存在链接内容,则不添加链接
@@ -642,36 +642,61 @@ public abstract class AbstractWriteExcel> {
return;
}
+ //获取分隔超链接类型与内容的符号位置
+ int splitIndex = linkContent.indexOf("=");
+ //拆分读取到的超链接文本,以此分为超链接类型与超链接内容
+ String linkTypeName = linkContent.substring(0, splitIndex);
+ String linkText = linkContent.substring(splitIndex + 1);
+
CreationHelper createHelper = xw.getCreationHelper();
XSSFHyperlink link = null;
// 添加本地文件链接
- HyperlinkType hyperlinkType = getHyperlinkType(linkContent);
+ HyperlinkType hyperlinkType = getHyperlinkType(linkTypeName);
link = (XSSFHyperlink) createHelper.createHyperlink(hyperlinkType);
- //添加超链接,若添加超链接类型为DOCUMENT,则将链接文本进行转换后写入到链接中
- link.setAddress(hyperlinkType == HyperlinkType.DOCUMENT ? getDocumentLinkPath(linkContent) : linkContent);
+ //添加超链接
+ link.setAddress(linkText);
// 在单元格上添加超链接
xc.setHyperlink(link);
// 新增单元格的样式
- CellStyleType.LINK_TEXT.getXSSFCellStyle(xc);
+// CellStyleType.LINK_TEXT.getXSSFCellStyle(xc);
+ // 获取字体信息
+ XSSFFont xf = xc.getCellStyle().getFont();
+ // 添加下划线
+ xf.setUnderline((byte) 1);
+ // 设置字体颜色为蓝色
+ xf.setColor(IndexedColors.BLUE.getIndex());
}
/**
- * 用于根据链接内容,返回相应的超链接枚举({@link HyperlinkType})
- * @param linkContent 标签中link属性的内容
+ * 用于根据链接类型名称,返回相应的超链接枚举({@link HyperlinkType})
+ * @param linkTypeName 超链接类型名称
* @return 超链接枚举
*/
- protected HyperlinkType getHyperlinkType(String linkContent) {
- //根据链接内容,与相应的正则进行判断,根据结果,返回相应的HyperlinkType类
- if (RegexType.URL.judgeString(linkContent)) {
- return HyperlinkType.URL;
- } else if (RegexType.EMAIL.judgeString(linkContent)) {
- return HyperlinkType.EMAIL;
- } else if (RegexType.FOLDER_PATH.judgeString(linkContent)) {
- return HyperlinkType.FILE;
- } else {
+ protected HyperlinkType getHyperlinkType(String linkTypeName) {
+ LinkType linkType = null;
+ for (LinkType type : LinkType.values()) {
+ if (type.getName().equals(linkTypeName)) {
+ linkType = type;
+ }
+ }
+
+ if (linkType == null) {
+ throw new NoSuchTypeException("错误的枚举名称:" + linkTypeName);
+ }
+
+ switch (linkType) {
+ case DOMCUMENT:
return HyperlinkType.DOCUMENT;
+ case EMAIL:
+ return HyperlinkType.EMAIL;
+ case FILE:
+ return HyperlinkType.FILE;
+ case URL:
+ return HyperlinkType.URL;
+ default:
+ return HyperlinkType.NONE;
}
}
@@ -813,11 +838,14 @@ public abstract class AbstractWriteExcel> {
if (!fieldMap.containsKey(sheetName)) {
fieldMap.put(sheetName, new HashMap(16));
}
- nowSheetName = sheetName;
+
+ nowSheetName = nowSheetName.isEmpty() ? sheetName : nowSheetName;
// 存储字段信息
fieldMap.get(sheetName).put(column.get(index).attributeValue("id"),
- new Field(column.get(index).attributeValue("id"), column.get(index).attributeValue("align"), index,
+ new Field(column.get(index).attributeValue("id"),
+ column.get(index).attributeValue("name"),
+ column.get(index).attributeValue("align"), index,
column.get(index).attributeValue("row_text"), datas,
Boolean.valueOf(column.get(index).attributeValue("index"))));
}
@@ -1019,13 +1047,13 @@ public abstract class AbstractWriteExcel> {
*/
protected int getPoiIndex(int length, int index) {
//判断下标的绝对值是否大于总长度,若大于总长度,则根据index的正负来判断返回值
- if (Math.abs(index) > length) {
+ if (Math.abs(index) >= length) {
return index > 0 ? length - 1 : 0;
}
//若下标绝对值小于length,则判断下标正负,正数则直接返回,负数,则通过总长度
//减去下标(由于下标是负数,故计算时用总长度加上下标)
- return index > 0 ? index : length + index;
+ return index < 0 ? length + index : index;
}
/**
@@ -1106,7 +1134,7 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public FieldMark fieldComment(String sheetName, String field, String content) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
+ Element caseElement = getCaseElement(sheetName);
// 判断字段是否存在,若不存在,则抛出异常
if (!fieldMap.get(nowSheetName).containsKey(field)) {
@@ -1114,7 +1142,7 @@ public abstract class AbstractWriteExcel> {
}
// 向包含uuid的标签下添加相应的属性
- ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field))
+ ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field))
.forEach(e -> e.addAttribute("comment", content));
return this;
@@ -1141,7 +1169,7 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public FieldMark changeFieldBackground(String sheetName, String field, MarkColorsType markColorsType) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
+ Element caseElement = getCaseElement(sheetName);
// 判断字段是否存在,若不存在,则抛出异常
if (!fieldMap.get(nowSheetName).containsKey(field)) {
@@ -1149,7 +1177,7 @@ public abstract class AbstractWriteExcel> {
}
// 向包含uuid的标签下添加相应的属性
- ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field))
+ ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field))
.forEach(e -> e.addAttribute("background", String.valueOf(markColorsType.getColorsValue())));
return this;
@@ -1174,11 +1202,11 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public FieldMark changeRowBackground(String sheetName, MarkColorsType markColorsType) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
+ Element caseElement = getCaseElement(sheetName);
// 将case下所有标签的name属性传至fieldBackground方法
((List) (caseElement.elements())).stream()
- .forEach(e -> changeFieldBackground(e.attributeValue("name"), markColorsType));
+ .forEach(e -> changeFieldBackground(e.attributeValue("id"), markColorsType));
return this;
}
@@ -1202,12 +1230,12 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public FieldMark changeRowTextColor(String sheetName, MarkColorsType markColorsType) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
+ Element caseElement = getCaseElement(sheetName);
// 将case下所有标签的name属性传至fieldBackground方法
((List) (caseElement.elements())).forEach(fieldElement -> {
List textElements = fieldElement.elements();
- changeTextColor(fieldElement.attributeValue("name"), 0, textElements.size(), markColorsType);
+ changeTextColor(fieldElement.attributeValue("id"), 0, textElements.size(), markColorsType);
});
return this;
@@ -1268,19 +1296,23 @@ public abstract class AbstractWriteExcel> {
@SuppressWarnings("unchecked")
public FieldMark changeTextColor(String sheetName, String field, int startIndex, int endIndex, MarkColorsType markColorsType) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
-
+ Element caseElement = getCaseElement(sheetName);
+
// 获取case下的name属性与所传参数相同的field标签
- ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field))
+ ((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field))
.forEach(fieldElement -> {
// 获取其下的所有field标签
List textElements = (fieldElement.elements());
// 判断是否存在text标签,若不存在,则结束
if (textElements.size() != 0) {
+ //转换下标
+ int changeStartIndex = getPoiIndex(textElements.size(), startIndex);
+ int changeEndIndex = getPoiIndex(textElements.size(), endIndex);
+
// 处理最大与最小值,保证数据不会错误
- boolean endIndexBig = startIndex < endIndex;
- int smallIndex = endIndexBig ? startIndex : endIndex;
- int bigIndex = endIndexBig ? endIndex : startIndex;
+ boolean endIndexBig = changeStartIndex < changeEndIndex;
+ int smallIndex = endIndexBig ? changeStartIndex : changeEndIndex;
+ int bigIndex = endIndexBig ? changeEndIndex : changeStartIndex;
// 判断最大最小值是否相同,相同则最大值+1
bigIndex = bigIndex == smallIndex ? (bigIndex + 1) : bigIndex;
@@ -1321,8 +1353,7 @@ public abstract class AbstractWriteExcel> {
}
/**
- * 用于向当前指向的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式,详情可
- * 参见{@link #fieldLink(String, String, String)}
+ * 用于向当前指向的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式
* @param field 字段id
* @param linkContent 需要链接的内容
* @return 类本身
@@ -1332,35 +1363,41 @@ public abstract class AbstractWriteExcel> {
}
/**
- * 用于向指定的的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式,包括:
+ * 用于向指定的的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式
*
* @param field 字段id
* @param linkContent 需要链接的内容
* @return 类本身
*/
public FieldMark fieldLink(String sheetName, String field, String linkContent) {
- //查找nowSheetName指向的sheet中的与uuid一致的单元格
- Element caseElement = getElement(sheetName);
+ //查找sheetName指向的sheet中的与uuid一致的单元格
+ Element fieldElement = getFieldElement(getCaseElement(sheetName), field);
+
+ fieldElement.addAttribute("link", judgelinkText(linkContent));
+
+ return this;
}
/**
- * 用于根据链接内容,返回相应的超链接类型名称
+ * 用于根据链接内容,返回相应的超链接类型名称,返回的形式为“超链接类型=超链接内容”
* @param linkContent 标签中link属性的内容
* @return 超链接类型名称
*/
- private String getlinkText(String linkContent) {
+ private String judgelinkText(String linkContent) {
+ //文件超链接判定规则
String fileRegex = "(([a-zA-Z]:(\\/|\\\\))|(\\.(\\/|\\\\)))([^/:*?<>\\\"|\\\\]+(\\/|\\\\)?)+[^/:*?<>\\\"|\\\\].[^/:*?<>\\\"|\\\\]";
+ //文档内超链接判定规则
String domRegex = "'[^\\\\\\/\\?\\*\\[\\]]{1,31}'![A-Za-z]+\\d+";
//根据链接内容,与相应的正则进行判断,根据结果,返回相应的HyperlinkType类
if (RegexType.URL.judgeString(linkContent)) {
- return "url=" + linkContent;
+ return LinkType.URL.getName() + "=" + linkContent;
} else if (RegexType.EMAIL.judgeString(linkContent)) {
- return "email=" + linkContent;
+ return LinkType.EMAIL.getName() + "=" + linkContent;
} else if (linkContent.matches(fileRegex)) {
- return "file=" + linkContent;
+ return LinkType.FILE.getName() + "=" + linkContent;
} else if (linkContent.matches(domRegex)) {
- return "dom=" + linkContent;
+ return LinkType.DOMCUMENT.getName() + "=" + linkContent;
} else {
throw new IncorrectIndexException("无法识别的超链接:" + linkContent);
}
@@ -1371,13 +1408,29 @@ public abstract class AbstractWriteExcel> {
* @param sheetName sheet名称
* @return 指定sheet名称下的case标签元素
*/
- private Element getElement(String sheetName) {
- if (writeSheetNameList.contains(sheetName)) {
+ private Element getCaseElement(String sheetName) {
+ if (!writeSheetNameList.contains(sheetName)) {
throw new IncorrectIndexException("不存在的sheet名称:" + sheetName);
}
return ((Element) (contentXml.selectSingleNode("//sheet[@name='" + sheetName +"']/case[@id='" + uuid + "']")));
}
+
+ /**
+ * 用于获取在指定的case标签元素中的字段元素
+ * @param caseElement case标签元素
+ * @param field case标签下的字段id
+ * @return
+ */
+ private Element getFieldElement(Element caseElement, String field) {
+ for (Object fieldElement : caseElement.elements("field")) {
+ if (((Element)fieldElement).attributeValue("id").equals(field)) {
+ return (Element)fieldElement;
+ }
+ }
+
+ throw new IncorrectIndexException("当前sheet(" + caseElement.getParent().attributeValue("name") + ")中不存在字段:" + field);
+ }
}
/**
@@ -1404,6 +1457,10 @@ public abstract class AbstractWriteExcel> {
* 用于存储字段在配置文件中的id
*/
public String id;
+ /**
+ * 用于存储字段在配置文件中的name
+ */
+ public String name;
/**
* 用于存储字段对应单元格内文本的水平对齐方式
*/
@@ -1442,8 +1499,9 @@ public abstract class AbstractWriteExcel> {
* @param numberSign 字段是否需要编号
* @param link 超链接内容
*/
- public Field(String id, String align, int index, String rowText, ArrayList datas, boolean numberSign) {
+ public Field(String id, String name, String align, int index, String rowText, ArrayList datas, boolean numberSign) {
this.id = id;
+ this.name = name;
this.align = align;
this.index = index;
this.datas = datas;
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/LinkType.java b/src/main/java/pres/auxiliary/tool/file/excel/LinkType.java
new file mode 100644
index 0000000..4e96d84
--- /dev/null
+++ b/src/main/java/pres/auxiliary/tool/file/excel/LinkType.java
@@ -0,0 +1,52 @@
+package pres.auxiliary.tool.file.excel;
+
+/**
+ * 文件名:LinkType.java
+ * 用途:
+ * 用于枚举excel中可用的超链接类型
+ *
+ * 编码时间:2020年8月22日下午4:43:35
+ * 修改时间:2020年8月22日下午4:43:35
+ * @author 彭宇琦
+ * @version Ver1.0
+ *
+ */
+public enum LinkType {
+ /**
+ * 表示文件超链接
+ */
+ FILE("file"),
+ /**
+ * 表示网页超链接
+ */
+ URL("url"),
+ /**
+ * 表示邮箱超链接
+ */
+ EMAIL("email"),
+ /**
+ * 表示文档内超链接
+ */
+ DOMCUMENT("dom");
+
+ /**
+ * 用于标记超链接名称
+ */
+ private String name;
+
+ /**
+ * 初始化枚举的名称
+ * @param name 枚举名称
+ */
+ private LinkType(String name) {
+ this.name = name;
+ }
+
+ /**
+ * 用于返回枚举的名称
+ * @return 枚举名称
+ */
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/NoSuchTypeException.java b/src/main/java/pres/auxiliary/tool/file/excel/NoSuchTypeException.java
new file mode 100644
index 0000000..4f2408e
--- /dev/null
+++ b/src/main/java/pres/auxiliary/tool/file/excel/NoSuchTypeException.java
@@ -0,0 +1,38 @@
+package pres.auxiliary.tool.file.excel;
+
+/**
+ * 文件名:NoSuchTypeException.java
+ * 用途:
+ * 当枚举类型不存在时抛出的异常
+ *
+ * 编码时间:2020年8月22日下午4:40:44
+ * 修改时间:2020年8月22日下午4:40:44
+ * @author 彭宇琦
+ * @version Ver1.0
+ *
+ */
+public class NoSuchTypeException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public NoSuchTypeException() {
+ super();
+ }
+
+ public NoSuchTypeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+
+ public NoSuchTypeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public NoSuchTypeException(String message) {
+ super(message);
+ }
+
+ public NoSuchTypeException(Throwable cause) {
+ super(cause);
+ }
+
+}
diff --git a/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.java b/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.java
new file mode 100644
index 0000000..f5db741
--- /dev/null
+++ b/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.java
@@ -0,0 +1,47 @@
+package pres.auxiliary.tool.file.excel;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.dom4j.DocumentException;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+public class WriteExcelTest {
+ final File configXml = new File("src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xml");
+ final File excelFile = new File("src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xlsx");
+
+ WriteExcel we;
+
+ @BeforeClass
+ public void init() throws DocumentException, IOException {
+ CreateExcelFile cef = new CreateExcelFile(configXml, excelFile);
+ cef.setCoverFile(true);
+ cef.create();
+
+ we = new WriteExcel(configXml, excelFile);
+ }
+
+ @AfterClass
+ public void writeFile() throws IOException {
+ we.writeFile();
+ java.awt.Desktop.getDesktop().open(excelFile.getParentFile());
+ }
+
+ @Test
+ public void mark_fieldLink() {
+ we.switchSheet("测试Sheet1")
+ .addContent("标题", "测试标题")
+ .addContent("状态", "1")
+ .switchSheet("测试Sheet2")
+ .addContent("关键用例", "2")
+ .addContent("设计者", "测试")
+ .switchSheet("测试Sheet1")
+ .addContent("步骤", "步骤1", "步骤2", "步骤3")
+ .end()
+ .fieldLink("标题", "'测试Sheet2'!A1")
+ .fieldLink("测试Sheet2", "设计者", "'测试Sheet1'!B2")
+ ;
+ }
+}
diff --git a/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xml b/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xml
new file mode 100644
index 0000000..6dee54e
--- /dev/null
+++ b/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/pres/auxiliary/work/testcase/file/JiraTestCaseWriteTest.java b/src/test/java/pres/auxiliary/work/testcase/file/JiraTestCaseWriteTest.java
index fc0b732..d1bfd88 100644
--- a/src/test/java/pres/auxiliary/work/testcase/file/JiraTestCaseWriteTest.java
+++ b/src/test/java/pres/auxiliary/work/testcase/file/JiraTestCaseWriteTest.java
@@ -56,7 +56,7 @@ public class JiraTestCaseWriteTest {
wtc.writeFile();
System.out.println("----------------------------");
java.awt.Desktop.getDesktop().open(tempFile.getParentFile());
- java.awt.Desktop.getDesktop().open(tempFile);
+// java.awt.Desktop.getDesktop().open(tempFile);
}
@BeforeMethod
From 7c7dc3f7d1fa7436ff78202b53d5d391872b30f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Sat, 29 Aug 2020 22:04:13 +0800
Subject: [PATCH 4/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ExcelRecord=E7=B1=BB?=
=?UTF-8?q?=EF=BC=8C=E4=BD=86=E6=9C=89=E6=8A=A5=E9=94=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../LogConfiguration/ExcelRecordTemplet.xml | 38 ++-
Result/测试用例.xlsx | Bin 6213 -> 7702 bytes
.../tool/file/excel/AbstractWriteExcel.java | 72 +++--
.../work/selenium/brower/AbstractBrower.java | 1 +
.../work/selenium/tool/ExcelRecord.java | 304 ++++++++++++++++--
.../tool/file/excel/WriteExcelTest.xlsx | Bin 0 -> 5347 bytes
.../work/selenium/tool/ExcelRecordTest.java | 108 +++++++
.../auxiliary/work/selenium/tool/Test.xlsx | Bin 0 -> 8813 bytes
.../tool/微信图片_20200828101657.png | Bin 0 -> 21077 bytes
9 files changed, 466 insertions(+), 57 deletions(-)
create mode 100644 src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xlsx
create mode 100644 src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java
create mode 100644 src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx
create mode 100644 src/test/java/pres/auxiliary/work/selenium/tool/微信图片_20200828101657.png
diff --git a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
index f1a8db6..96eaf4b 100644
--- a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
+++ b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
@@ -1,55 +1,61 @@
-
-
-
+
+
-
-
+
-
+
-
+
-
-
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
-
+
-
+
+
\ No newline at end of file
diff --git a/Result/测试用例.xlsx b/Result/测试用例.xlsx
index 58f37a87bbb10f2b5569ce0b3b492d87b36294c0..ee0646eb7afbac7f1b043b8698c96fd72c9a9d52 100644
GIT binary patch
delta 5463
zcmai21yodDw;y_Fko1qz-QWNUNO!lSwDiy&qcjQ#%+TH44j`p;H{#IJC80Eke4yWZ
z#(VF3d#$tXK6l--?>W29{_QUA1Yuk?MHEzG01yZS(7;HmaVd~cZk|v!Bzg!OHURFR
zCXj}7nHfye>uG6|Fuf`;s*6nt0E9S4wkwJ~g)Fv3lgS$uJ1mnV3C+3QjVU|~(wWBd
zi2`rUeAlSU8sgWL)R*j+u5tBAG2odJNy`Yos51#PH}9`K!Ii
z2JRu%&=8Cdlfn9pPGM;Dz9LzQzW20Hvajh7C2{wH*9@WzUZ(3{kDMS99w2jGV>u;%
z9^Lcp81`lPlwuKMh!#HQ&3>fbUQDRCzQQ(PEm!RoVVh-bWZ1EHFcX1=vr8LKH`0Ka6!
zD_9``09R-Lz)zE4{M#nbGUVYOHt|QHhs-Ndy(L;?McGwD^KSug{!Z$2O(Ftb~-)
zL96|6ez&8>PbBGl|Bk#t<_AL`VnXc%RN)N6l2sw^l8Op^p>f`RYZZY<=3#MPOO|0R
zlLvMIqyg#Wj$E2FkDpy$rY0L?+Ck1VT`w_j^)dUBl4sm}p*wydI_3=#bVmdjxLG#Kn%*+p>#
zG$L`^Q1B^!+2cel-*g$U`1+sSU5JXGNmhT8mdME+meIA=qB;KfSKcSwF?9ZrLKjC4
zK}N#EXbnByk6Zv)qBZWZUlgYx1y$LSTnA|po;4OL;q+csCcUbO@>-tGdb%Q25y~ji
zW6H8;jvekN!pXyo1J!{#`(kBpJeAm%MQM@28p+4`)@GH`-{|*D=XwZs1|VB!msjqO
z{GN`8V&$Mlp*UPq@tF(BT%g~oL_f6s{lv|Iss5u%$bYKD!o}3n25jZZ^>5~fY8WCF
zvD&!_#7+Y}fwlESM&ZE)^TeuI7{DO}aSHx}wiC!1x}nIz%JB-Jz%fGt9~1URm7pAu
z)w_bO_RHgDVUv5qh2IbCJ(6|dA`v#$G?V%`IfE~9pqyk1Ljk<9Pbj_yX3Q_BICrE@
zdBWOPn^AKFuW&ydpxo}h>?v83=gr=NZpQyQEAEnU-p5?}A
z!AFP!XFlkC#^FF8@!)amb)cwnM^vlP7wFJMgmyIyw+6t{^OW&Ba1e35J%y)oPXuy3
z&7OaN
z^CM~kTy(vVtvlP!7|VnX;ciY!n;hbq#JHBU1o$nyq{zxHPEQmSPOWi}Kn&jS&)x#w
zUNje1PD8eH)Pf#;EO>*aTt+v$arpSRB_T{es+&>wt
zS;Kgl7r_DW1}Wv91Vi5i6IW&pC&7Hcooo|GD1&;-
z5nv}_y#qqB?t+Y}*C8%iDz@Z;3H6-tuh_4R{1%0ISHa5{p|EbA1Y_stiwQFZPMj(v
zqTc<9u_NO32mxuvm!(Rp$-0)y9e#2H?r>rAJ1P55U5QfQE`$YhEbY@&XOqM%N&NCu
zr*mN(>#QNsmo~l$SHi2XgNk$PThCc1X|MZyb+|A4`U@BgBLsuLk&lzOOfbIvOnM-qj*%Unv4$$$nJAcrgIDZ{<5=D+
z3LRp+?sAaRZnQBAT2idP6du_>ZFca;Jj(wfkwJkb2-9ZhU}|dg#$%34fyOW4T+f;q
zFAGChd@r>Ak?4fT+p3G-{f-Q0Vf~sZ?bJn-*7V*LCiCKM04mLH4z-vKDzOwI-&QO;
zWwzug0pa|12lAvF_4+3upeTk+V}8CxLL5dSk{as5A64_Q3t0}EIhAy-g{g_>2qPv&
zcw6&mM@%C=EzMZ|HhRsHEoqB2u}1VdE-d$bYY5+u
zm%qAi=dMf%p)|GpI4=pc%70g4p3RxIP3aA;VqEWud)q{B+nS*X(_WyFiPtL7O~10f
zD{2TFZMp2pIInCO#?Ef3V9=S7XaeoCtLk1aSmHWf1?(oaNvS%r%8e1_ozcjBF^|a+
z04dm&zcd!MR7SnbGJB%acR52&ekVHNOD$tw4UNehqzD@IsJYg5YA3dB^*rse(tJc#
z=)+tRhIXmeE1VNN1W()4j?DnVWr|AoaMsImrX+zbsBe+#z(p3#4y8MucVRXfhw(MP
zoH;MZs*=5jU6;EdD9|7Kn^A^j>3y7NjjDmGt3d4xIz{MES5OE_TD@x8c7j+2-@$i@
z1{VIOka4a-ex1)L``eE2BShH{pYXBRK>`q9bwM*N;Njb%CRs>>QvluFH4F{Yr&<2hBq&Fgm#e~`Gn?@d}|Si@1Z+&dey4(
zpFk!Y7ty#C%?>16TCAfj0cTJ43q=pOz*>V7kYsM@Fo}|hOD!~STKmD2%h%_U&+T5;
z^l=KW@C$B@`G9)UvA86ZVPc_$D9ET6%%5rtqi3W%<82!i{If9!Bs307hWixoB7^Q7
zI}PW*OiF=QZqUQ!{T>yvCeUn=F#DNg&i2}bLrfkAB#mdhRnW+
z9DGOTFX-FYpqH^-0;U6K`oH7fhPj|c-;>sx5HG#C)c?33py-&?kfE2e+yp)QA+159
zEj!H00yfnxVG;@>sS=ehIhf3jO)V^UKC>MmPB$rz9A-|7ET$<6t58W(1_L=`LCM#H
z_==I;^jpeoXpL3{OZt{chRWP#C8G>aQgI-99ER5}!i*P^O1{
z6AGn4mUZvj;tGdQ8VlR2y&rBovChU_F0tTXd(eEqFU^4cl&biXT}RV%EthKi^YD7ErfJ_jW-DST
zabl@9Z`AqGhcsl%)vD>sCcP6W`U8>rjcD5&rT#;_WpB2z{Wm<@oATE8pxKwPITVJ=
zaQ=L|$*@UO`~qQ;vKkeWvu8W9rFM`pYdg3bG;ShFN9!ymC?~U_3XN!a%JbB?G#B9z
z5;(Fk?z!2k3Bl1krN6M*TwH0sl(FVxsNyX~!}8Ls9?BQZoR(Gmo7
z$0fAIBeX>#+;bPrU|eVVf|&FFNV#Gh4ERz6mT
zg)bM?gmfMecfPd&8D1i^R9^7wkNpCWk6$vg6-1c@nN)Yl>wGR)e=XX%D7&6IUB9Rl
zoiz8v7g*fJ$y`$Ww(!k8106VIzT*ZC8MX&T*%c8$644%UJ3w}3fJ==1Z<>E*=vk^;|c0f
zc*M`#&=dj$vnUlXGGJK$BU~pGxqp6^a%KBq><;lLz#!%E`_s=(whN{Z1?TTHv%AGM
zTEuE61_}pOy~sHYbMIlC)DoJmOEo}8Mc7#J)>l7~exeLRaA`*REXOt7U}$-FiH{#1
zO@-@W205lu8`2p5nHTPPzS08Og+XM=#YFFery3KzZG{)UzC{QnQA^Buf$UdABa~96
zpc<5qR^&237|Dn#mKqu)zbM8vKW&z2Ln_EBM3`lD3kx@Yv`W=_6Tf{U*pFp(2MbMu
zd6URx2R>Fxq>x@EAbnCR7&{pOa+lGt$}3($Z1CCau=15Qd3wK-+G?&!Ux?og(C)kA
z|HO0ajv99=fgcFyD9n#5+F(Ih+DNEZ|CQon$6$so{x=QzL9`_ZYw!dkY2X2Iy91G;
zI1Wj>9TA)O85WN{Q8hJk$iZx9Jhem!aHbPZO&bE7?bIir3kjd;G)U$#5SMXSm7%rO
zNmtPqh_hKcUhLE_Q&Wb|73f#=zDe1xB3d!zu1G1$GIydOm&JXsIi<8+?1IAwqK0ze!$ne@CbqxE=$;k|<
zZay{=+c$il&xBLbE-vfEkUYhD)!$Ff-!ADKo3fS#U5mGvED772Xb-4e^&4xnRp?Mr
z*odq4O$sq-7D>;y2&8<*u;Jp9q|4huxvnrwa?JfP4$~Ks1hzYtZ4v(((RAZ+22BMUQzfn@p#@b
z_DWGP^Jik)3-%9A(K%CIgNzGbs5~w8K1y%aIouTTE?*z>{Hi~cyT58VG;yB2>?rJU
zaG$ys%-j%X80x4prNm3_~gWDJN2Snvi?pcE8dPjJjr%Urp3Nrlu?hPZ2y
zR(-8#kv`c(8z@xeZ|Kp}d{L=&SYvbY3m
zy`fCQ4&AHvgR<;_M**x|1$1HTlJv%`%5r$F@|vZzDcE&+Q`*NB;}8h?VDhpxUtVsx
zcp48J#wS;7-)={^!ct_plo)N0XH^$gu!XxDbndZw7}(i~2Dh)xm`?h%cQ4>=7ivJ>
zmpVV#81Cg3=Zam__fbzKzRT|?KT>lebj9=*=}O(C=RZn;KT3HS&-C
z$y*YByqn&Z`ma_C^oryG)$J>Oa1agjMqtCuxa}GIqHd@vDb9zN!BXfp1~@FZz7b6}nmdzk>FEO9B5^4^RDf
zJah|}e^D{|pJM(3&wuad_lk@7my{cB0SFyMC1wA6!S7cl?w<>Ap!j4IKg_^EMuBXJ
z4^<$$|6^)%T>PRC(jTY&|DxpYLr?&;nn&g?mRX4d@Itl#XNq0}P|Gt?m=MS!4CD2O%}Q3+!O
zlbnBXLSPi|{)UzhM1t;kuz&I|uSGg_I7z&4AF03!`2KvCc?fQn?jU@IgiSR;Ehg1(
z*O*{R5P7@2(L3z{qtyEXW8DRpwwFFnwv*lpKeb+{q^kaAIkWh}!3rargI$}2nj4k%
z#RV$#-QhM2Ttw~Cbuf&^tvJ7QvP|G77>i=C&&*Sa_v+=shb^)QE4m4D9dF1o3@@!Og$daHrc`j^SZ&lV@YfkRrSpwSO@3rSPv8
z-pLU5@j)ZX_}mheNeQ@w3&~No)RWz$02F_M(j^3$)}Brat&>C<(|3n*%|6kK(m9%A~0YOsDKm%`a^5n7zF=Y>wFRvV58F|j)*(c
z?hntBjy6)Ar%tYm&Rn^Eux{{514EbTXoi$6F5qnvZ7Z&mXJ4
za^-jVPqdzUH#)!gqUym^GAv2m#AX#*PQ#-#gEpI(s`8y-l$b>{ur
zC*0s*Qm$qZx0zPM9RyMRB-rOZK$!}!0b79SKPjaWu%L~b>}%5MWUAU(Adu@Q8z&8|
zAG6BCsSsU;WeH^4C1(sa`YUpBX11o;>1rejfwsZI8Bs0*ysDe6xJRJzwUK;5!PG{1
zswjFEAd9AULPs~jy{r{f&mlNYmg?9_W+@BHnQ~Cbft27BsmLA^=Jb=Q1Uuc)Cvn+E
z&Xm_hKLr<}>V2e}Z$SAUqy9#n`NYdEOfGW;kfthyPaCiV}hAAxWi;6!eor;
z6%?__q&wu1)Q2lf2s69@)f!Pv4A+^Ba}#|ujLW6Cb;RVqRPjM+Hugh{sGU32`?(U+
zu$Z&sX@P^2;QBWGnB3?Vrc0YW4O=}2qe&7|lR7OX8e$RtiN32^9l|&IiJJ)IvSJr-
z5H*Ib3U4o(=DH(PWGle}Td=Qc9X(X6{)E@9mFv}FUMp$s2#N~lL$+o19Y)nQ$C!Ek
z<W2u$`Ufjl6i<
zyP#J;(JR+A2@1P|DeM7NuA8^+b}8w9_)PtQ2_v=~dyVPUe5|e6MpsAL37>nb^mnJQ
z?9&JQW-7^HVtvg$`f|NXJfoh^#OL>J;0wF`S=v3zt5jmkd>&{Qv(1+lKHG$z03#8O
ze6i9w`yq;q#!nT6b%y!4!$;)9dY?ipbHzEB`*rJA3w`DNI7MoVIVxdOR1Th3T1o^|
z=`U0U+!&5jq?|g4)n`7_2z_L9n%9ZZkJ}fV`0ToJocu-f5;%K>lYw*XHR%4RvfR@=
z*U#DP1w$0u;rwm-nlyVmA~n|N9)OqFLoWCZc`Nwqn0KCqRLZj#(^PLT-#QmZA)>3%
zBI2G-S8JA!fTB
z?-{-!0l5?(N82$?u7q|c&pILFbxP7uPil`%vmsw5v+yY4;(Wd*<0XjMl
z^)~oi{VPRQ6IC#|+GMJ*Ggtr95S#fMbSNEb=E?ifc_AYeZ?e`YK;wj%`
zrp6FQZ>U!I?*=x8$f4_dX5}o1K@S#g$p_yvTbD(%u4Njy&t$Nco8NI^DL(bAe
zwAB!6yoKFNS=F>(jtw|x2=Yk_NWL+p{xp*>ZME$u$?cv-(BKrV_M{h4pSZ%Cq8nBR
zT07Ccl&lw19@1Bu{VrNhswZ!f9p~tx&Y3E}9Xz50i{l9VVxr2*igkZS576E|Jw5!o
zwm)QBJ9IVqr`hd|t&BX5??sxxiN$w*44BF=5`uURB6Fkrc8wUTI=Ch@^HA+tn#?-|
zpYNSw4;)(OWR%b|>r2?Nqnt10kHZhVrhW3)DV~M6czxO_IvRhtrKippy4}*A_?-`n
zmtMlUWJ?Vi2zE?pNHME^X6)*Y7ioOBzvOsSb|rD1p!MyiaqL@ndj20KKpR7sw5{VZ
zPdBG#Ql+MYTSZbL
zDCEjgB%3A(^w;UD{0O81swz!Vb8?>M)pGJ8b1XHLG_wnloj=(rMfE^0=u^SkGF)J+
zHirBa`Ss>VQaUKtIFBTzIPNV2CWNLxk^pjNN(E`~a*;grz(A1ckr&RqW%9e^$RdIc
z*xC*#ejUHPdAB7i2nf_A_8-U32y|YmgK6V`2UFExIQRcXRdq}#KteRc+w1*fJ^zog
z$iAJNjbLBp#*1xBOp@*Tk*T}`_${xQZ3{5?DfDfv`t`8QO69HFx9;qejT!W;6*((6
zRAreyhR45&Oa=~#J8SCwpW8xb=!kG87wzh(?Lh0<&gpE?Q7@U-z^VJ8lVclm#F-7C
znH2ArEKz+B`HF1{@a*07?-N+_Y*BHEUzJ}r%cz;+>NQA8H(4dqNb(qtlW!$z;K>V~
zC~t|4!tmYLn^BKQjyf*`kEZai?J7ARB}{f81wKU2#m-qmTxA2rG3A!53?tfVjA>hVo@sGT`=i<(vEmEn0S;W)pahMPkI
z0;L9?xJ1;{1i7;5!k+hl+aa&b>%eg0F3R_^R`$2Kep&?$N|jK7kJW1V-CTm7?xyYq
z`q_?#n(~8Q0PQ!5s8wxp4CS`ED=1^R5Sdi!T!@XB;}Y2#MTzz98M?-bP1JK7a`PLe
z(5+~>F+MXuFMV@!B4b}dJHGQrP5L%qI*=A_7PvtwA-%;E;KrEy^+5XL;@@|KOEp&J
zEqCoW<9!xF5!a%STAgOl3N0)zoIhp(#rI%cP;D3mi1NY()#|l$dEo+TQ>bzjTu5yk
z^+B7*D4{{?9csiRAz#b-TDLXXhD;hOX1pk@?DYr8SOO7<3Jl5J^!gcCcbD1SRNhD3
z55;T;a~W@nuXI-WE}IvG$7sG8D$0?uAJ11Sv)ApYE@7x&ZGy1Z#^eTljx-{VT+}4ov#JduQB+RGi-;#X9%@6PuR+jJZ25fR9(oa!Sj)c3qblF}a%}mQ
zxC~LN)IhVnp=mHx_qi*Nk9sHs%krrqy-eq^&YO{Z0>s3=scA5>k>17yGzK*w+Z6vxGq?aS&RdA`^8RINp6;#DN%4f%Of%jsDnl!?AH(cB0|tlx90=
zlX04^+=K{EJE}>Ybaiv{BHW(drWmxmp-qM~t4{ze6SdVP(@KRHhwlXzKy(Aticx_R
z49w$Cec)-j$a8niY2)+!v2`HPwty-#??(ZXKF(b#w#7wxla8
zwiMQeXiy?OWBnEBSo2yqcYquZ{~dWRYhR<`kN1@s?(f;?;S0K*2pL?r8qSV~PRACG
z#DLFN&nnMODmd{PZl?-oi*n{t;e`r&68h!ua;%|fre1y5RsG)1fdgU506)*q&OF(=
z*qph?m!D9f$Ew?h2gc_H3VeaitB%)%KBjE5x^wuW3qAh(h4y@UkoEul?2|Dd#v8X-
z*e(SZnHSuRMlYPuc-4m$H{?Iuq3mG>E}A>l6d6Ems}ifqR9m;p?l-CHq@7*;N>Un~6k
zPDlLVQ$vc=W8?Yl^l$RQ{&4yU#ig*Z{@z9z8!IG*8aK$s{@dIbPYe80yHu(N`H;Plxq;*Qv1G*loeQ0)0uOBjFo{}1vB-1`6k
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
index 6086c5c..e2b4d43 100644
--- a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
+++ b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
@@ -54,7 +54,7 @@ import pres.auxiliary.work.testcase.templet.LabelNotFoundException;
* 编码时间:2020年2月17日下午9:36:00
*
*
- * 修改时间:2020年8月12日 下午14:29:37
+ * 修改时间:2020年8月22日 下午17:29:37
*
*
* @author 彭宇琦
@@ -180,14 +180,16 @@ public abstract class AbstractWriteExcel> {
// 将相应的sheet标签的name属性存储至sheetName中
this.nowSheetName = sheetName;
- writeSheetNameList.add(sheetName);
+ if (!writeSheetNameList.contains(sheetName)) {
+ writeSheetNameList.add(sheetName);
+ }
return (T) this;
}
/**
- * 设置字段名称的常值,通过该设置,则之后该字段将直接填入设置的值,无需再次写入字段的值
+ * 用于在当前指向的sheet中设置字段名称的常值,通过该设置,则之后该字段将直接填入设置的值,无需再次写入字段的值
*
* @param field 字段id
* @param content 相应字段的内容
@@ -195,22 +197,29 @@ public abstract class AbstractWriteExcel> {
* @throws LabelNotFoundException 当在sheet标签中查不到相应的单元格id不存在时抛出的异常
*/
public void setFieldValue(String field, String content) {
- // 为保证在写用例的时候也能生效,故将值设置进入fieldMap
- //为保证内容被重复添加,故需要清空原始内容
-// clearContent(field);
-// addContent(field, content);
-
- // 先将值设置入fieldMap中可以保证field字段是存在于fieldMap中,以减少此处再做判断
- // 将字段内容写入caseValueMap
-// constValueMap.put(field, content);
+ setFieldValue(nowSheetName, field, content);
+ }
+
+ /**
+ * 用于在指定的sheet中设置字段名称的常值,通过该设置,则之后该字段将直接填入设置的值,无需再次写入字段的值
+ *
+ * @param sheetName 指定的sheet名称
+ * @param field 字段id
+ * @param content 相应字段的内容
+ *
+ * @throws LabelNotFoundException 当在sheet标签中查不到相应的单元格id不存在时抛出的异常
+ */
+ public void setFieldValue(String sheetName, String field, String content) {
//若当前sheetName中不存在常量,则先构造HashMap
- if (!constValueMap.containsKey(nowSheetName)) {
- constValueMap.put(nowSheetName, new HashMap(16));
+ if (!constValueMap.containsKey(sheetName)) {
+ constValueMap.put(sheetName, new HashMap(16));
}
//添加常量
- constValueMap.get(nowSheetName).put(field, content);
+ constValueMap.get(sheetName).put(field, content);
}
+
+
/**
* 用于设置需要被替换的词语。添加词语时无需添加特殊字符
@@ -393,6 +402,9 @@ public abstract class AbstractWriteExcel> {
sheetElement = contentXml.getRootElement().addElement("sheet").addAttribute("name", sheetName);
}
*/
+ if (writeSheetNameList.isEmpty()) {
+ throw new IncorrectIndexException("当前不存在需要写入的sheet内容");
+ }
//生成case标签的uuid
String caseUuid = UUID.randomUUID().toString();
@@ -457,6 +469,8 @@ public abstract class AbstractWriteExcel> {
*/
});
+ //清空sheet写入记录
+ writeSheetNameList.clear();
return new FieldMark(caseUuid);
}
@@ -558,11 +572,11 @@ public abstract class AbstractWriteExcel> {
field.addDataValidation(xs, index, index);
// 向单元格中添加Comment注解
addComment(xs, xc, fieldElement);
- //向单元格中添加超链接
- addLink(xc, fieldElement.attributeValue("link"));
// 将字段内容写入单元格
writeText(xc, textList);
+ //向单元格中添加超链接
+ addLink(xc, fieldElement.attributeValue("link"));
}
/**
@@ -793,7 +807,11 @@ public abstract class AbstractWriteExcel> {
* 清空fieldMap内的存储字段信息,不清除字段
*/
private void clearFieldContent() {
- fieldMap.get(nowSheetName).forEach((key, value) -> value.clearContent());
+ fieldMap.forEach((sheetName, sheetFieldMap) -> {
+ sheetFieldMap.forEach((fieldId, field) -> {
+ field.clearContent();
+ });
+ });
}
/**
@@ -1102,7 +1120,7 @@ public abstract class AbstractWriteExcel> {
public class FieldMark {
// 用于存储case标签元素
// Element caseElement;
- String uuid;
+ protected String uuid;
/**
* 构造类,但不允许外部进行构造
@@ -1297,7 +1315,6 @@ public abstract class AbstractWriteExcel> {
public FieldMark changeTextColor(String sheetName, String field, int startIndex, int endIndex, MarkColorsType markColorsType) {
//查找nowSheetName指向的sheet中的与uuid一致的单元格
Element caseElement = getCaseElement(sheetName);
-
// 获取case下的name属性与所传参数相同的field标签
((List) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field))
.forEach(fieldElement -> {
@@ -1404,14 +1421,16 @@ public abstract class AbstractWriteExcel> {
}
/**
- * 用于根据指定的sheet名称获取其下相应的case标签,并返回其元素
+ * 用于根据指定的sheet名称获取其下相应的case标签,并返回其元素,若查不到元素,则返回null
* @param sheetName sheet名称
* @return 指定sheet名称下的case标签元素
*/
- private Element getCaseElement(String sheetName) {
+ public Element getCaseElement(String sheetName) {
+ /*
if (!writeSheetNameList.contains(sheetName)) {
- throw new IncorrectIndexException("不存在的sheet名称:" + sheetName);
+ return null;
}
+ */
return ((Element) (contentXml.selectSingleNode("//sheet[@name='" + sheetName +"']/case[@id='" + uuid + "']")));
}
@@ -1653,5 +1672,14 @@ public abstract class AbstractWriteExcel> {
DataValidation d = new XSSFDataValidationHelper(caseSheet).createValidation(constraint, regions);
caseSheet.addValidationData(d);
}
+
+ /**
+ * 根据下标返回字段中存储的内容,下标允许传入负数,表示从后向前遍历
+ * @param index 下标
+ * @return 下标对应的字段内容
+ */
+ public String getContent(int index) {
+ return content.get(getPoiIndex(content.size(), index));
+ }
}
}
diff --git a/src/main/java/pres/auxiliary/work/selenium/brower/AbstractBrower.java b/src/main/java/pres/auxiliary/work/selenium/brower/AbstractBrower.java
index a338dbf..ce0a0cd 100644
--- a/src/main/java/pres/auxiliary/work/selenium/brower/AbstractBrower.java
+++ b/src/main/java/pres/auxiliary/work/selenium/brower/AbstractBrower.java
@@ -371,6 +371,7 @@ public abstract class AbstractBrower {
pageMap.put(popuHandle, popuPage);
//将当前页面指向到弹窗页面上
nowPage = popuPage;
+ windowHandleSet.add(popuHandle);
//返回切换弹窗成功
return true;
diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java b/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
index a863d6e..9d723af 100644
--- a/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
+++ b/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java
@@ -1,12 +1,16 @@
package pres.auxiliary.work.selenium.tool;
import java.io.File;
+import java.util.ArrayList;
import org.dom4j.Document;
import org.dom4j.DocumentException;
+import org.dom4j.Element;
+import pres.auxiliary.tool.date.Time;
import pres.auxiliary.tool.file.excel.AbstractWriteExcel;
import pres.auxiliary.work.selenium.brower.AbstractBrower;
+import pres.auxiliary.work.testcase.file.MarkColorsType;
/**
* 文件名:ExcelRecord.java
@@ -21,30 +25,270 @@ import pres.auxiliary.work.selenium.brower.AbstractBrower;
*/
public class ExcelRecord extends AbstractWriteExcel {
/**
- * 存储浏览器对象
+ * 用于记录当前出现BUG的结果位置
*/
- AbstractBrower brower;
+ private ArrayList resultBugList = new ArrayList<>();
+ /**
+ * 用于指向当前记录的运行截图文件
+ */
+ private File runScreenhotFile = null;
+ /**
+ * 用于指向当前记录的异常截图文件
+ */
+ private File errorScreenhotFile = null;
+ /**
+ * 用于指向当前是否存在异常
+ */
+ boolean isError = false;
+ /**
+ * 用于记录开始执行的时间
+ */
+ private long startTime = 0L;
/**
- * 通过
- * @param configDocument
- * @param tempFile
- * @param brower
+ * 根据xml配置文件的{@link Document}类对象进行构造
+ * @param configDocument xml配置文件的{@link Document}类对象
+ * @param tempFile excel文件对象
*/
- public ExcelRecord(Document configDocument, File tempFile, AbstractBrower brower) {
+ public ExcelRecord(Document configDocument, File tempFile) {
super(configDocument, tempFile);
- this.brower = brower;
}
/**
- * @param configFile
- * @param tempFile
- * @param brower
- * @throws DocumentException
+ * 根据xml配置文件对象进行构造
+ * @param configFile xml配置文件对象
+ * @param tempFile excel文件对象
+ * @throws DocumentException 当读取xml配置文件对象失败时抛出的异常
*/
- public ExcelRecord(File configFile, File tempFile, AbstractBrower brower) throws DocumentException {
+ public ExcelRecord(File configFile, File tempFile) throws DocumentException {
super(configFile, tempFile);
- this.brower = brower;
+ }
+
+ /**
+ * 用于添加浏览器信息。该方法不能单独调用,必须配合其他
+ * 其他方法一起使用,否则在生成文件时,其写入的内容不会被填写到文件中
+ * @param brower 继承自{@link AbstractBrower}类的浏览器类对象
+ * @return 类本身
+ */
+ public ExcelRecord setBrowerInformation(AbstractBrower brower) {
+ //TODO 添加浏览器信息内容
+
+ return this;
+ }
+
+ /**
+ * 用于添加执行者。该方法不能单独调用,必须配合的其他其他方法一起使用,
+ * 否则在生成文件时,其写入的内容不会被填写到文件中
+ * @param actionName 执行者
+ * @return 类本身
+ */
+ public ExcelRecord setActionName(String actionName) {
+ switchSheet("运行记录").setFieldValue("active_person", actionName);
+
+ return this;
+ }
+
+ /**
+ * 用于添加运行类名以及运行方法名。多次调用时会清空上一次记录的内容
+ * @param className 类名
+ * @param methodName 方法名
+ * @return 类本身
+ */
+ public ExcelRecord runMethod(String className, String methodName) {
+ setFieldValue("运行记录", "class_name", className);
+ setFieldValue("运行记录", "method_name", methodName);
+ setFieldValue("错误记录", "class_name", className);
+ setFieldValue("错误记录", "method_name", methodName);
+ return this;
+ }
+
+ /**
+ * 用于记录执行开始时间,记录结束时,会写入相应的结束时间
+ */
+ public void reckonByTime() {
+ //若设定当前状态为开始记录状态,则存储当前的时间戳
+ startTime = System.currentTimeMillis();
+ }
+
+ /**
+ * 用于添加实际运行步骤,支持传入多条,每条数据将自动编号以及换行
+ *
+ * @param text 实际运行步骤
+ * @return 类本身
+ */
+ public ExcelRecord runStep(String... text) {
+ return switchSheet("运行记录").addContent("step", text);
+ }
+
+ /**
+ * 用于添加执行结果,根据传入的Bug判定来记录当前执行的Bug数量。该方法可调用多次,
+ * 将多个结果,结果将自动编号。
+ *
+ * @param text 结果
+ * @param bug 标记是否为Bug
+ * @return 类本身
+ */
+ public ExcelRecord runResult(String text, boolean bug) {
+ //若当前结果为BUG,则记录相应的编号
+ if (bug) {
+ //编号可根据相应sheet中字段的内容数量获取到当前出现BUG的内容位置
+ resultBugList.add(fieldMap.get("运行记录").get("result").content.size());
+ }
+
+ return switchSheet("运行记录").addContent("result", text);
+ }
+
+ /**
+ * 用于添加运行备注
+ *
+ * @param text 备注文本
+ * @return 类本身
+ */
+ public ExcelRecord runMark(String text) {
+ return switchSheet("运行记录").addContent("mark", text);
+ }
+
+ /**
+ * 用于添加运行时截图
+ *
+ * @param screenshotFile 截图文件对象
+ * @return 类本身
+ */
+ public ExcelRecord runScreenshot(File screenshotFile) {
+ //记录运行截图
+ runScreenhotFile = screenshotFile;
+
+ return switchSheet("运行记录")
+ .addContent("screenshot_position", screenshotFile.getPath());
+ }
+
+ /**
+ * 用于添加异常步骤的信息,传入异常类后,将会自动记录异常步骤
+ * @param exception 异常类
+ * @return 类本身
+ */
+ public ExcelRecord exception(Exception exception) {
+ isError = true;
+ return switchSheet("错误记录")
+ .addContent("error_step", fieldMap.get("运行记录").get("step").content.size() == 0 ? "" : fieldMap.get("运行记录").get("step").getContent(-1))
+ .addContent("error_class", exception.getClass().getName())
+ .addContent("error_information", exception.getMessage());
+ }
+
+ /**
+ * 用于添加异常步骤信息,并记录截图,可参见{@link #exception(Exception)}
+ * @param exception 异常类
+ * @param screenshotFile 截图文件对象
+ * @return 类本身
+ */
+ public ExcelRecord exception(Exception exception, File screenshotFile) {
+ return exception(exception)
+ .switchSheet("错误记录")
+ .addContent("screenshot_position", screenshotFile.getPath());
+ }
+
+ /**
+ * 用于添加测试用例的前置条件,支持传入多条,每条数据将自动编号以及换行
+ *
+ * @param text 前置条件
+ * @return 类本身
+ */
+ public ExcelRecord caseCondition(String... text) {
+ return switchSheet("测试用例").addContent("condition", text);
+ }
+
+ /**
+ * 用于添加测试用例的标题,不支持传入多个标题,每次调用方法后将覆盖之前传入的内容
+ * @param text 标题
+ * @return 类本身
+ */
+ public ExcelRecord caseTitle(String text) {
+ return switchSheet("测试用例")
+ .clearContent("title")
+ .addContent("title", text);
+ }
+
+ /**
+ * 用于添加测试用例的步骤,支持传入多条,每条数据将自动编号以及换行
+ * @param text 标题
+ * @return 类本身
+ */
+ public ExcelRecord caseStep(String... text) {
+ return switchSheet("测试用例")
+ .addContent("step", text);
+
+ }
+
+ /**
+ * 用于添加测试用例的预期,支持传入多条,每条数据将自动编号以及换行
+ * @param text 标题
+ * @return 类本身
+ */
+ public ExcelRecord caseExpect(String... text) {
+ return switchSheet("测试用例")
+ .addContent("expect", text);
+ }
+
+ @Override
+ public AbstractWriteExcel.FieldMark end() {
+ //记录运行状态,Bug数量,当前时间以及运行时间
+ switchSheet("运行记录")
+ .addContent("state", isError ? "2" : "1")
+ .addContent("bug_number", String.valueOf(resultBugList.size()))
+ .addContent("active_time", new Time().getFormatTime())
+ .addContent("use_time", startTime == 0L ? "" : (String.valueOf((System.currentTimeMillis() - startTime) / 1000.0) + "s"));
+
+ //获取父类的end方法,结束当前的记录
+ FieldMark fieldMark = super.end();
+
+ //判断是否存在BUG,并标记相应的结果文本为红色
+ resultBugList.forEach(bugIndex -> {
+ fieldMark.changeTextColor("result", bugIndex, MarkColorsType.RED);
+ });
+
+ //若存在异常,则将运行状态文本标记为红色,并添加相应的超链接
+ if (isError) {
+ //修改文本为红色
+ fieldMark.changeTextColor("运行记录", "state", 0, MarkColorsType.RED);
+
+ //添加运行记录与错误记录的内链关系
+ fieldMark.fieldLink("运行记录", "state", getDocumentLinkPath("错误记录|id|-1"));
+ fieldMark.fieldLink("错误记录", "method_name", getDocumentLinkPath("运行记录|method_name|-1"));
+ //若存在异常截图文件,则添加本地文件链接
+ if (errorScreenhotFile != null) {
+ fieldMark.fieldLink("错误记录", "screenshot_position", getScreenshotPath(errorScreenhotFile));
+ }
+ }
+
+ //若需要进行超链接,则添加相应的超链接
+ if (runScreenhotFile != null) {
+ fieldMark.fieldLink("运行记录", "screenshot_position", getScreenshotPath(runScreenhotFile));
+ }
+
+ //获取测试用例中相应的元素
+ Element caseElement = fieldMark.getCaseElement("测试用例");
+ Element runElement = fieldMark.getCaseElement("运行记录");
+ //若能获取到元素,则添加运行记录与测试用例之间的关联
+ if (caseElement != null && runElement != null) {
+ fieldMark.fieldLink("测试用例", "case_id", getDocumentLinkPath("运行记录|case_id|-1"));
+ fieldMark.fieldLink("运行记录", "case_id", getDocumentLinkPath("测试用例|case_id|-1"));
+ }
+
+
+ //初始化数据
+ initDta();
+ return fieldMark;
+ }
+
+ /**
+ * 用于初始化所有需要用作记录的数据
+ */
+ private void initDta() {
+ resultBugList.clear();
+ runScreenhotFile = null;
+ errorScreenhotFile = null;
+ startTime = 0L;
+ isError = false;
}
/**
@@ -53,7 +297,7 @@ public class ExcelRecord extends AbstractWriteExcel {
* @return 转换后的在poi使用的超链接代码
*/
private String getDocumentLinkPath(String linkContent) {
- String[] linkContents = linkContent.split("|");
+ String[] linkContents = linkContent.split("\\|");
int length = linkContents.length;
//获取超链接的sheet名称
@@ -63,17 +307,39 @@ public class ExcelRecord extends AbstractWriteExcel {
String linkRowIndex = "";
//获取当前表格的最后一行元素个数
- int lastIndex = xw.getSheet(linkSheetName).getLastRowNum();
+
+ int lastIndex = ((Element) (contentXml.selectSingleNode("//sheet[@name='" + linkSheetName + "']"))).elements().size();
//判断当前linkContents是否存在链接行数(即第三个元素)且链接的文本为数字
//若符合规则,则将linkRowIndex设置为当前编写的内容
//若不符合规则,则将linkRowIndex设置为当前sheet的最后一行
+ //由于存在标题行,调用getPoiIndex()方法得到的数值需要向下平移一位才能得到真实的数据
if (length > 2) {
- linkRowIndex = String.valueOf(getPoiIndex(lastIndex + 1, Integer.valueOf(linkContents[2])));
+ linkRowIndex = String.valueOf(getPoiIndex(lastIndex + 1, Integer.valueOf(linkContents[2])) + 1);
} else {
- linkRowIndex = String.valueOf(lastIndex);
+ linkRowIndex = String.valueOf(lastIndex + 1);
}
//返回文档链接的内容
- return "'" + nowSheetName + "'!" + linkColumnIndex + linkRowIndex;
+ return "'" + linkSheetName + "'!" + linkColumnIndex + linkRowIndex;
+ }
+
+ /**
+ * 用于返回需要链接的截图文件路径,若截图文件在tempFile下,则返回相应的相对路径;
+ * 若不在其下,则返回截图文件的绝对路径
+ * @param screenshotFile 截图文件对象
+ * @return 截图文件路径
+ */
+ private String getScreenshotPath(File screenshotFile) {
+ //获取excel文件以及截图文件存储路径
+ String excelFolderPath = tempFile.getParentFile().getAbsolutePath();
+ String screenhotPath = screenshotFile.getAbsolutePath();
+
+ //判断当前截图文件的路径是否在excel文件路径下,若存在其下,则返回相应的相对路径;
+ //若不存在,则返回截图文件的绝对路径
+ if (screenhotPath.indexOf(excelFolderPath) == -1) {
+ return screenhotPath;
+ } else {
+ return "." + screenhotPath.substring(excelFolderPath.length()).replaceAll("\\\\", "/");
+ }
}
}
diff --git a/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xlsx b/src/test/java/pres/auxiliary/tool/file/excel/WriteExcelTest.xlsx
new file mode 100644
index 0000000000000000000000000000000000000000..ce80e708807154e3fdd4d312c0c05b074fe5de78
GIT binary patch
literal 5347
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
literal 0
HcmV?d00001
diff --git a/src/test/java/pres/auxiliary/work/selenium/tool/微信图片_20200828101657.png b/src/test/java/pres/auxiliary/work/selenium/tool/微信图片_20200828101657.png
new file mode 100644
index 0000000000000000000000000000000000000000..296c531b406a09b2abb471fd8d48e6634def7e83
GIT binary patch
literal 21077
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
literal 0
HcmV?d00001
From 651ac630f80392e3b84ef6288dd9d083040285b5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Sat, 29 Aug 2020 22:04:34 +0800
Subject: [PATCH 5/7] =?UTF-8?q?=E6=BC=8F=E4=BC=A0=E6=96=87=E4=BB=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
index e6279a6..9f3adbe 100644
--- a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
+++ b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
@@ -1,2 +1,2 @@
-
\ No newline at end of file
+
\ No newline at end of file
From 1fc2462c44c0e3b79d4e892a8b1d244e2b5c208e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com>
Date: Mon, 31 Aug 2020 12:58:45 +0800
Subject: [PATCH 6/7] =?UTF-8?q?=E5=AE=8C=E6=88=90ExcelRecord=E7=B1=BB?=
=?UTF-8?q?=E7=9A=84=E6=94=B9=E9=80=A0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../LogConfiguration/ExcelRecordTemplet.xml | 8 ++--
.../tool/file/excel/AbstractWriteExcel.java | 41 +++++++-----------
.../work/selenium/tool/ExcelRecord.java | 5 ++-
.../work/selenium/tool/ExcelRecordTest.java | 32 ++++++++++++++
.../auxiliary/work/selenium/tool/Test.xlsx | Bin 8813 -> 8204 bytes
.../work/testcase/用例xml文件.xml | 2 +-
6 files changed, 57 insertions(+), 31 deletions(-)
diff --git a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
index 96eaf4b..6f2e203 100644
--- a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
+++ b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml
@@ -44,10 +44,10 @@
-
-
-
-
+
+
+
+
-
@@ -49,13 +40,4 @@
-
-
\ No newline at end of file
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
index 80a4d7a..6a70873 100644
--- a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
+++ b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java
@@ -231,7 +231,7 @@ public abstract class AbstractWriteExcel> {
word = WORD_SIGN + word + WORD_SIGN;
replaceWordMap.put(word, replactWord);
}
-
+
/**
* 通过传入的字段id,将对应的字段内容写入到用例最后的段落中,字段id对应xml配置文件中的单元格标签的id属性。
* 若需要使用替换的词语,则需要使用“#XX#”进行标记,如传参:
diff --git a/src/main/java/pres/auxiliary/tool/file/excel/ReplactFunction.java b/src/main/java/pres/auxiliary/tool/file/excel/ReplactFunction.java
new file mode 100644
index 0000000..40f2795
--- /dev/null
+++ b/src/main/java/pres/auxiliary/tool/file/excel/ReplactFunction.java
@@ -0,0 +1,22 @@
+package pres.auxiliary.tool.file.excel;
+
+/**
+ * 文件名:ReplactFunction.java
+ * 用途:
+ * 用于根据替换词语,设置相应的替换方法,并在读取到该词语时执行设置方法的接口
+ *
+ * 编码时间:2020年9月3日上午8:24:58
+ * 修改时间:2020年9月3日上午8:24:58
+ * @author 彭宇琦
+ * @version Ver1.0
+ *
+ */
+public interface ReplactFunction {
+ /**
+ * 根据替换的词语,以及在该位置上的原始内容,对词语所在位置内容进行替换
+ * @param replactWord 需要替换的词语
+ * @param value 原始内容
+ * @return 被替换的内容
+ */
+ public String replact(String replactWord, String value);
+}
diff --git a/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java b/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java
index 5c05639..4e266eb 100644
--- a/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/element/AbstractBy.java
@@ -22,10 +22,9 @@ import pres.auxiliary.work.selenium.xml.ReadXml;
/**
* 文件名:AbstractElement.java
* 用途:
- *
- * 对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的
+ * 对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的
* xml文件,以更简便的方式对页面元素进行获取,减少编程时的代码量。
- *
+ *
* 编码时间:2020年4月25日 下午4:18:37
* 修改时间:2020年4月25日 下午4:18:37
* @author 彭宇琦
@@ -34,7 +33,7 @@ import pres.auxiliary.work.selenium.xml.ReadXml;
*/
public abstract class AbstractBy {
/**
- * 用于存储浏览器的WebDriver对象,设为静态,保证所有的子类只使用一个WebDriver对象,以避免造成WebDriver不正确导致的Bug
+ * 用于存储浏览器的WebDriver对象
*/
WebDriver driver;
/**
@@ -70,7 +69,7 @@ public abstract class AbstractBy {
private long waitTime = 5;
/**
- * 控制是否自动切换窗体,由于通过Event类调用时会构造另一个事件类,但每个类都应共享一个开关,故需要加上static
+ * 控制是否自动切换窗体,由于通过Event类调用时会构造另一个事件类
*/
boolean isAutoSwitchIframe = true;
@@ -109,9 +108,9 @@ public abstract class AbstractBy {
}
/**
- * 用于设置事件等待时间,默认时间为5秒
+ * 用于设置元素等待时间,默认时间为5秒
*
- * @param waitTime 事件等待时间
+ * @param waitTime 元素等待时间
*/
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
diff --git a/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java
index e4a4b75..651d64e 100644
--- a/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/element/DataListBy.java
@@ -76,14 +76,6 @@ public class DataListBy extends ListBy {
super(driver);
}
- /**
- * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中
- * @param brower {@link AbstractBy}对象
- */
- public DataListBy(AbstractBy by) {
- super(by);
- }
-
/**
* 用于设置首行元素是否为标题元素
* @param isFristRowTitle 首行是否为标题元素
diff --git a/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java b/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java
index 4c93005..f93574d 100644
--- a/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/element/ListBy.java
@@ -45,14 +45,6 @@ public abstract class ListBy extends MultiBy {
super(driver);
}
- /**
- * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中
- * @param brower {@link AbstractBy}对象
- */
- public ListBy(AbstractBy by) {
- super(by);
- }
-
/**
* 返回列表名称对应的元素个数,若该列未被获取,则返回-1
* @param name 被获取的列名称
diff --git a/src/main/java/pres/auxiliary/work/selenium/element/MultiBy.java b/src/main/java/pres/auxiliary/work/selenium/element/MultiBy.java
index e00969f..c88b602 100644
--- a/src/main/java/pres/auxiliary/work/selenium/element/MultiBy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/element/MultiBy.java
@@ -39,14 +39,6 @@ public abstract class MultiBy extends AbstractBy {
super(driver);
}
- /**
- * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中
- * @param brower {@link AbstractBy}对象
- */
- public MultiBy(AbstractBy by) {
- super(by);
- }
-
/**
* 用于根据传入的元素在xml文件中的名称或者元素的定位内容,添加元素。由于该方法不指定元素的定位
* 方式,若传入的参数不是xml元素且非xpath路径或绝对css路径时,其识别效率较慢,建议在该情况下
diff --git a/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java b/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java
index c0ed031..40e0817 100644
--- a/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java
+++ b/src/main/java/pres/auxiliary/work/selenium/element/SelectBy.java
@@ -90,14 +90,6 @@ public class SelectBy extends MultiBy {
super(driver);
}
- /**
- * 通过{@link AbstractBy}对象对类进行构造,将传入的AbstractBy类中的关键参数设置到当前类对象中
- * @param brower {@link AbstractBy}对象
- */
- public SelectBy(AbstractBy by) {
- super(by);
- }
-
/**
* 设置首个选项是否为不可选择的选项
* @param fristIsEmpty 首个选项是否为不可选择
diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/Log.java b/src/main/java/pres/auxiliary/work/selenium/tool/Log_Old.java
similarity index 95%
rename from src/main/java/pres/auxiliary/work/selenium/tool/Log.java
rename to src/main/java/pres/auxiliary/work/selenium/tool/Log_Old.java
index ea13a9e..6e7b3ac 100644
--- a/src/main/java/pres/auxiliary/work/selenium/tool/Log.java
+++ b/src/main/java/pres/auxiliary/work/selenium/tool/Log_Old.java
@@ -15,7 +15,7 @@ import java.util.Date;
* @version Ver1.0
* @since JDK 12
*/
-public class Log {
+public class Log_Old {
/**
* 用于存储文件的保存路径
*/
@@ -45,7 +45,7 @@ public class Log {
* 默认位置为:C:\\AutoTestting\\TestResults\\
* 默认文件名为(不带后缀):TestResults
*/
- public Log() {
+ public Log_Old() {
}
/**
@@ -59,7 +59,7 @@ public class Log {
* @throws IncorrectDirectoryException
* 传入路径不合法时抛出的异常
*/
- public Log(String savePath) {
+ public Log_Old(String savePath) {
setSavePath(savePath);
}
@@ -73,7 +73,7 @@ public class Log {
* @throws IncorrectDirectoryException
* 传入的路径不合法或者文件名不合法时抛出的异常
*/
- public Log(String savePath, String fileName) {
+ public Log_Old(String savePath, String fileName) {
setSavePath(savePath);
setFileName(fileName);
}
diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/RecordTool.java b/src/main/java/pres/auxiliary/work/selenium/tool/RecordTool.java
index f768baa..dbee629 100644
--- a/src/main/java/pres/auxiliary/work/selenium/tool/RecordTool.java
+++ b/src/main/java/pres/auxiliary/work/selenium/tool/RecordTool.java
@@ -66,7 +66,7 @@ public class RecordTool {
/**
* Log类对象,默认构造
*/
- private static Log log = new Log(DEFAULT_FILE_PATH);
+ private static Log_Old log = new Log_Old(DEFAULT_FILE_PATH);
/**
* Record类对象,默认构造
*/
@@ -127,11 +127,11 @@ public class RecordTool {
private static boolean startRecord = false;
/**
- * 返回{@link Log}类对象
+ * 返回{@link Log_Old}类对象
*
- * @return {@link Log}类对象
+ * @return {@link Log_Old}类对象
*/
- public static Log getLog() {
+ public static Log_Old getLog() {
return log;
}
diff --git a/src/main/java/pres/auxiliary/work/selenium/tool/RunLog.java b/src/main/java/pres/auxiliary/work/selenium/tool/RunLog.java
new file mode 100644
index 0000000..ae6b2fb
--- /dev/null
+++ b/src/main/java/pres/auxiliary/work/selenium/tool/RunLog.java
@@ -0,0 +1,32 @@
+package pres.auxiliary.work.selenium.tool;
+
+import java.io.File;
+
+/**
+ * 文件名:RunLog.java
+ * 用途:
+ * 以纯文本的形式记录自动化运行过程
+ *
+ * 编码时间:2020年9月3日上午8:02:37
+ * 修改时间:2020年9月3日上午8:02:37
+ * @author 彭宇琦
+ * @version Ver1.0
+ *
+ */
+public class RunLog {
+ /**
+ * 指向日志文件类对象
+ */
+ private File logFile = null;
+
+ public RunLog() {
+ }
+
+ /**
+ * 构造对象,并指定日志存放位置
+ * @param logFile 日志文件类对象
+ */
+ public RunLog(File logFile) {
+ this.logFile = logFile;
+ }
+}
diff --git a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
index 4d7bbf5..decf45d 100644
--- a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
+++ b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml
@@ -1,2 +1,178 @@
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/test/javase/testResultFile.java b/src/test/java/test/javase/testResultFile.java
index 80bf6a8..9f12b26 100644
--- a/src/test/java/test/javase/testResultFile.java
+++ b/src/test/java/test/javase/testResultFile.java
@@ -1,10 +1,10 @@
package test.javase;
-import pres.auxiliary.work.selenium.tool.Log;
+import pres.auxiliary.work.selenium.tool.Log_Old;
public class testResultFile {
public static void main(String[] args) {
- Log trf = new Log();
+ Log_Old trf = new Log_Old();
trf.setSavePath("\\a");
}