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 @@ + + + + + + + + + + + + + + </titles> + <preconditions> + <precondition id='1' value='myTest001_前置1' /> + <precondition id='2' value='myTest001_前置2' /> + </preconditions> + <ranks> + <rank id='1' value='myTest001_优先级1' /> + </ranks> + <keys> + <key id='1' value='myTest001_关键词1' /> + </keys> + </case> + + <case name='myTest002'> + <steps> + <step id='1' value='myTest002_步骤1_*{词语}*'/> + <step id='2' value='myTest002_步骤2'/> + <step id='3' value='myTest002_步骤3'/> + </steps> + <excepts> + <except id='1' value='myTest002_预期1'/> + </excepts> + <titles> + <title id='1' value='myTest002_标题1' /> + </titles> + <preconditions> + <precondition id='1' value='myTest002_前置1' /> + <precondition id='2' value='myTest002_前置2' /> + </preconditions> + <ranks> + <rank id='1' value='myTest002_优先级1' /> + </ranks> + <keys> + <key id='1' value='myTest002_关键词1' /> + </keys> + </case> +</cases> \ 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<T extends AbstractWriteExcel<T>> { * @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<T extends AbstractWriteExcel<T>> { */ @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<T extends AbstractWriteExcel<T>> { for (Element element : ((List<Element>) (contentXml.getRootElement().elements("sheet")))) { if (element.attributeValue("name").equals(sheetName)) { sheetElement = element; + break; } } @@ -415,7 +415,7 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { 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<T extends AbstractWriteExcel<T>> { // 添加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<T extends AbstractWriteExcel<T>> { // 遍历所有的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<Element> textList = fieldElement.elements("text"); @@ -527,9 +527,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } else { writeSpecificField(xs, fieldElement, fieldId, field, textList, index); } - - //TODO 根据field中的link字段,添加超链接信息 - } } @@ -561,6 +558,8 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { 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<T extends AbstractWriteExcel<T>> { field.addDataValidation(xs, index, index); // 向单元格中添加Comment注解 addComment(xs, xc, fieldElement); + //向单元格中添加超链接 + addLink(xc, fieldElement.attributeValue("link")); // 存储裁剪后的text元素 ArrayList<Element> subTextList = new ArrayList<Element>(); @@ -631,10 +632,9 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } /** - * 用于添加超链接内容 - * @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<T extends AbstractWriteExcel<T>> { 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<T extends AbstractWriteExcel<T>> { if (!fieldMap.containsKey(sheetName)) { fieldMap.put(sheetName, new HashMap<String, Field>(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<T extends AbstractWriteExcel<T>> { */ 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<T extends AbstractWriteExcel<T>> { @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<T extends AbstractWriteExcel<T>> { } // 向包含uuid的标签下添加相应的属性 - ((List<Element>) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field)) + ((List<Element>) (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<T extends AbstractWriteExcel<T>> { @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<T extends AbstractWriteExcel<T>> { } // 向包含uuid的标签下添加相应的属性 - ((List<Element>) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field)) + ((List<Element>) (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<T extends AbstractWriteExcel<T>> { @SuppressWarnings("unchecked") public FieldMark changeRowBackground(String sheetName, MarkColorsType markColorsType) { //查找nowSheetName指向的sheet中的与uuid一致的单元格 - Element caseElement = getElement(sheetName); + Element caseElement = getCaseElement(sheetName); // 将case下所有标签的name属性传至fieldBackground方法 ((List<Element>) (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<T extends AbstractWriteExcel<T>> { @SuppressWarnings("unchecked") public FieldMark changeRowTextColor(String sheetName, MarkColorsType markColorsType) { //查找nowSheetName指向的sheet中的与uuid一致的单元格 - Element caseElement = getElement(sheetName); + Element caseElement = getCaseElement(sheetName); // 将case下所有标签的name属性传至fieldBackground方法 ((List<Element>) (caseElement.elements())).forEach(fieldElement -> { List<Element> 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<T extends AbstractWriteExcel<T>> { @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<Element>) (caseElement.elements())).stream().filter(e -> e.attributeValue("name").equals(field)) + ((List<Element>) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field)) .forEach(fieldElement -> { // 获取其下的所有field标签 List<Element> 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<T extends AbstractWriteExcel<T>> { } /** - * 用于向当前指向的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式,详情可 - * 参见{@link #fieldLink(String, String, String)} + * 用于向当前指向的sheet下的指定字段添加超链接。超链接文本可传入excel允许的超链接形式 * @param field 字段id * @param linkContent 需要链接的内容 * @return 类本身 @@ -1332,35 +1363,41 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } /** - * 用于向指定的的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<T extends AbstractWriteExcel<T>> { * @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<T extends AbstractWriteExcel<T>> { * 用于存储字段在配置文件中的id */ public String id; + /** + * 用于存储字段在配置文件中的name + */ + public String name; /** * 用于存储字段对应单元格内文本的水平对齐方式 */ @@ -1442,8 +1499,9 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { * @param numberSign 字段是否需要编号 * @param link 超链接内容 */ - public Field(String id, String align, int index, String rowText, ArrayList<String> datas, boolean numberSign) { + public Field(String id, String name, String align, int index, String rowText, ArrayList<String> 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; + +/** + * <p><b>文件名:</b>LinkType.java</p> + * <p><b>用途:</b> + * 用于枚举excel中可用的超链接类型 + * </p> + * <p><b>编码时间:</b>2020年8月22日下午4:43:35</p> + * <p><b>修改时间:</b>2020年8月22日下午4:43:35</p> + * @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; + +/** + * <p><b>文件名:</b>NoSuchTypeException.java</p> + * <p><b>用途:</b> + * 当枚举类型不存在时抛出的异常 + * </p> + * <p><b>编码时间:</b>2020年8月22日下午4:40:44</p> + * <p><b>修改时间:</b>2020年8月22日下午4:40:44</p> + * @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 @@ +<?xml version='1.0' encoding='UTF-8'?> +<templet> + <sheet name='测试Sheet1' freeze='2'> + <column id='标题' name='Name' wide='30.88' align='left'/> + <column id='步骤' name='Test Script (Step-by-Step) - Step' wide='45.75' align='left' row_text='1' index='true'/> + <column id='状态' name='Status' wide='10.00' align='center'/> + + <datas id='状态'> + <data name='Approved' /> + <data name='Draft' /> + <data name='Deprecated' /> + </datas> + </sheet> + + <sheet name='测试Sheet2' freeze='1'> + <column id='关键用例' name='Component' wide='10.00' align='center'/> + <column id='设计者' name='Owner' wide='10.00' align='center'/> + + <datas id='关键用例'> + <data name='是' /> + <data name='否' /> + </datas> + </sheet> +</templet> \ 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 @@ <?xml version="1.0" encoding="UTF-8"?> <templet> - <sheet name="测试用例" freeze="3"> - <column id="case_id" name="用例编号" wide="17" align="center" link="运行记录|case_id"/> - <column id="module" name="所属模块" wide="25" align="center"/> + <sheet name="测试用例" freeze="2"> + <column id="case_id" name="用例编号" wide="17" align="center"/> <column id="title" name="用例标题" wide="30" align="left"/> <column id="step" name="步骤" wide="45" align="left"/> <column id="expect" name="预期" wide="45" align="left"/> - <column id="condition" name="前置条件" wide="30" align="left"/> - <column id="flow" name="所属流程" wide="13" align="center"/> + <column id="condition" name="前置条件" wide="30" align="left" index='true'/> </sheet> - <sheet name="运行记录" freeze="6" > + <sheet name="运行记录" freeze="5" > <column id="id" name="序号" wide="8" align="center"/> - <column id="case_id" name="用例编号" wide="17" align="center" link="测试用例|case_id"/> + <column id="case_id" name="用例编号" wide="17" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> <column id="method_name" name="方法名" wide="15" align="left"/> - <column id="state" name="执行状态" wide="10" align="center" link="错误记录|id"/> - <column id="step" name="执行步骤" wide="25" align="left"/> - <column id="result" name="执行结果" wide="25" align="left"/> - <column id="condition" name="前置条件" wide="25" align="left"/> - <column id="mark" name="备注" wide="25" align="left"/> + <column id="state" name="执行状态" wide="10" align="center"/> + <column id="step" name="执行步骤" wide="25" align="left" index='true'/> + <column id="result" name="执行结果" wide="25" align="left" index='true'/> <column id="bug_number" name="Bug数量" wide="10" align="center"/> - <column id="screenshot_position" name="截图位置" wide="25" align="center" link="运行记录截图|id"/> - <column id="use_time" name="执行耗时(s)" wide="15" align="center"/> + <column id="screenshot_position" name="截图位置" wide="25" align="center"/> + <column id="use_time" name="执行耗时" wide="15" align="center"/> <column id="active_person" name="执行者" wide="20" align="center"/> <column id="active_time" name="执行时间" wide="12" align="center"/> <column id="brower" name="浏览器" wide="12" align="center"/> <column id="version" name="版本" wide="12" align="center"/> <column id="system" name="操作系统" wide="12" align="center"/> + <column id="mark" name="备注" wide="25" align="left"/> + + <datas id='state'> + <data name='正常' /> + <data name='异常' /> + </datas> </sheet> + <!-- <sheet name="运行记录截图" freeze="0"> <column id="id" name="序号" wide="8" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> <column id="method_name" name="方法名" wide="15" align="left" link="运行记录|id"/> <column id="screenshot" name="截图" wide="25" align="left" link="本地"/> </sheet> + --> <sheet name="错误记录" freeze="4"> <column id="id" name="序号" wide="8" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> - <column id="method_name" name="方法名" wide="15" align="left" link="运行记录|id"/> + <column id="method_name" name="方法名" wide="15" align="left"/> <column id="error_step" name="错误步骤" wide="25" align="left"/> <column id="error_class" name="异常类" wide="25" align="left"/> <column id="error_information" name="异常信息" wide="25" align="left"/> - <column id="screenshot_position" name="截图位置" wide="25" align="left" link="错误记录截图|id"/> + <column id="screenshot_position" name="截图位置" wide="25" align="left"/> </sheet> + <!-- <sheet name="错误记录截图" freeze="0"> <column id="id" name="序号" wide="8" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> <column id="method_name" name="方法名" wide="15" align="left" link="错误记录|id"/> <column id="screenshot" name="截图" wide="25" align="left" link="本地"/> </sheet> + --> </templet> \ No newline at end of file diff --git a/Result/测试用例.xlsx b/Result/测试用例.xlsx index 58f37a87bbb10f2b5569ce0b3b492d87b36294c0..ee0646eb7afbac7f1b043b8698c96fd72c9a9d52 100644 GIT binary patch delta 5463 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 delta 3906 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 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; * <b>编码时间:</b>2020年2月17日下午9:36:00 * </p> * <p> - * <b>修改时间:</b>2020年8月12日 下午14:29:37 + * <b>修改时间:</b>2020年8月22日 下午17:29:37 * </p> * * @author 彭宇琦 @@ -180,14 +180,16 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { // 将相应的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<T extends AbstractWriteExcel<T>> { * @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<String, String>(16)); + if (!constValueMap.containsKey(sheetName)) { + constValueMap.put(sheetName, new HashMap<String, String>(16)); } //添加常量 - constValueMap.get(nowSheetName).put(field, content); + constValueMap.get(sheetName).put(field, content); } + + /** * 用于设置需要被替换的词语。添加词语时无需添加特殊字符 @@ -393,6 +402,9 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { 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<T extends AbstractWriteExcel<T>> { */ }); + //清空sheet写入记录 + writeSheetNameList.clear(); return new FieldMark(caseUuid); } @@ -558,11 +572,11 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { 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<T extends AbstractWriteExcel<T>> { * 清空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<T extends AbstractWriteExcel<T>> { public class FieldMark { // 用于存储case标签元素 // Element caseElement; - String uuid; + protected String uuid; /** * 构造类,但不允许外部进行构造 @@ -1297,7 +1315,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { public FieldMark changeTextColor(String sheetName, String field, int startIndex, int endIndex, MarkColorsType markColorsType) { //查找nowSheetName指向的sheet中的与uuid一致的单元格 Element caseElement = getCaseElement(sheetName); - // 获取case下的name属性与所传参数相同的field标签 ((List<Element>) (caseElement.elements())).stream().filter(e -> e.attributeValue("id").equals(field)) .forEach(fieldElement -> { @@ -1404,14 +1421,16 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } /** - * 用于根据指定的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<T extends AbstractWriteExcel<T>> { 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; /** * <p><b>文件名:</b>ExcelRecord.java</p> @@ -21,30 +25,270 @@ import pres.auxiliary.work.selenium.brower.AbstractBrower; */ public class ExcelRecord extends AbstractWriteExcel<ExcelRecord> { /** - * 存储浏览器对象 + * 用于记录当前出现BUG的结果位置 */ - AbstractBrower brower; + private ArrayList<Integer> 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<ExcelRecord>.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<ExcelRecord> { * @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<ExcelRecord> { 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 zcmbVQXIPWl(hWU;N)QmFDjk*HQBgt{5;_P-Zy}V>rAY}8x>O4S(iNl^=|P$l0fo?{ z_aYqy(I9XW@BOYE?>YYXCeNGlBs1CXthHy)8cj7KVp;$Y2n384uxJ5J871z$nVXHH zyPyF6xj3=q4v{bjWyaNuPIV%owjYlMq9cdM7?Q@O%2L%;l%|@{Ez#AEaxDu&qBAGL z-CnoCRna;E&vSx32a(yZvF{(5yrpGJwr<n4th&srkV19M-%Q93hH4wUo7K^JL>(P0 z$2sL-vT>V0tu4}W(<6=O4!?UT%{a9mCbb$p{GEsBeahPGnZ*#}5E;uY)ib?G$Fnz@ zMB*TCM>_Zh5a7D?#yqlWL~!;sYcusAQ?D`q2B~U|ly&YGdov<pl#0sEkKlwhyZiG7 zG0qoauGwKzG5g8`!Ne>S0a}8gdt+=L9}sG)kpZ1WfND#)d%r^n0BHVWc4%<FFqTI+ zd)PR8nCbes*tnYrcsn`v=}y22g+WJ;xJqp#;aSP^Yx06|#hQl%_96{Ty|L<5*n{*U ztfoT?J5r-AO>`ygBDiDlwfI{KcK9}2qKLEzz=Ot=6pwZO$ZNDC;hswtnwIO62y&FU z_(77OEYm1ld|jJ@DlKQDnWD%apsccxLl^n5d`Ye=3>F+m8gg9#tv0KjQbC#;laWcS zmK4>w`QUL$3a|yncmD1C)tBcKdeY75TK1SXJerx<%jSI`S0=oGiX9p*QrCLzUisy; zC=}0{4fqej$lvwk<t0*7ydu;?skA>8+i-iYpkCUVc!}q8jOHSzN%{hsEqad{D$?6t z$xK!M79_{J0Z0_5^I}K(Y9yErZi5`!0zm>#Ih=YE_!a>--MY#9jSRD<gbxJS=rg7T z1y(Xxut#QJZ$>nlp$rnOJh-Ht52U?MrXWoOcoa}cC=o>h0Dzz5Pbh$JC|Dz`G~Ey` z?t&IBE_eta4_hc&g+L11$P<toqQ)1LAeMIt$>Y~g1^hHZ`V69?|7j&P$v5rd@~&<T zR<TjohCcsMLwy2aH)>#@@=@Gjp3FNaLK3cW+0ruHFqv#g|9$T+ar|b?^kRLl?qfbq zL~Z+Cs1W4+y!6K>%9bA``v_cYa;ZD71O#gr%67apY*Pdu4AAB>I2(|hpph9N$2c01 z0VSM6E+^rZTZ_B?nO4-NZ^#PaW`n;Yr+5>!HX&Nn$(^nTsktmxsA~D-;7lo(Y;XER zD`Q7lmF%fww0%0=Py^?-J1cY=?l(k)1+e)#z<b@Is2S|_5aW!uSiQzbb3kEQmSv=H ze`HV%gp1|LNZYhAne11P=I5u)d4;a@ISZl0W5E|LYlN!K7493gd+hVOf}0{QsK|YK z28#ek@^*3dPFl9x<t0XA(1#WmcvZ~-XSqpR-IM}80!_mM$(F4z$7Px2yE1<%Pphk< z=J;^GhU&{_L&S?WYRwQ&efLjt3Yxs+-Z$!WyYGM2H8o-Ls^x>piPm>VMH5|>Hr^e^ z=CQw7=9wEE!!C=^VF<=&X4EG?-%Ge9E}4N(;x0`@GAWJ~<+$sglSqq8qPL@<JIun( z##+b2&EDD09iPYIBn^BXo41iOmlt!x1supkayR2+S@c$a0Lpu+Tc5RarUycOK`kc4 zJR7{(?8phZy%!m_fs-{tCig$qI|xE%w$VRKTRFTwU2_aMM=fGL6l^O%MUW+1NLKZ! zImc+2w>7b$&O)sq=mYyJW|$#JK};%AMVi2tny@$v6U?9YO#qBRB!GID7ed$6Ln1*} zS)#ZT?}6?;;Row}RMMAy69Q(|Tpbs2aa!71i2tZkClR#}IvlaJ^__i|!qF$nW#QXo z#Hf>bkT(ReL#v;lJ}5#dofG=XV}3UId;%(|bZcg(C7KG(I5@H0y`)!f9p~O6lly#` zE||#yaz$ZgvJ;N>FG#Y9DZOQfZmBwuz;2e%eGRu4Yw|Nu1ncBl37^n~V>twGlhy2} zUAt+TPNS!!hwKR1T3um%FWH{=PTV~y?#b9;WeQ9Y1$W4*t}vj#um=9RHhkI69=a^+ z)0lE|U$iENiv?3UdPIhYOmoPW!W9SCI?<mXJNqBVJbWB&eqyz0pyoUwL_0~}#RA-- z8H1-XhUH$PkXn@y=;!CZsjBdeT16(oElj{KZaTBZetSS!t9nV%LM&Q|ph|d#>CMH5 zTyRGo$zs|?f|w<vJP)7OnZ&v!lqIi{1ICI34fePjyp!&ZlGhdzFw3DT_=?jVWR(*7 z9O8RTKatWl>A*Qs+D3E}oX(WB`X<t9HQv3aoam}psj#_dB%|hrJJs?i8EsSxhN%rp zV7DvUWfRD_L7$gh1V+J3t$GCfw7^bQU3D<SVLR~*<MdULZbkapfL8}Hy{aWuyR!m& z7jBgUs1z(_c6@1%j}|6MGiLl!&^c04<EW98soucYA1OQa<VThXU13t3D(Xb>TxZ?S z#TZ%1qkIR&<F)gKUCgm{qJt!&2Q?^94y8A<9mY-+G5zx112>bo2=9aww-t_;LM4xz z;VV_`*|SBMD00C%yE7#3mM^uZf0!y=iu5v06#7!PGp5=Y{UFl7l2^V1)v+EojQo1n zYyX-F=5hGh_`YXK9uAu%hvB<Llb;3M43T`MeB|#EjF^r?zZ`e00E4oQDSLMPV{R~x zIA(h0Fu;0NQlehM);4J&=+x|j106BXn~FMY#~}qtXO;LwD%>r<q>*L3tPFYLC6p0r zFZFc0O}C`=mR|(Q%=|9PiLqVa&oW6HBT~DEqf0#1pXh@762HUmBitM;5eNtT=8n~Z zXtWA3G^KuHgSY9`6EK=oQ$LD#5$4V`&>p#8WZ|G{Ec=jEyn{n>dwM83(0<qMWAGrg zWov;CR@Q8Dz2=Ew)N-cS6ZU53sTQCD=SBJjz|6V&PP<wbR@QHn1>78bJYAo|&be6j z4sj?blUwVKF42ajw`<!B-OcY%(4f<NK?6w2%bk;Y$(eI+Ha6tt*WGy6UXIl+*yCU! zCK?hx@#<peH{FGunz2}L45Q13bp0T!XYgjuz36V1@UUZ!3!s6n9qBWxyv@)S4!Zez zcOP~+QJ~B5_r3k5HF`+_rFRS0nqPH3V<<MfNjcTJ!UoC7w$~GjW$9bv2n^^kWBoEL zA8=xnkgjXp=ebnD6Y`YOe00Q|DJxWz)T>mf50Im)B)0j4)oU=dYfgmD@WIEW0)pWz z)WiIvhBEAY&bVUVKHNZjl!xx*sBQA7jq#Snlj|1NhgrGzVBgN-w=z_w*W3(;O~)TQ zBgTJY^Y7O2G(tbyNOV#;v`q+fJMe9Nx|FJMsOFRaowflloB7xiDY&I^Q%?MwQi~uZ zI47#rqXHVR&0jMea0V@9kuBg&qNjztjX-Yt7tZeQcpLzbcl`<vXSG@)h$s567ybIa zQ`QM2cAe3nV0QOUPK;@j)1hX^Hrj(3#a8U#Hbcw##>t+B(>)&DL3}zJ#mK4}x`+@c ze+8kNOxA<B<iY%|*+xc=V<o0%FGOo8mz{2ZFxYS-B=foXqA6moymP|9Uu$JAn(fF> zMcFOlhv9Q&&-Fw^%e`JV*%!wLPlx?`=QXSr7tcx9;ZxOnWxi(tmk8(|s~*EI8oR@6 zY&_g?XBO^77|&<49t1In<1@!D+YJW{RLmaZIF)QYE(1{~v^TOyLl4;($+(tHc`dY4 zhe~aAq%*n93F`egV>)4&{21;skNLLXld*ENb0{I(#4l~6S@1Of{N(m`hJh<IH2M&l zAK2mVm6v6q8M2X2!0&bC3Y5$>3yA5BMwOqxtUx|i*jIpDt?drG7KtiO^L_O=S-nWB z8{K?xfKDu<c)1(;s7fSC1#_c?=P0KV=x6U(J{lvSXBR70cToo_3gICiaf1qrOiu!Z zMGxp*)`;vOSE5v2j3G^1MOq}m4qB$=_F2N(&tOtLdEUxbW2*Aa`tQZ@u8^~mFibsk zc<+HEN(yeUwZd3TR;+bQVW})@zZw}dtcQc%J1GfpJ?l^Ft!p~pvoiFQ@WJ9Y(UwO? zid>?K&H0=)UsL<&c+nO#CRJGtkktbeS(|*|tq1_O6whms@7?4ERhK<I<mBmZC`m^6 zk_B>5FlFxuXE!0v*T#0bTa4$XQA03yqqq{ep&;RCnuxn&wU?zSp!5Z7ew0?@m!K@{ ztCz6r5ef34EDHVXH#8k>Li8nEDjbRqnOe_@Zh(<zmryU(18$9%u*kwPP$R2l4m8d+ z7po+Qcoy%+l1{{COLTQzR5Zy6iM_<6{tak5WKKFE44qu3P3e6tWp__!Oyc?waJr4S zq?FulCu~G}$9DOVmyO{YFt!9$vY?(K8{lB5UO~QM>GMui+|N5i_s-=`>_Z}ER@hlx z+e>}YpI#OovK4-q(Ko~CtXoCXfm35Q$Id>SB|ATAX^AlTo^d1cIF5&jtY4KxibJ~4 zc1nDny)uY+yEq^KyMGkm2&dlIe7faE2Xwsd)#o6RCm5L~k{^=lETprk&=nShNnvS> zB3$-qm=n6iPXU{{QRx7zE*EFtoKeCu;aUF-;p|_AD-LkdKNatPV7&;Q_324{&O<_= z&TW;(klj3<5mjt?{vB=4X#GpUy087yrmPe1u77;IIpydR_T1+jwDJ7BFvIoBQ9(3M zthrN85XTGZp9`%7y9tVDjOfHnxRQfjdGPBR_s6kS3z`iSe*RwR-|w{|1JKaSyeD^k zyN}DNWG!>WIqxhlPV!8+#}zoGh+gn!QAArCCf+N1PN~?_c;RM#f5KfDg>Sm)v~}_$ zpQ0m9bC>9+p(9jA+u+aD0x%?T8y(2h$2G|K3?()bJ$jT5yRH%WWpbgiV@)uVcXzxo zq+=#1nPkd3nRz>wHh}TKHG!Dw5<%T+-w%?GQOB>ZV*(GSI(8BK1zB@`pSJgQNRhO= zD;#eyn73CyDN4EC@ePPMfNz%#+G!n@WKM4dCt9duI2jaU7dr@8<=XN>A|>1^B9o5T z!eguFL8WyoHqQIE9e2VYV3*i)yOkMpt`~;p2IYO8Rm#Uh=~Bz*{k2>r41^Z@`W;cW zT8XCD#6DrEHgqeG@Am<1DOdcr_w`k%yi5hFQ1V`Jq(!vwl?%cN_4BgMC*5(|8n@m& zKvU)KEh@s82~um*9Qh<0!wx2^!O|kmz^x^CY^9`;)k=K2HfD}Wi0Ax$A^po<laUMy zUeNJ=>*Eja%<w!>;u#K{#~mc8|DWn8isy+_A_Ng4bmsPU(pR?ZN#)F$!k||Zx=!J$ zI<GgMBZKonIh<DyzpKIM6ipBk0Rd2EOdn!2k%pIF(^f3f^3LrGcPR|*_SW4G%Cb{` z91E~$vUn1iM>xgH<irXeJrgz&>vv_bpu*^1(Pfd8&=Vg-6PiARnDlVFHkz~0CobFb z$;3OeYiZheq!wk^B`<yI3ZP{00MSTdgS<VujZ+3bW^J%FFewM}YJ=Yf8dY}A(J4$Z z_!axm`khcp-q4^sr!W?E6EcT%0!N~Uk>`6H4)>Ek=y+9xL{aW~a6cy4T_v}DU@EhV zQ3VK=cv$d9B2r&Wi=ACvdc;@6)$KIcn`%pdu16Y{Wj!C=d9TNx%S|Rmdc6S)lYW^C z7R$V6%Om+U_5lWLqZD=C)AWdeX+sdbwe+Jj`Q)d%UcJ4fejNuuz|WJMfRGmOYX)?B z{(+wX{nbuQgf!Lu>UdhR<HsYvj1~7+e={ukJ-}&+j92!*EEl)V-*x`)-lw%8UPk{i zPaMtu>-~SC`gix!It4Eve_1{8-^<D0Bb;ts@p|T$IpOLdUXcD*-Tdx)y0gOfw!bV5 z_&=TQ@6M-t4Se(U%cLlNI{!l}_IsSu)f-=<f0-4I2mfie|EEv+J<935{nsdl=l(Xz p&$|D6l+y(LYm{IdGyY~RKdXYK8VN4b001TK(SxH5;d%V0e*t#yyN3V( literal 0 HcmV?d00001 diff --git a/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java b/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java new file mode 100644 index 0000000..8daaff0 --- /dev/null +++ b/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java @@ -0,0 +1,108 @@ +package pres.auxiliary.work.selenium.tool; + +import java.awt.Desktop; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; + +import org.dom4j.DocumentException; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.Test; + +import pres.auxiliary.tool.file.excel.CreateExcelFile; + +public class ExcelRecordTest { + CreateExcelFile cef; + ExcelRecord er; + + final File configXml = new File("ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml"); + final File tempFile = new File("src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx"); + final File imageFile = new File("src/test/java/pres/auxiliary/work/selenium/tool/微信图片_20200828101657.png"); + + @BeforeTest + public void init() throws DocumentException, IOException { + cef = new CreateExcelFile(configXml, tempFile); + cef.setCoverFile(true); + cef.create(); + + er = new ExcelRecord(configXml, tempFile); + } + + @AfterTest + public void writeFile() throws IOException { + er.writeFile(); + Desktop.getDesktop().open(tempFile.getParentFile()); + Desktop.getDesktop().open(er.getCaseXml()); + } + + @BeforeClass + public void recordBaseInfo() { + er.setActionName("yuqipeng_d"); + } + + @BeforeMethod + public void startRecord(Method method) { + er.runMethod(this.getClass().getName(), method.getName()); + er.reckonByTime(); + } + + @AfterMethod + public void endRecord() { + er.end(); + } + + @Test + public void runStepTest() { + er.runStep("第一步", "第二步", "第三步"); + } + + @Test + public void runResultTest() { + er.runResult("结果1,不是BUG", false); + er.runResult("结果2,是BUG", true); + } + + @Test + public void runMarkTest() { + er.runMark("这是备注信息"); + } + + @Test + public void runScreenshotTest() throws IOException { + er.runScreenshot(imageFile); + } + + @Test + public void exceptionTest_NotFile() { + er.exception(new NullPointerException("抛出了NullPointerException异常")); + } + + @Test + public void exceptionTest_HasFile() { + er.exception(new RecordStateException("抛出了RecordStateException异常"), imageFile); + } + + @Test + public void caseConditionTest() { + er.caseCondition("测试用例前置条件1", "测试用例前置条件2"); + } + + @Test + public void caseTitleTest() { + er.caseTitle("测试用例标题"); + } + + @Test + public void caseStepTest() { + er.caseStep("测试用例步骤1", "测试用例步骤2"); + } + + @Test + public void caseExpectTest() { + er.caseExpect("测试用例预期1", "测试用例预期2"); + } +} diff --git a/src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx b/src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1ec4c1aa01271881a755b2d0306da04a702f1b3d GIT binary patch literal 8813 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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 @@ <?xml version="1.0" encoding="UTF-8"?> -<cases><sheet name="测试用例"><case id="9faf569f-9de4-46db-ad85-eb667586d3dc"><field name="前置条件"><text value="1.myTest001_前置1"/><text value="2.myTest001_前置2"/></field><field name="步骤"><text value="1.myTest001_步骤1"/><text value="2.myTest001_步骤2"/></field><field name="优先级"><text value="myTest001_优先级1"/></field><field name="状态"><text value="Approved"/></field><field name="项目"><text value=""/></field><field name="目的"><text value="验证创建账号界面各个控件输入是否有效"/></field><field name="预期"><text value="1.myTest001_预期1"/><text value="2.myTest001_预期2"/></field><field name="关联需求"><text value="TEST-1"/></field><field name="关键用例"><text value=""/></field><field name="模块"><text value="/测试项目/账号管理/创建账号"/></field><field name="标题"><text value="myTest001_标题1"/></field><field name="设计者"><text value="test"/></field></case><case id="34536547-71e4-428b-b269-4fa5d7972ad2"><field name="前置条件"><text value="1.myTest002_前置1"/><text value="2.myTest002_前置2"/></field><field name="步骤"><text value="1.myTest002_步骤1_测试"/><text value="2.myTest002_步骤2"/><text value="3.myTest002_步骤3"/></field><field name="优先级"><text value="myTest002_优先级1"/></field><field name="状态"><text value="Approved"/></field><field name="项目"><text value=""/></field><field name="目的"><text value="验证创建账号界面各个控件输入是否有效"/></field><field name="预期"><text value="1.myTest002_预期1"/></field><field name="关联需求"><text value="TEST-1"/></field><field name="关键用例"><text value=""/></field><field name="模块"><text value="/测试项目/账号管理/创建账号"/></field><field name="标题"><text value="myTest002_标题1"/></field><field name="设计者"><text value="test"/></field></case><case id="aaf1e599-e397-4877-ada0-aebee6b2d99c"><field name="前置条件"><text value="1.myTest001_前置1"/><text value="2.myTest001_前置2"/></field><field name="步骤"><text value="1.myTest001_步骤1"/><text value="2.myTest001_步骤2"/></field><field name="优先级"><text value="myTest001_优先级1"/></field><field name="状态"><text value="Approved"/></field><field name="项目"><text value=""/></field><field name="目的"><text value="验证创建账号界面各个控件输入是否有效"/></field><field name="预期"><text value="1.myTest001_预期1"/><text value="2.myTest001_预期2"/></field><field name="关联需求"><text value="TEST-1"/></field><field name="关键用例"><text value=""/></field><field name="模块"><text value="/测试项目/账号管理/创建账号"/></field><field name="标题"><text value="myTest001_标题1混合"/></field><field name="设计者"><text value="test"/></field></case></sheet></cases> \ No newline at end of file +<cases><sheet name="运行记录"><case id="7fdbc4d4-7106-46ca-a007-776d3c1b1678"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.012s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseConditionTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A2"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="20305811-b960-4c16-beea-f580a323f5c4"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseExpectTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A3"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="682b290f-d6d1-4ab9-9f56-30e1f4cbfca5"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseStepTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A4"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="b6cb40a3-07ae-435c-a442-6f3b5b6eea2e"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseTitleTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A5"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="2234270f-730d-4951-812e-44abef6ead58"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="exceptionTest_HasFile"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A2"><text value="" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="fe74a97c-f8c8-43bf-a631-eabc006c5f3f"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="exceptionTest_NotFile"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A3"><text value="" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="438603a2-b850-4881-aaa1-327b309433f4"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.002s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runMarkTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="这是备注信息"/></field></case><case id="790df044-2eac-40f7-a936-d1ddaf927a11"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.003s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.结果2,是BUG"/><text value="2.结果1,不是BUG" colors="10"/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runResultTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="14bc7123-d957-458f-99e1-64caac4e60c1"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.004s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runScreenshotTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="8dab2f52-e90b-4b4c-9653-f0cb43c3d584"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.003s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runStepTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value="1.第一步"/><text value="2.第二步"/><text value="3.第三步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case></sheet><sheet name="测试用例"><case id="7fdbc4d4-7106-46ca-a007-776d3c1b1678"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B2"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="20305811-b960-4c16-beea-f580a323f5c4"><field id="expect" name="预期"><text value="测试用例预期1"/><text value="测试用例预期2"/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B3"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="682b290f-d6d1-4ab9-9f56-30e1f4cbfca5"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B4"><text value=""/></field><field id="step" name="步骤"><text value="测试用例步骤1"/><text value="测试用例步骤2"/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="b6cb40a3-07ae-435c-a442-6f3b5b6eea2e"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B5"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value="测试用例标题"/></field></case></sheet><sheet name="错误记录"><case id="2234270f-730d-4951-812e-44abef6ead58"><field id="screenshot_position" name="截图位置"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="error_information" name="异常信息"><text value="抛出了RecordStateException异常"/></field><field id="error_class" name="异常类"><text value="pres.auxiliary.work.selenium.tool.RecordStateException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D6"><text value="exceptionTest_HasFile"/></field><field id="error_step" name="错误步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case><case id="fe74a97c-f8c8-43bf-a631-eabc006c5f3f"><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="error_information" name="异常信息"><text value="抛出了NullPointerException异常"/></field><field id="error_class" name="异常类"><text value="java.lang.NullPointerException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D7"><text value="exceptionTest_NotFile"/></field><field id="error_step" name="错误步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case></sheet></cases> \ 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 @@ <column id="id" name="序号" wide="8" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> <column id="method_name" name="方法名" wide="15" align="left"/> - <column id="error_step" name="错误步骤" wide="25" align="left"/> - <column id="error_class" name="异常类" wide="25" align="left"/> - <column id="error_information" name="异常信息" wide="25" align="left"/> - <column id="screenshot_position" name="截图位置" wide="25" align="left"/> + <column id="error_step" name="错误步骤" wide="25" align="left" index='true' row_text='1'/> + <column id="error_class" name="异常类" wide="25" align="left" index='true' row_text='1'/> + <column id="error_information" name="异常信息" wide="25" align="left" index='true' row_text='1'/> + <column id="screenshot_position" name="截图位置" wide="25" align="left" index='true' row_text='1'/> </sheet> <!-- 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 e2b4d43..80a4d7a 100644 --- a/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java +++ b/src/main/java/pres/auxiliary/tool/file/excel/AbstractWriteExcel.java @@ -311,8 +311,13 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } //还原下标 + /* + System.out.print(nowSheetName + " = "); + System.out.print(fieldMap.get(nowSheetName).get(field).name + " = "); + System.out.println(fieldMap.get(nowSheetName).get(field).content.size()); + */ 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)); @@ -322,7 +327,7 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { // 将字段内容写入fieldMap,若插入的下标不正确,则不做任何处理 try { - fieldMap.get(nowSheetName).get(field).content.addAll(index, Arrays.asList(contents)); + fieldMap.get(nowSheetName).get(field).content.addAll(fieldMap.get(nowSheetName).get(field).content.size() == 0 ? 0 : index + 1, Arrays.asList(contents)); } catch (Exception e) { } @@ -387,21 +392,7 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { /** * 用于结束一条用例写作的标志,调用该方法后将结束一条用例的编写, 该方法以下的添加用例内容的方法均为编辑另一条用例 */ - @SuppressWarnings("unchecked") public FieldMark end() { - /* - // 写入到caseXml中 - // 获取所有的sheet标签, 并筛选出name属性为sheetName的标签 - List<Element> sheetList = ((List<Element>) (contentXml.getRootElement().elements("sheet"))).stream() - .filter(e -> e.attributeValue("name").equals(sheetName)).collect(Collectors.toList()); - Element sheetElement = null; - // 判断是否存在sheet标签,若存在,则直接获筛选后的第一个数据,若不存在,则创建 - if (sheetList.size() != 0) { - sheetElement = sheetList.get(0); - } else { - sheetElement = contentXml.getRootElement().addElement("sheet").addAttribute("name", sheetName); - } - */ if (writeSheetNameList.isEmpty()) { throw new IncorrectIndexException("当前不存在需要写入的sheet内容"); } @@ -411,14 +402,17 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { // 创建case标签 writeSheetNameList.forEach(sheetName -> { // 写入到caseXml中 - // 获取所有的sheet标签, 并筛选出name属性为sheetName的标签 - Element sheetElement = null; + // 通过xpath查询到相应的sheet标签 + String finSheetXpath = "//sheet[@name='" + sheetName + "']"; + Element sheetElement = (Element) (contentXml.selectSingleNode(finSheetXpath)); + /* for (Element element : ((List<Element>) (contentXml.getRootElement().elements("sheet")))) { if (element.attributeValue("name").equals(sheetName)) { sheetElement = element; break; } } + */ // 判断是否存在sheet标签,若不存在,则创建相应的标签 if (sheetElement == null) { @@ -453,9 +447,9 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { } } }); - + // 清空fieldMap中的内容 - clearFieldContent(); + clearFieldContent(sheetName); // 将字段常值设置入fieldMap中,若抛出异常,则不进行处理 /* if (constValueMap != null && constValueMap.size() != 0) { @@ -806,12 +800,10 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { /** * 清空fieldMap内的存储字段信息,不清除字段 */ - private void clearFieldContent() { - fieldMap.forEach((sheetName, sheetFieldMap) -> { - sheetFieldMap.forEach((fieldId, field) -> { + private void clearFieldContent(String sheetName) { + fieldMap.get(sheetName).forEach((fieldId, field) -> { field.clearContent(); }); - }); } /** @@ -1431,7 +1423,6 @@ public abstract class AbstractWriteExcel<T extends AbstractWriteExcel<T>> { return null; } */ - return ((Element) (contentXml.selectSingleNode("//sheet[@name='" + sheetName +"']/case[@id='" + uuid + "']"))); } 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 9d723af..1872d89 100644 --- a/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java +++ b/src/main/java/pres/auxiliary/work/selenium/tool/ExcelRecord.java @@ -105,9 +105,11 @@ public class ExcelRecord extends AbstractWriteExcel<ExcelRecord> { /** * 用于记录执行开始时间,记录结束时,会写入相应的结束时间 */ - public void reckonByTime() { + public ExcelRecord reckonByTime() { //若设定当前状态为开始记录状态,则存储当前的时间戳 startTime = System.currentTimeMillis(); + + return this; } /** @@ -182,6 +184,7 @@ public class ExcelRecord extends AbstractWriteExcel<ExcelRecord> { * @return 类本身 */ public ExcelRecord exception(Exception exception, File screenshotFile) { + errorScreenhotFile = screenshotFile; return exception(exception) .switchSheet("错误记录") .addContent("screenshot_position", screenshotFile.getPath()); diff --git a/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java b/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java index 8daaff0..8f907e5 100644 --- a/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java +++ b/src/test/java/pres/auxiliary/work/selenium/tool/ExcelRecordTest.java @@ -105,4 +105,36 @@ public class ExcelRecordTest { public void caseExpectTest() { er.caseExpect("测试用例预期1", "测试用例预期2"); } + + @Test + public void addAllContentTest() { + er.caseTitle("测试成功运行标题") + .caseStep("测试第1步") + .caseExpect("测试第1预期") + .caseCondition("前置条件1") + .runStep("实际第1步") + .runStep("实际第2步") + .runStep("实际第3步", "实际第4步") + .runResult("实际结果1", false) + .runResult("实际结果2", true) + .runMark("实际备注") + .runScreenshot(imageFile) + .end(); + + er.reckonByTime() + .caseTitle("测试失败运行标题") + .caseStep("测试第1步") + .caseExpect("测试第1预期") + .caseCondition("前置条件1") + .runStep("实际第1步") + .runStep("实际第2步", "实际第3步") + .exception(new NullPointerException("此时抛出了NullPointerException异常"), imageFile) + .runStep("实际第4步") + .runStep("实际第5步") + .exception(new RecordStateException("这里出现了RecordStateException异常")) + .runResult("实际结果1", false) + .runResult("实际结果2", true) + .runMark("实际备注") + .runScreenshot(imageFile); + } } diff --git a/src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx b/src/test/java/pres/auxiliary/work/selenium/tool/Test.xlsx index 1ec4c1aa01271881a755b2d0306da04a702f1b3d..407de1611850256a420496fb7e34499810b61b42 100644 GIT binary patch delta 5141 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 delta 5805 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 a->pU|@XwAgL3cLc-M(hGn>ePq>-`VPj%iB( diff --git a/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml b/src/test/java/pres/auxiliary/work/testcase/用例xml文件.xml index 9f3adbe..4d7bbf5 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 @@ <?xml version="1.0" encoding="UTF-8"?> -<cases><sheet name="运行记录"><case id="7fdbc4d4-7106-46ca-a007-776d3c1b1678"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.012s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseConditionTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A2"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="20305811-b960-4c16-beea-f580a323f5c4"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseExpectTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A3"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="682b290f-d6d1-4ab9-9f56-30e1f4cbfca5"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseStepTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A4"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="b6cb40a3-07ae-435c-a442-6f3b5b6eea2e"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="caseTitleTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A5"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="2234270f-730d-4951-812e-44abef6ead58"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="exceptionTest_HasFile"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A2"><text value="" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="fe74a97c-f8c8-43bf-a631-eabc006c5f3f"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value=""/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value=""/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value=""/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="exceptionTest_NotFile"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A3"><text value="" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="438603a2-b850-4881-aaa1-327b309433f4"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.002s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runMarkTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="这是备注信息"/></field></case><case id="790df044-2eac-40f7-a936-d1ddaf927a11"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.003s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.结果2,是BUG"/><text value="2.结果1,不是BUG" colors="10"/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runResultTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="14bc7123-d957-458f-99e1-64caac4e60c1"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.004s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runScreenshotTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case><case id="8dab2f52-e90b-4b4c-9653-f0cb43c3d584"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.003s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value=""/></field><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="active_time" name="执行时间"><text value="2020-08-29 22:03:02"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="0"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="runStepTest"/></field><field id="case_id" name="用例编号"><text value=""/></field><field id="step" name="执行步骤"><text value="1.第一步"/><text value="2.第二步"/><text value="3.第三步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value=""/></field></case></sheet><sheet name="测试用例"><case id="7fdbc4d4-7106-46ca-a007-776d3c1b1678"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B2"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="20305811-b960-4c16-beea-f580a323f5c4"><field id="expect" name="预期"><text value="测试用例预期1"/><text value="测试用例预期2"/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B3"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="682b290f-d6d1-4ab9-9f56-30e1f4cbfca5"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B4"><text value=""/></field><field id="step" name="步骤"><text value="测试用例步骤1"/><text value="测试用例步骤2"/></field><field id="title" name="用例标题"><text value=""/></field></case><case id="b6cb40a3-07ae-435c-a442-6f3b5b6eea2e"><field id="expect" name="预期"><text value=""/></field><field id="condition" name="前置条件"><text value=""/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B5"><text value=""/></field><field id="step" name="步骤"><text value=""/></field><field id="title" name="用例标题"><text value="测试用例标题"/></field></case></sheet><sheet name="错误记录"><case id="2234270f-730d-4951-812e-44abef6ead58"><field id="screenshot_position" name="截图位置"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="error_information" name="异常信息"><text value="抛出了RecordStateException异常"/></field><field id="error_class" name="异常类"><text value="pres.auxiliary.work.selenium.tool.RecordStateException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D6"><text value="exceptionTest_HasFile"/></field><field id="error_step" name="错误步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case><case id="fe74a97c-f8c8-43bf-a631-eabc006c5f3f"><field id="screenshot_position" name="截图位置"><text value=""/></field><field id="error_information" name="异常信息"><text value="抛出了NullPointerException异常"/></field><field id="error_class" name="异常类"><text value="java.lang.NullPointerException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D7"><text value="exceptionTest_NotFile"/></field><field id="error_step" name="错误步骤"><text value=""/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case></sheet></cases> \ No newline at end of file +<cases><sheet name="运行记录"><case id="2c206a2f-2c1c-43e1-a633-374561096866"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.01s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.实际结果1"/><text value="2.实际结果2" colors="10"/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-31 12:50:19"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="addAllContentTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A2"><text value=""/></field><field id="step" name="执行步骤"><text value="1.实际第1步"/><text value="2.实际第2步"/><text value="3.实际第3步"/><text value="4.实际第4步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="实际备注"/></field></case><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.004s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.实际结果1"/><text value="2.实际结果2" colors="10"/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-31 12:50:19"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="addAllContentTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A3"><text value=""/></field><field id="step" name="执行步骤"><text value="1.实际第1步"/><text value="2.实际第2步"/><text value="3.实际第3步"/><text value="4.实际第4步"/><text value="5.实际第5步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A2"><text value="异常" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="实际备注"/></field></case></sheet><sheet name="测试用例"><case id="2c206a2f-2c1c-43e1-a633-374561096866"><field id="expect" name="预期"><text value="测试第1预期"/></field><field id="condition" name="前置条件"><text value="1.前置条件1"/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B2"><text value=""/></field><field id="step" name="步骤"><text value="测试第1步"/></field><field id="title" name="用例标题"><text value="测试成功运行标题"/></field></case><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="expect" name="预期"><text value="测试第1预期"/></field><field id="condition" name="前置条件"><text value="1.前置条件1"/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B3"><text value=""/></field><field id="step" name="步骤"><text value="测试第1步"/></field><field id="title" name="用例标题"><text value="测试失败运行标题"/></field></case></sheet><sheet name="错误记录"><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="1.src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="error_information" name="异常信息"><text value="1.此时抛出了NullPointerException异常"/><text value="2.这里出现了RecordStateException异常"/></field><field id="error_class" name="异常类"><text value="1.java.lang.NullPointerException"/><text value="2.pres.auxiliary.work.selenium.tool.RecordStateException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D3"><text value="addAllContentTest"/></field><field id="error_step" name="错误步骤"><text value="1.实际第3步"/><text value="2.实际第5步"/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case></sheet></cases> \ No newline at end of file From 140879a934a0f6b256631d63327fdf08e80d73b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BD=AD=E5=AE=87=E7=90=A6?= <465615774@qq.com> Date: Thu, 3 Sep 2020 08:41:27 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=8D=E8=AF=AD?= =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LogConfiguration/ExcelRecordTemplet.xml | 18 -- .../tool/file/excel/AbstractWriteExcel.java | 2 +- .../tool/file/excel/ReplactFunction.java | 22 +++ .../work/selenium/element/AbstractBy.java | 13 +- .../work/selenium/element/DataListBy.java | 8 - .../work/selenium/element/ListBy.java | 8 - .../work/selenium/element/MultiBy.java | 8 - .../work/selenium/element/SelectBy.java | 8 - .../selenium/tool/{Log.java => Log_Old.java} | 8 +- .../work/selenium/tool/RecordTool.java | 8 +- .../auxiliary/work/selenium/tool/RunLog.java | 32 ++++ .../work/testcase/用例xml文件.xml | 178 +++++++++++++++++- src/test/java/test/javase/testResultFile.java | 4 +- 13 files changed, 248 insertions(+), 69 deletions(-) create mode 100644 src/main/java/pres/auxiliary/tool/file/excel/ReplactFunction.java rename src/main/java/pres/auxiliary/work/selenium/tool/{Log.java => Log_Old.java} (95%) create mode 100644 src/main/java/pres/auxiliary/work/selenium/tool/RunLog.java diff --git a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml index 6f2e203..1f27337 100644 --- a/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml +++ b/ConfigurationFiles/SeleniumConfigurationFile/LogConfiguration/ExcelRecordTemplet.xml @@ -31,15 +31,6 @@ </datas> </sheet> - <!-- - <sheet name="运行记录截图" freeze="0"> - <column id="id" name="序号" wide="8" align="center"/> - <column id="class_name" name="类名" wide="25" align="left"/> - <column id="method_name" name="方法名" wide="15" align="left" link="运行记录|id"/> - <column id="screenshot" name="截图" wide="25" align="left" link="本地"/> - </sheet> - --> - <sheet name="错误记录" freeze="4"> <column id="id" name="序号" wide="8" align="center"/> <column id="class_name" name="类名" wide="25" align="left"/> @@ -49,13 +40,4 @@ <column id="error_information" name="异常信息" wide="25" align="left" index='true' row_text='1'/> <column id="screenshot_position" name="截图位置" wide="25" align="left" index='true' row_text='1'/> </sheet> - - <!-- - <sheet name="错误记录截图" freeze="0"> - <column id="id" name="序号" wide="8" align="center"/> - <column id="class_name" name="类名" wide="25" align="left"/> - <column id="method_name" name="方法名" wide="15" align="left" link="错误记录|id"/> - <column id="screenshot" name="截图" wide="25" align="left" link="本地"/> - </sheet> - --> </templet> \ 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<T extends AbstractWriteExcel<T>> { word = WORD_SIGN + word + WORD_SIGN; replaceWordMap.put(word, replactWord); } - + /** * 通过传入的字段id,将对应的字段内容写入到用例最后的段落中,字段id对应xml配置文件中的单元格标签的id属性。 * 若需要使用替换的词语,则需要使用“#XX#”进行标记,如传参:<br> 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; + +/** + * <p><b>文件名:</b>ReplactFunction.java</p> + * <p><b>用途:</b> + * 用于根据替换词语,设置相应的替换方法,并在读取到该词语时执行设置方法的接口 + * </p> + * <p><b>编码时间:</b>2020年9月3日上午8:24:58</p> + * <p><b>修改时间:</b>2020年9月3日上午8:24:58</p> + * @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; /** * <p><b>文件名:</b>AbstractElement.java</p> * <p><b>用途:</b></p> - * <p><pre> - * 对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的 + * <p>对辅助化测试工具selenium的获取元素代码进行的二次封装,通过类中提供的方法以及配合相应存储元素的 * xml文件,以更简便的方式对页面元素进行获取,减少编程时的代码量。 - * </pre></p> + * </p> * <p><b>编码时间:</b>2020年4月25日 下午4:18:37</p> * <p><b>修改时间:</b>2020年4月25日 下午4:18:37</p> * @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\\<br/> * 默认文件名为(不带后缀):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; + +/** + * <p><b>文件名:</b>RunLog.java</p> + * <p><b>用途:</b> + * 以纯文本的形式记录自动化运行过程 + * </p> + * <p><b>编码时间:</b>2020年9月3日上午8:02:37</p> + * <p><b>修改时间:</b>2020年9月3日上午8:02:37</p> + * @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 @@ <?xml version="1.0" encoding="UTF-8"?> -<cases><sheet name="运行记录"><case id="2c206a2f-2c1c-43e1-a633-374561096866"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.01s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.实际结果1"/><text value="2.实际结果2" colors="10"/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-31 12:50:19"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="addAllContentTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A2"><text value=""/></field><field id="step" name="执行步骤"><text value="1.实际第1步"/><text value="2.实际第2步"/><text value="3.实际第3步"/><text value="4.实际第4步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态"><text value="正常"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="实际备注"/></field></case><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="active_person" name="执行者"><text value="yuqipeng_d"/></field><field id="use_time" name="执行耗时"><text value="0.004s"/></field><field id="version" name="版本"><text value=""/></field><field id="result" name="执行结果"><text value="1.实际结果1"/><text value="2.实际结果2" colors="10"/></field><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="active_time" name="执行时间"><text value="2020-08-31 12:50:19"/></field><field id="brower" name="浏览器"><text value=""/></field><field id="bug_number" name="Bug数量"><text value="1"/></field><field id="system" name="操作系统"><text value=""/></field><field id="method_name" name="方法名"><text value="addAllContentTest"/></field><field id="case_id" name="用例编号" link="dom='测试用例'!A3"><text value=""/></field><field id="step" name="执行步骤"><text value="1.实际第1步"/><text value="2.实际第2步"/><text value="3.实际第3步"/><text value="4.实际第4步"/><text value="5.实际第5步"/></field><field id="id" name="序号"><text value=""/></field><field id="state" name="执行状态" link="dom='错误记录'!A2"><text value="异常" colors="10"/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field><field id="mark" name="备注"><text value="实际备注"/></field></case></sheet><sheet name="测试用例"><case id="2c206a2f-2c1c-43e1-a633-374561096866"><field id="expect" name="预期"><text value="测试第1预期"/></field><field id="condition" name="前置条件"><text value="1.前置条件1"/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B2"><text value=""/></field><field id="step" name="步骤"><text value="测试第1步"/></field><field id="title" name="用例标题"><text value="测试成功运行标题"/></field></case><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="expect" name="预期"><text value="测试第1预期"/></field><field id="condition" name="前置条件"><text value="1.前置条件1"/></field><field id="case_id" name="用例编号" link="dom='运行记录'!B3"><text value=""/></field><field id="step" name="步骤"><text value="测试第1步"/></field><field id="title" name="用例标题"><text value="测试失败运行标题"/></field></case></sheet><sheet name="错误记录"><case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"><field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"><text value="1.src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/></field><field id="error_information" name="异常信息"><text value="1.此时抛出了NullPointerException异常"/><text value="2.这里出现了RecordStateException异常"/></field><field id="error_class" name="异常类"><text value="1.java.lang.NullPointerException"/><text value="2.pres.auxiliary.work.selenium.tool.RecordStateException"/></field><field id="method_name" name="方法名" link="dom='运行记录'!D3"><text value="addAllContentTest"/></field><field id="error_step" name="错误步骤"><text value="1.实际第3步"/><text value="2.实际第5步"/></field><field id="id" name="序号"><text value=""/></field><field id="class_name" name="类名"><text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/></field></case></sheet></cases> \ No newline at end of file +<cases> + <sheet name="运行记录"> + <case id="2c206a2f-2c1c-43e1-a633-374561096866"> + <field id="active_person" name="执行者"> + <text value="yuqipeng_d"/> + </field> + <field id="use_time" name="执行耗时"> + <text value="0.01s"/> + </field> + <field id="version" name="版本"> + <text value=""/> + </field> + <field id="result" name="执行结果"> + <text value="1.实际结果1"/> + <text value="2.实际结果2" colors="10"/> + </field> + <field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"> + <text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/> + </field> + <field id="active_time" name="执行时间"> + <text value="2020-08-31 12:50:19"/> + </field> + <field id="brower" name="浏览器"> + <text value=""/> + </field> + <field id="bug_number" name="Bug数量"> + <text value="1"/> + </field> + <field id="system" name="操作系统"> + <text value=""/> + </field> + <field id="method_name" name="方法名"> + <text value="addAllContentTest"/> + </field> + <field id="case_id" name="用例编号" link="dom='测试用例'!A2"> + <text value=""/> + </field> + <field id="step" name="执行步骤"> + <text value="1.实际第1步"/> + <text value="2.实际第2步"/> + <text value="3.实际第3步"/> + <text value="4.实际第4步"/> + </field> + <field id="id" name="序号"> + <text value=""/> + </field> + <field id="state" name="执行状态"> + <text value="正常"/> + </field> + <field id="class_name" name="类名"> + <text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/> + </field> + <field id="mark" name="备注"> + <text value="实际备注"/> + </field> + </case> + <case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"> + <field id="active_person" name="执行者"> + <text value="yuqipeng_d"/> + </field> + <field id="use_time" name="执行耗时"> + <text value="0.004s"/> + </field> + <field id="version" name="版本"> + <text value=""/> + </field> + <field id="result" name="执行结果"> + <text value="1.实际结果1"/> + <text value="2.实际结果2" colors="10"/> + </field> + <field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"> + <text value="src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/> + </field> + <field id="active_time" name="执行时间"> + <text value="2020-08-31 12:50:19"/> + </field> + <field id="brower" name="浏览器"> + <text value=""/> + </field> + <field id="bug_number" name="Bug数量"> + <text value="1"/> + </field> + <field id="system" name="操作系统"> + <text value=""/> + </field> + <field id="method_name" name="方法名"> + <text value="addAllContentTest"/> + </field> + <field id="case_id" name="用例编号" link="dom='测试用例'!A3"> + <text value=""/> + </field> + <field id="step" name="执行步骤"> + <text value="1.实际第1步"/> + <text value="2.实际第2步"/> + <text value="3.实际第3步"/> + <text value="4.实际第4步"/> + <text value="5.实际第5步"/> + </field> + <field id="id" name="序号"> + <text value=""/> + </field> + <field id="state" name="执行状态" link="dom='错误记录'!A2"> + <text value="异常" colors="10"/> + </field> + <field id="class_name" name="类名"> + <text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/> + </field> + <field id="mark" name="备注"> + <text value="实际备注"/> + </field> + </case> + </sheet> + <sheet name="测试用例"> + <case id="2c206a2f-2c1c-43e1-a633-374561096866"> + <field id="expect" name="预期"> + <text value="测试第1预期"/> + </field> + <field id="condition" name="前置条件"> + <text value="1.前置条件1"/> + </field> + <field id="case_id" name="用例编号" link="dom='运行记录'!B2"> + <text value=""/> + </field> + <field id="step" name="步骤"> + <text value="测试第1步"/> + </field> + <field id="title" name="用例标题"> + <text value="测试成功运行标题"/> + </field> + </case> + <case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"> + <field id="expect" name="预期"> + <text value="测试第1预期"/> + </field> + <field id="condition" name="前置条件"> + <text value="1.前置条件1"/> + </field> + <field id="case_id" name="用例编号" link="dom='运行记录'!B3"> + <text value=""/> + </field> + <field id="step" name="步骤"> + <text value="测试第1步"/> + </field> + <field id="title" name="用例标题"> + <text value="测试失败运行标题"/> + </field> + </case> + </sheet> + <sheet name="错误记录"> + <case id="1ce766aa-f62c-4df3-bc09-80e63ab67a41"> + <field id="screenshot_position" name="截图位置" link="file=./微信图片_20200828101657.png"> + <text value="1.src\test\java\pres\auxiliary\work\selenium\tool\微信图片_20200828101657.png"/> + </field> + <field id="error_information" name="异常信息"> + <text value="1.此时抛出了NullPointerException异常"/> + <text value="2.这里出现了RecordStateException异常"/> + </field> + <field id="error_class" name="异常类"> + <text value="1.java.lang.NullPointerException"/> + <text value="2.pres.auxiliary.work.selenium.tool.RecordStateException"/> + </field> + <field id="method_name" name="方法名" link="dom='运行记录'!D3"> + <text value="addAllContentTest"/> + </field> + <field id="error_step" name="错误步骤"> + <text value="1.实际第3步"/> + <text value="2.实际第5步"/> + </field> + <field id="id" name="序号"> + <text value=""/> + </field> + <field id="class_name" name="类名"> + <text value="pres.auxiliary.work.selenium.tool.ExcelRecordTest"/> + </field> + </case> + </sheet> +</cases> \ 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"); }