更换仓库

This commit is contained in:
彭宇琦 2020-01-17 17:46:43 +08:00
commit 32d3f9b277
313 changed files with 1399465 additions and 0 deletions

30
.classpath Normal file
View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="test" value="true"/>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-12">
<attributes>
<attribute name="module" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.testng.TESTNG_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="lib" path="lib/beautyeye_lnf.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target/

23
.project Normal file
View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Autest</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
</natures>
</projectDescription>

View File

@ -0,0 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8

View File

@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=12
org.eclipse.jdt.core.compiler.compliance=12
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
org.eclipse.jdt.core.compiler.release=enabled
org.eclipse.jdt.core.compiler.source=12

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<templet>
<sheet id="case" name="测试用例" freeze="4">
<column id="case_id" name="用例编号" wide="14.00" align="center"/>
<column id="module" name="所属模块" wide="22.00" align="center"/>
<column id="story" name="相关需求" wide="22.00" align="center"/>
<column id="title" name="用例标题" wide="30.88" align="left"/>
<column id="step" name="步骤" wide="45.75" align="left"/>
<column id="expect" name="预期" wide="45.75" align="left"/>
<column id="keys" name="关键词" wide="7.88" align="left"/>
<column id="type" name="用例类型" wide="9.63" align="left"/>
<column id="rank" name="优先级" wide="6.00" align="left"/>
<column id="state" name="用例状态" wide="6.00" align="left"/>
<column id="stage" name="适用阶段" wide="6.00" align="left"/>
<column id="condition" name="前置条件" wide="18.25" align="left"/>
<column id="flow" name="所属流程" wide="15.00" align="center"/>
</sheet>
</templet>

View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="GBK"?>
<cases project="AddInformation">
<case function="addTextboxCase">
<steps>
<step id="1" value="不填写或只输入空格,点击“*{buttonName}*”按钮"/>
<step id="2" value="填写特殊字符或HTML代码点击“*{buttonName}*”按钮"/>
<step id="3" value="输入非*{charGroup}*,点击“*{buttonName}*”按钮"/>
<step id="4" value="输入小于*{lengthMin}*个字符,点击“*{buttonName}*”按钮"/>
<step id="5" value="输入*{lengthMin}*个字符,点击“*{buttonName}*”按钮"/>
<step id="6" value="输入大于*{lengthMax}*个字符,点击“*{buttonName}*”按钮"/>
<step id="7" value="输入*{lengthMax}*个字符,点击“*{buttonName}*”按钮"/>
<step id="8" value="输入小于*{numberMin}*的数字,点击“*{buttonName}*”按钮"/>
<step id="9" value="输入*{numberMin}*的数字,点击“*{buttonName}*”按钮"/>
<step id="10" value="输入大于*{numberMax}*的数字,点击“*{buttonName}*”按钮"/>
<step id="11" value="输入*{numberMax}*的数字,点击“*{buttonName}*”按钮"/>
<step id="12" value="填写一个已存在的*{name}*信息,点击“*{buttonName}*”按钮"/>
</steps>
<expectationss>
</expectationss>
</case>
<case function="addSelectboxCase">
<steps>
<step id="1" value="不进行选择或选择空选项,点击“*{buttonName}*”按钮"/>
<step id="2" value="选择选项中的第一项,点击“*{buttonName}*”按钮"/>
<step id="3" value="选择选项中的最后一项,点击“*{buttonName}*”按钮"/>
</steps>
<expectationss>
</expectationss>
</case>
<case function="addRadioButtonCase">
<steps>
<step id="1" value="从第一个选项开始,将所有的选项依次点击"/>
<step id="2" value="不进行选择,点击“*{buttonName}*”按钮"/>
<step id="3" value="选择选项中的第一项,点击“*{buttonName}*”按钮"/>
<step id="4" value="选择选项中的最后一项,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
<expectation id="1" value="不会出现有两个或以上的选项被选中的情况"/>
</expectations>
</case>
<case function="addCheckboxCase">
<steps>
<step id="1" value="从第一个选项开始,依次点击所有的选项"/>
<step id="2" value="再次依次点击所有的选项"/>
<step id="3" value="不进行选择,点击“*{buttonName}*”按钮"/>
<step id="4" value="选择选项中的第一项,点击“*{buttonName}*”按钮"/>
<step id="5" value="选择选项中的最后一项,点击“*{buttonName}*”按钮"/>
<step id="6" value="选择其中多个选项,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
<expectation id="1" value="所有的选项均被勾选"/>
<expectation id="2" value="所有的选项均被取消勾选"/>
</expectations>
</case>
<case function="addDateCase">
<steps>
<step id="1" value="不选择时间,点击“*{buttonName}*”按钮"/>
<step id="2" value="选择当前的时间,点击“*{buttonName}*”按钮"/>
<step id="3" value="选择时间后清空时间,点击“*{buttonName}*”按钮"/>
<step id="4" value="手动输入正确格式的日期,点击“*{buttonName}*”按钮"/>
<step id="5" value="手动输入非正确格式的日期,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addStartDateCase">
<steps>
<step id="1" value="不选择时间,点击“*{buttonName}*”按钮"/>
<step id="2" value="选择当前的时间,点击“*{buttonName}*”按钮"/>
<step id="3" value="选择时间后清空时间,点击“*{buttonName}*”按钮"/>
<step id="4" value="手动输入正确格式的日期,点击“*{buttonName}*”按钮"/>
<step id="5" value="手动输入非正确格式的日期,点击“*{buttonName}*”按钮"/>
<step id="6" value="输入或选择大于*{endDateName}*的日期,点击“*{buttonName}*”按钮"/>
<step id="7" value="选择大于*{endDateName}*的日期,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addEndDateCase">
<steps>
<step id="1" value="不选择时间,点击“*{buttonName}*”按钮"/>
<step id="2" value="选择当前的时间,点击“*{buttonName}*”按钮"/>
<step id="3" value="选择时间后清空时间,点击“*{buttonName}*”按钮"/>
<step id="4" value="手动输入正确格式的日期,点击“*{buttonName}*”按钮"/>
<step id="5" value="手动输入非正确格式的日期,点击“*{buttonName}*”按钮"/>
<step id="6" value="输入或选择小于*{startDateName}*的日期,点击“*{buttonName}*”按钮"/>
<step id="7" value="选择小于*{startDateName}*的日期,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addPhoneCase">
<steps>
<step id="1" value="不进行输入,点击“*{buttonName}*”按钮"/>
<step id="2" value="输入非数字字符,点击“*{buttonName}*”按钮"/>
<step id="3" value="输入大于11位的数字点击“*{buttonName}*”按钮"/>
<step id="4" value="输入小于11位的数字点击“*{buttonName}*”按钮"/>
<step id="5" value="输入大于7位的数字点击“*{buttonName}*”按钮"/>
<step id="6" value="输入小于7位的数字点击“*{buttonName}*”按钮"/>
<step id="7" value="输入不符合规则但长度符合规则的数字,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addIDCardCase">
<steps>
<step id="1" value="不进行输入,点击“*{buttonName}*”按钮"/>
<step id="2" value="输入非数字字符,点击“*{buttonName}*”按钮"/>
<step id="3" value="输入15位的证件信息点击“*{buttonName}*”按钮"/>
<step id="4" value="输入18位的证件信息点击“*{buttonName}*”按钮"/>
<step id="5" value="输入末尾带“X”或“x”的证件信息点击“*{buttonName}*”按钮"/>
<step id="6" value="输入大于18位的数字点击“*{buttonName}*”按钮"/>
<step id="7" value="输入小于18位但大于15位的数字点击“*{buttonName}*”按钮"/>
<step id="8" value="输入小于15位的数字点击“*{buttonName}*”按钮"/>
<step id="9" value="输入不符合证件规则但长度符合规则的数字如123456789012345678点击“*{buttonName}*”按钮"/>
<step id="10" value="输入存在的证件信息,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addUploadImageCase">
<steps>
<step id="1" value="不*{text}*图片,点击“*{buttonName}*”按钮"/>
<step id="2" value="上传图片后点击图片"/>
<step id="3" value="*{text}*图片后删除图片再*{text}*图片,点击“*{buttonName}*”按钮"/>
<step id="4" value="*{text}*同一张图片,点击“*{buttonName}*”按钮"/>
<step id="5" value="拍照后再取消拍照"/>
<step id="6" value="*{text}*超过限制大小的图片,点击“*{buttonName}*”按钮"/>
<step id="7" value="*{text}*较大的图片如超过3M的图片点击“*{buttonName}*”按钮"/>
<step id="8" value="上传非*{fileGroup}*格式的文件,点击“*{buttonName}*”按钮"/>
<step id="9" value="*{text}*上传非图片格式的文件,点击“*{buttonName}*”按钮"/>
<step id="10" value="*{text}*小于*{fileMin}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="11" value="*{text}**{fileMin}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="12" value="*{text}*大于*{fileMax}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="13" value="*{text}**{fileMax}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
<expectation id="2" value="图片能进行预览"/>
<expectation id="5" value="界面上不显示任何图片"/>
</expectations>
</case>
<case function="addUploadFileCase">
<steps>
<step id="1" value="不上传文件,点击“*{buttonName}*”按钮"/>
<step id="2" value="上传文件后删除图片再上传一个文件,点击“*{buttonName}*”按钮"/>
<step id="3" value="上传同一个文件,点击“*{buttonName}*”按钮"/>
<step id="4" value="上传超过限制大小的文件,点击“*{buttonName}*”按钮"/>
<step id="5" value="上传较大的文件如超过50M的文件点击“*{buttonName}*”按钮"/>
<step id="6" value="上传非*{fileGroup}*格式的文件,点击“*{buttonName}*”按钮"/>
<step id="7" value="*{text}*小于*{fileMin}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="8" value="*{text}**{fileMin}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="9" value="*{text}*大于*{fileMax}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
<step id="10" value="*{text}**{fileMax}**{s}**{mode}*,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addWholeInformationCase">
<steps>
<step id="1" value="正确填写所有的信息,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
<case function="addUnWholeInformationCase">
<steps>
<step id="1" value="不填写任何信息,点击“*{buttonName}*”按钮"/>
<step id="2" value="只填写所有的必填项信息,点击“*{buttonName}*”按钮"/>
<step id="3" value="只填写所有的非必填项信息,点击“*{buttonName}*”按钮"/>
</steps>
<expectations>
</expectations>
</case>
</cases>

View File

@ -0,0 +1,217 @@
<?xml version="1.0" encoding="GBK"?>
<cases project="BrowseList">
<case function="addAppBrowseListCase">
<title value="浏览*{name}*列表" />
<keyword value="*{name}*列表,刷新,加载" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="查看*{name}*列表" />
<step id="2" value="下拉刷新列表" />
<step id="3" value="上拉加载列表" />
<step id="4" value="在无剩余数据时,上拉加载列表" />
<step id="5" value="加载或刷新列表时点击某一个信息或某一个按钮" />
</steps>
<expectations>
<expectation id="1" value="能看到当前存在的所有信息,且信息按一定规则排序"/>
<expectation id="2" value="列表被刷新,若有新增信息则被显示出来,且原有数据排序不会混乱"/>
<expectation id="3" value="能加载剩下的信息"/>
<expectation id="4" value="上拉有效,但不加载出数据或数据不会错乱"/>
<expectation id="5" value="app不会闪退且能正常显示"/>
</expectations>
</case>
<case function="addWebBrowseListCase">
<title value="浏览*{name}*列表" />
<keyword value="*{name}*列表,刷新,加载" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="查看*{name}*列表" />
<step id="2" value="翻页查看*{name}*列表" />
<step id="3" value="在首页上点击“首页”按钮" />
<step id="4" value="在首页上点击“上一页”按钮" />
<step id="5" value="在尾页上点击“尾页”按钮" />
<step id="6" value="在尾页上点击“下一页”按钮" />
</steps>
<expectations>
<expectation id="1" value="能看到当前存在的所有信息,且信息按一定规则排序"/>
<expectation id="2" value="能看到不同页上的列表信息,且切换页后列表的排序不变"/>
<expectation id="3" value="按钮无法点击或点击无效,且当前页列表排序不变"/>
<expectation id="4" value="按钮无法点击或点击无效,且当前页列表排序不变"/>
<expectation id="5" value="按钮无法点击或点击无效,且当前页列表排序不变"/>
<expectation id="6" value="按钮无法点击或点击无效,且当前页列表排序不变"/>
</expectations>
</case>
<case function="addInputSearchCase">
<title value="通过*{condition}*对*{information}*进行搜索" />
<keyword value="*{information}*列表,搜索" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="通过*{condition}*对*{information}*进行模糊搜索" />
<step id="2" value="通过*{condition}*对*{information}*进行精准搜索" />
<step id="3" value="不输入信息进行搜索" />
<step id="4" value="输入*{information}*中都不包含的关键词进行搜索" />
</steps>
<expectations>
<expectation id="1" value="能搜索出包含输入内容的结果"/>
<expectation id="2" value="能搜索出与输入相对应的结果"/>
<expectation id="3" value="能查看到所有的结果"/>
<expectation id="4" value="无搜索结果"/>
</expectations>
</case>
<case function="addSelectSearchCase">
<title value="通过*{condition}*对*{information}*进行搜索" />
<keyword value="*{information}*列表,搜索" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="选择*{condition}*的第一个选项对*{information}*进行搜索" />
<step id="2" value="选择*{condition}*非第一个选项和非最后一个选项对*{information}*进行搜索" />
<step id="3" value="选择*{condition}*的最后一个选项对*{information}*进行搜索" />
<step id="4" value="不选择任何选项进行搜索" />
<step id="5" value="选择所有*{information}*中都不包含的选项进行搜索" />
</steps>
<expectations>
<expectation id="1" value="能搜索出符合选项的结果"/>
<expectation id="2" value="能搜索出符合选项的结果"/>
<expectation id="3" value="能搜索出符合选项的结果"/>
<expectation id="4" value="能查看到所有的结果"/>
<expectation id="5" value="无搜索结果"/>
</expectations>
</case>
<case function="addDateSearchCase">
<title value="通过*{condition}*对*{information}*进行搜索" />
<keyword value="*{information}*列表,搜索" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="选择一个*{condition}*存在的*{s}*数据进行搜索" />
<step id="2" value="选择一个*{condition}*不存在的*{s}*数据进行搜索" />
<step id="3" value="不选择*{condition}*进行搜索" />
<step id="4" value="选择一个开始时间大于结束时间的时间段进行搜索" />
<step id="5" value="通过不选择开始时间,只选择结束时间的时间段进行搜索" />
<step id="6" value="通过不选择结束时间,只选择开始时间的时间段进行搜索" />
</steps>
<expectations>
<expectation id="1" value="能搜索出在该*{s}*内所有的结果"/>
<expectation id="2" value="搜索无结果"/>
<expectation id="3" value="能搜索出所有的结果"/>
<expectation id="4" value="无搜索结果或弹出错误输入的提示"/>
<expectation id="5" value="能搜索出从有数据以来至结束时间的所有结果"/>
<expectation id="6" value="能搜索出从开始时间至今的所有结果"/>
</expectations>
</case>
<case function="addListSortCase">
<title value="对*{information}*列表按照*{condition}*进行排序" />
<keyword value="*{information}*列表,排序" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="点击列表中的*{condition}*列" />
<step id="2" value="再次点击列表中的*{condition}*列" />
<step id="3" value="当*{condition}*列为空时,对该列排序" />
</steps>
<expectations>
<expectation id="1" value="列表中的数据按照所选的项目进行某种规律的排序"/>
<expectation id="2" value="列表中的数据按照第一步相反的顺序排序"/>
<expectation id="3" value="列表中的数据排序不变"/>
</expectations>
</case>
<case function="addExportListCase">
<title value="导出*{information}*列表的数据" />
<keyword value="*{information}*列表,导出" />
<rank value="1" />
<preconditions>
<precondition value="列表中有信息存在" />
</preconditions>
<steps>
<step id="1" value="在列表上有数据的情况下点击“导出”按钮" />
<step id="2" value="在列表上勾选一条数据,点击“导出”按钮" />
<step id="3" value="在列表上勾选多条数据,点击“导出”按钮" />
<step id="4" value="不勾选列表上的数据,点击“导出”按钮" />
<step id="5" value="在列表上无数据的情况下点击“导出”按钮" />
</steps>
<expectations>
<expectation id="1" value="能导出文件,且文件上显示的信息与列表上的信息保持一致"/>
<expectation id="2" value="能导出文件,导出的文件中只有勾选的*{information}*信息且文件上显示的信息与列表上的信息保持一致"/>
<expectation id="3" value="能导出文件,导出的文件中只有勾选的*{information}*信息且文件上显示的信息与列表上的信息保持一致"/>
<expectation id="4" value="导出的文件中有所有的*{information}*信息且文件上显示的信息与列表上的信息保持一致"/>
<expectation id="5" value="若能导出相应的文件,则文件中只有表格的表头,无其他数据;若不能导出,则给出相应的提示"/>
</expectations>
</case>
<case function="addImportListCase">
<title value="导入*{information}*列表的数据" />
<keyword value="*{information}*列表,导入" />
<rank value="1" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="按照模版正确的输入信息后,导入" />
<step id="2" value="在模版中部分必填信息不输入或信息错误输入,导入" />
<step id="3" value="导入非模版文件" />
</steps>
<expectations>
<expectation id="1" value="信息导入成功,能在列表上看到新导入的帐号信息"/>
<expectation id="2" value="信息导入失败,并给出相应的提示"/>
<expectation id="3" value="信息导入失败,并给出相应的提示"/>
</expectations>
</case>
<case function="addResetSearchCase">
<title value="重置搜索" />
<keyword value="重置,搜索" />
<rank value="1" />
<preconditions>
<precondition value="已对列表进行搜索" />
</preconditions>
<steps>
<step id="1" value="先对列表进行一次搜索,之后点击重置按钮" />
</steps>
<expectations>
<expectation id="1" value="所有的搜索条件回到初次进入界面的状态,且列表中的数据也被还原"/>
</expectations>
</case>
<case function="addSwitchListShowDataCase">
<title value="修改列表每页显示的数据量" />
<keyword value="切换,数据量" />
<rank value="1" />
<preconditions>
<precondition value="列表中有多条数据存在,且能分页显示" />
</preconditions>
<steps>
<step id="1" value="选择分页下拉框的第一个选项" />
<step id="2" value="选择分页下拉框的最后一个选项" />
<step id="3" value="选择分页下拉框的非第一个和最后一个选项" />
<step id="4" value="在数据量较少的情况下选择一个较大的单页显示量如只有5条数据时选择单页显示20条数据" />
<step id="5" value="在列表无数据的情况下切换单页数据显示量" />
</steps>
<expectations>
<expectation id="1" value="列表中每页显示相应的数据量,且修改后不改变原数据的顺序"/>
<expectation id="2" value="列表中每页显示相应的数据量,且修改后不改变原数据的顺序"/>
<expectation id="3" value="列表中每页显示相应的数据量,且修改后不改变原数据的顺序"/>
<expectation id="4" value="列表中数据无变化,且顺序保持不变"/>
<expectation id="5" value="列表无任何变化"/>
</expectations>
</case>
</cases>

View File

@ -0,0 +1,106 @@
<?xml version="1.0" encoding="GBK"?>
<cases project="Map">
<case function="addRangeFindingCase">
<title value="在地图上进行测距" />
<keyword value="地图,测距" />
<rank value="3" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="设置画线的起点后拖动鼠标" />
<step id="2" value="在地图上画线后单击鼠标左键" />
<step id="3" value="在地图上画线后双击鼠标左键" />
<step id="4" value="停止画线后缩放地图" />
<step id="5" value="设置起点后直接双击左键" />
<step id="6" value="在不同的地图比例上画等长的线段" />
<step id="7" value="在画好的线段上,点击“×”按钮" />
</steps>
<expectations>
<expectation id="1" value="线随鼠标的移动而增长,且标注中显示的距离随鼠标的移动而改变"/>
<expectation id="2" value="还能继续画线测距,且标注中显示的距离应累加上一次定位的距离"/>
<expectation id="3" value="停止画线,且线段留在地图上"/>
<expectation id="4" value="线段随地图的缩放而改变其长度,且方框中的内容显示不变"/>
<expectation id="5" value="停止画线"/>
<expectation id="6" value="随地图缩放程度不同,其不同比例尺下画出的等长的线段在标注中显示的距离不同"/>
<expectation id="7" value="线段被清除"/>
</expectations>
</case>
<case function="addMapPointCase">
<title value="查看地图*{pointName}*定位点信息" />
<keyword value="地图,*{pointName}*,定位点" />
<rank value="2" />
<preconditions>
<precondition value="地图上有多个*{pointName}*定位点以及聚合点存在" />
</preconditions>
<steps>
<step id="1" value="在地图上点击*{pointName}*的定位点" />
<step id="2" value="在地图上点击*{pointName}*的聚合点" />
</steps>
<expectations>
<expectation id="1" value="能查看到该*{pointName}*的详细信息"/>
<expectation id="2" value="地图能自动缩放到能看到*{pointName}*定位点的比例"/>
</expectations>
</case>
<case function="addMapSearchInformationCase">
<title value="通过*{condition}*在地图上搜索*{name}*信息" />
<keyword value="地图,*{name}*,搜索" />
<rank value="1" />
<preconditions>
<precondition value="地图上有*{name}*信息存在" />
</preconditions>
<steps>
<step id="1" value="通过*{condition}*对*{name}*进行模糊搜索" />
<step id="2" value="通过*{condition}*对*{name}*进行精准搜索" />
<step id="3" value="不输入信息进行搜索" />
<step id="4" value="输入*{name}*中都不包含的关键词进行搜索" />
</steps>
<expectations>
<expectation id="1" value="地图上显示所有符合条件的*{name}*定位点"/>
<expectation id="2" value="地图上显示*{name}*对应的定位点"/>
<expectation id="3" value="地图界面保持不变"/>
<expectation id="4" value="提示无搜索结果"/>
</expectations>
</case>
<case function="addCarLocusPlaybackCase">
<title value="回放车辆轨迹" />
<keyword value="车辆轨迹" />
<rank value="1" />
<preconditions>
<precondition value="车辆有轨迹存在" />
</preconditions>
<steps>
<step id="1" value="查询到车辆的轨迹后点击回放或播放按钮" />
<step id="2" value="从最小的回放速度开始依次点击到最大的播放速度" />
<step id="3" value="在轨迹播放时点击播放按钮" />
<step id="4" value="在轨迹播放时点击暂停按钮,再点击回放按钮" />
<step id="5" value="在轨迹播放时点击停止按钮,再点击回放按钮" />
</steps>
<expectations>
<expectation id="1" value="地图上的车辆点以默认速度沿着轨迹在地图上移动"/>
<expectation id="2" value="车辆点的回放速度依次加快"/>
<expectation id="3" value="车辆点移动后不受任何影响,且在继续移动"/>
<expectation id="4" value="车辆点停止移动后又重新在停止的位置继续移动"/>
<expectation id="5" value="车辆点停止移动后又从起点开始重新移动"/>
</expectations>
</case>
<case function="addShowLocusCase">
<title value="地图上显示车辆轨迹点" />
<keyword value="车辆轨迹" />
<rank value="1" />
<preconditions>
<precondition value="车辆有轨迹存在" />
</preconditions>
<steps>
<step id="1" value="依次点击*{pointType}*" />
<step id="2" value="点击“清除轨迹”按钮" />
</steps>
<expectations>
<expectation id="1" value="地图上显示的车辆轨迹随点击的轨迹样式不同而变化"/>
<expectation id="2" value="地图上不再显示轨迹"/>
</expectations>
</case>
</cases>

View File

@ -0,0 +1,202 @@
<?xml version="1.0" encoding="GBK"?>
<cases project="Username">
<case function="addRightLoginCase">
<title value="通过正确的用户名与密码进行登录" />
<keyword value="正确的,用户名,密码,登录" />
<rank value="1" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="正确输入用户名及密码,登录" />
</steps>
<expectations>
<expectation id="1" value="能正常登录系统,且登陆后跳转的页面正确"/>
</expectations>
</case>
<case function="addErrorLoginCase">
<title value="通过非常规的用户名与密码进行登录" />
<keyword value="不正确的,用户名,密码,登录" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="输入一个不存在的用户名及密码,登录" />
<step id="2" value="输入一个存在的用户名但密码输入与其不对应,登录" />
<step id="3" value="不输入用户名,登录" />
<step id="4" value="不输入密码,登录" />
<step id="5" value="在用用户名与密码中输入中文或特殊字符,登录" />
</steps>
<expectations>
<expectation id="1" value="无法登录,并给出相应的提示"/>
<expectation id="2" value="无法登录,并给出相应的提示"/>
<expectation id="3" value="无法登录,并给出相应的提示"/>
<expectation id="4" value="无法登录,并给出相应的提示"/>
<expectation id="5" value="若带中文的用户名或密码能注册,则能正常登录系统,且登陆后跳转的页面正确;若不能注册,则无法登录,并给出相应的提示"/>
</expectations>
</case>
<case function="addCaptchaCase">
<title value="输入不同的验证码进行登录" />
<keyword value="验证码,登录" />
<rank value="1" />
<preconditions>
<precondition value="帐号和密码输入正确" />
</preconditions>
<steps>
<step id="1" value="正确输入验证码,登录" />
<step id="2" value="不输入验证码,登录" />
<step id="3" value="输入错误的验证码,登录" />
</steps>
<expectations>
<expectation id="1" value="能正常登录系统,且登陆后跳转的页面正确"/>
<expectation id="2" value="无法登录,并给出相应的提示"/>
<expectation id="3" value="无法登录,并给出相应的提示"/>
</expectations>
</case>
<case function="addLoginAuthorityCase">
<title value="通过不同权限的帐号进行登录" />
<keyword value="权限,登录" />
<rank value="1" />
<preconditions>
<precondition value="帐号和密码输入正确" />
</preconditions>
<steps>
<step id="1" value="输入不同权限的帐号和密码,登录" />
<step id="2" value="在所有登录页面上输入与之权限不对应的帐号,登录" />
</steps>
<expectations>
<expectation id="1" value="能正常登录系统,且登陆后能看到权限对应的页面及功能"/>
<expectation id="2" value="无法登录,并给出相应的提示"/>
</expectations>
</case>
<case function="addUsernameRegisterCase">
<title value="注册不同用户名的账号" />
<keyword value="用户名,注册" />
<rank value="1" />
<preconditions>
<precondition value="已在注册账号界面" />
<precondition value="除用户名外,其他信息均正确填写" />
</preconditions>
<steps>
<step id="1" value="通过一个未被注册且正确的用户名进行注册操作" />
<step id="2" value="通过一个已注册的用户名进行注册操作" />
<step id="3" value="输入一个大于11位的数字字符进行注册操作" />
<step id="4" value="输入一个小于11位的数字字符进行注册操作" />
<step id="5" value="输入非数字字符进行注册操作" />
<step id="6" value="通过一个不符合要求的用户名进行注册操作" />
<step id="7" value="不输入用户名进行注册操作" />
</steps>
<expectations>
<expectation id="1" value="注册完成后能通过该帐号及对应的密码进行登录"/>
<expectation id="2" value="提示用户名已存在"/>
<expectation id="3" value="提示用户名不合理"/>
<expectation id="4" value="提示用户名不合理"/>
<expectation id="5" value="提示用户名不合理"/>
<expectation id="6" value="提示用户名不合理"/>
<expectation id="7" value="提示请输入用户名"/>
</expectations>
</case>
<case function="addUsernameForgetCase">
<title value="通过不同用户名的账号进行忘记密码操作" />
<keyword value="用户名,忘记密码" />
<rank value="1" />
<preconditions>
<precondition value="已在忘记密码界面" />
<precondition value="除用户名外,其他信息均正确填写" />
</preconditions>
<steps>
<step id="1" value="通过一个已存在且正确的用户名进行忘记密码操作" />
<step id="2" value="通过一个不存在的用户名进行忘记密码操作" />
<step id="3" value="通过一个不符合要求的用户名进行忘记密码操作" />
<step id="4" value="不输入用户名进行忘记密码操作" />
</steps>
<expectations>
<expectation id="1" value="密码修改成功,并且可以使用该帐号及修改的密码进行登录操作"/>
<expectation id="2" value="提示用户名不存在"/>
<expectation id="3" value="提示用户名不合理"/>
<expectation id="4" value="提示请输入用户名"/>
</expectations>
</case>
<case function="addPasswordRegisterOrForgetCase">
<title value="通过不同的密码进行*{operation}*操作" />
<keyword value="密码,*{operation}*" />
<rank value="1" />
<preconditions>
<precondition value="已在*{operation}*账号界面" />
<precondition value="除密码外,其他信息均正确填写" />
</preconditions>
<steps>
<step id="1" value="通过正确的密码进行*{operation}*操作" />
<step id="2" value="通过一个不符合要求的密码进行*{operation}*操作" />
<step id="3" value="不输入密码进行*{operation}*操作" />
<step id="4" value="不再次输入密码,*{operation}*操作" />
<step id="5" value="两次密码输入不一致后进行*{operation}*操作" />
</steps>
<expectations>
<expectation id="1" value="*{operation}*操作完成后能通过该帐号及对应的密码进行登录"/>
<expectation id="2" value="提示密码不合理"/>
<expectation id="3" value="提示请输入密码"/>
<expectation id="4" value="提示两次密码输入不一致或者提示输入确认密码"/>
<expectation id="5" value="提示两次密码输入不一致"/>
</expectations>
</case>
<case function="addCodeRegisterOrForgetCase">
<title value="通过不同的验证码进行*{operation}*操作" />
<keyword value="验证码,*{operation}*" />
<rank value="1" />
<preconditions>
<precondition value="已在*{operation}*账号界面" />
<precondition value="除密码外,其他信息均正确填写" />
</preconditions>
<steps>
<step id="1" value="通过正确的验证码进行*{operation}*" />
<step id="2" value="通过一个不正确的验证码进行*{operation}*" />
<step id="3" value="不输入验证码进行*{operation}*" />
<step id="4" value="重新发送验证码后输入上一次的验证码" />
<step id="5" value="重新发送验证码后输入新的验证码" />
<step id="6" value="超过验证码的过期时间后再输入验证码,*{operation}*" />
</steps>
<expectations>
<expectation id="1" value="*{operation}*操作完成后能通过该帐号及对应的密码进行登录"/>
<expectation id="2" value="提示验证码不正确"/>
<expectation id="3" value="提示请输入验证码"/>
<expectation id="4" value="提示验证码输入有误"/>
<expectation id="5" value="*{operation}*操作完成后能通过该帐号及对应的密码进行登录"/>
<expectation id="6" value="提示验证码不正确"/>
</expectations>
</case>
<case function="addAlterPasswordCase">
<title value="修改用户密码" />
<keyword value="修改,密码" />
<rank value="1" />
<preconditions>
<precondition value="已登录系统" />
<precondition value="除密码外,其他信息均正确填写" />
</preconditions>
<steps>
<step id="1" value="正确输入原密码并按要求输入新密码后修改密码" />
<step id="2" value="输入错误的原密码后修改密码" />
<step id="3" value="不输入原密码进行修改密码" />
<step id="4" value="输入一个不符合要求的密码进行修改密码" />
<step id="5" value="不输入密码进行修改密码" />
<step id="6" value="不再次输入密码进行修改密码" />
<step id="7" value="两次密码输入不一致后进行修改密码" />
</steps>
<expectations>
<expectation id="1" value="修改密码成功,该帐号能通过新修改的密码进行登录"/>
<expectation id="2" value="提示用户原密码输入有误"/>
<expectation id="3" value="提示请输入原密码"/>
<expectation id="4" value="提示密码不合理"/>
<expectation id="5" value="提示请输入密码"/>
<expectation id="6" value="提示两次密码输入不一致或者提示输入确认密码"/>
<expectation id="7" value="提示两次密码输入不一致"/>
</expectations>
</case>
</cases>

View File

@ -0,0 +1,139 @@
<?xml version="1.0" encoding="GBK"?>
<cases project="Video">
<case function="addPlayVideoCase">
<title value="播放/暂停*{videoType}*" />
<keyword value="播放/暂停" />
<rank value="1" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="在*{videoType}*播放状态下点击播放按钮" />
<step id="2" value="在*{videoType}*播放状态下点击暂停按钮或单击*{videoType}*画面,再点击播放按钮" />
<step id="3" value="在*{videoType}*播放状态下点击停止按钮,再点击播放按钮" />
<step id="4" value="在*{videoType}*播放状态下点击暂停按钮,再点击停止按钮" />
<step id="5" value="在*{videoType}*播放状态下一直按住键盘上的空格按键" />
<step id="6" value="在*{videoType}*未播放状态下点击暂停、停止按钮" />
</steps>
<expectations>
<expectation id="1" value="*{videoType}*播放不受影响"/>
<expectation id="2" value="*{videoType}*暂停,*{videoType}*画面定格在按下按钮的瞬间,再次按下播放时*{videoType}*会从暂停的位置继续播放"/>
<expectation id="3" value="*{videoType}*停止,*{videoType}*画面定格在按下按钮的瞬间或画面消失,再次按下播放时*{videoType}*会重新播放"/>
<expectation id="4" value="*{videoType}*停止,*{videoType}*画面定格在按下按钮的瞬间或画面消失,再次按下播放时*{videoType}*会重新播放"/>
<expectation id="5" value="系统只执行一次按下空格按键的操作,或*{videoType}*在不断地暂停/播放,但页面不会崩溃"/>
<expectation id="6" value="*{videoType}*不会播放"/>
</expectations>
</case>
<case function="addVideoScreenshotCase">
<title value="对*{videoType}*进行截图" />
<keyword value="*{videoType}*,截图" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="在*{videoType}*播放状态下点击截图按钮" />
<step id="2" value="在*{videoType}*暂停状态下点击截图按钮" />
<step id="3" value="在*{videoType}*停止状态下点击截图按钮" />
<step id="4" value="在*{videoType}*未播放状态下点击截图按钮" />
</steps>
<expectations>
<expectation id="1" value="弹出截图成功提示,截图的画面是按下截图按钮瞬间的画面"/>
<expectation id="2" value="弹出截图成功提示,截图的画面是按下当前*{videoType}*的画面"/>
<expectation id="3" value="截图失败,弹出未保存或*{videoType}*未播放的提示"/>
<expectation id="4" value="截图失败,弹出未保存或*{videoType}*未播放的提示"/>
</expectations>
</case>
<case function="addVideoAdvanceCase">
<title value="快进/快退*{videoType}*" />
<keyword value="*{videoType}*,快进,快退" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="在*{videoType}*播放状态下点击快进或快退按钮" />
<step id="2" value="在*{videoType}*暂停状态下点击快进或快退按钮" />
<step id="3" value="在*{videoType}*刚开始播放时只播放1-2秒点击快退按钮" />
<step id="4" value="在*{videoType}*快结束时剩余1-2秒点击快进按钮" />
<step id="5" value="在*{videoType}*未播放状态下点击快进或快退按钮" />
<step id="6" value="一直按住键盘的右或左方向键" />
<step id="7" value="正常修改默认的跳跃秒数后点击快进或快退按钮" />
<step id="8" value="修改秒数为小于1的数字后点击快进或快退按钮" />
<step id="9" value="修改秒数为大于*{videoType}*剩余播放时间的数字后点击快进按钮" />
<step id="10" value="不输入秒数或输入非数字字符后点击快进或快退按钮" />
</steps>
<expectations>
<expectation id="1" value="*{videoType}*进度条向前或向后跳跃,*{videoType}*画面前进或后退对应的时间后继续播放"/>
<expectation id="2" value="*{videoType}*进度条向前或向后跳跃,*{videoType}*画面前进或后退对应的时间后仍暂停播放"/>
<expectation id="3" value="*{videoType}*重新播放"/>
<expectation id="4" value="*{videoType}*停止播放"/>
<expectation id="5" value="快进或快退无效"/>
<expectation id="6" value="进度条一直向前或向后跳跃,直至进度条到达端点时按住方向键将无效"/>
<expectation id="7" value="*{videoType}*跳跃相应的秒数"/>
<expectation id="8" value="提示跳跃秒数不允许小于1或者*{videoType}*不跳跃"/>
<expectation id="9" value="提示跳跃秒数不允许超过*{videoType}*的播放时间,或者*{videoType}*停止播放"/>
<expectation id="10" value="提示输入正确的数字,或者*{videoType}*不跳跃"/>
</expectations>
</case>
<case function="addVideoSpeedCase">
<title value="快放/慢放*{videoType}*" />
<keyword value="*{videoType}*,快放,慢放" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="在*{videoType}*播放状态下点击快放或慢放按钮" />
<step id="2" value="在*{videoType}*暂停状态下点击快放或慢放按钮" />
<step id="3" value="在*{videoType}*未播放状态下点击快放或慢放按钮" />
<step id="4" value="依次选择不同的倍率后,点击快放或慢放按钮" />
</steps>
<expectations>
<expectation id="1" value="*{videoType}*播放仍在播放,但其播放速度明显比默认播放速度快或慢"/>
<expectation id="2" value="*{videoType}*播放开始播放,但其播放速度明显比默认播放速度快或慢"/>
<expectation id="3" value="按钮点击无效"/>
<expectation id="4" value="*{videoType}*的播放速度较点击前的播放速度有明显的变化"/>
</expectations>
</case>
<case function="addVideoProgressBarCase">
<title value="拖动进度条" />
<keyword value="进度条" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="在*{videoType}*播放状态下向前或向后拖动进度条" />
<step id="2" value="在*{videoType}*暂停状态下向前或向后拖动进度条" />
<step id="3" value="在*{videoType}*未播放状态下点击快放或慢放按" />
<step id="4" value="停止画线后缩放地图" />
<step id="5" value="将进度条拉至端点后继续向同方向拉动" />
</steps>
<expectations>
<expectation id="1" value="*{videoType}*跳跃到进度条相对应的时间上继续播放"/>
<expectation id="2" value="*{videoType}*跳跃到进度条相对应的时间上仍暂停播放"/>
<expectation id="3" value="*{videoType}*跳从进度条相对应的时间上开始播放"/>
<expectation id="4" value="进度条不会超出端点"/>
</expectations>
</case>
<case function="addFullScreenPlayCase">
<title value="全屏播放*{videoType}*" />
<keyword value="全屏*{videoType}*" />
<rank value="2" />
<preconditions>
</preconditions>
<steps>
<step id="1" value="点击全屏播放按钮" />
<step id="2" value="双击*{videoType}*画面" />
<step id="3" value="再次双击*{videoType}*画面" />
<step id="4" value="点击退出全屏播放按钮" />
</steps>
<expectations>
<expectation id="1" value="*{videoType}*全屏播放"/>
<expectation id="2" value="*{videoType}*退出全屏播放"/>
<expectation id="3" value="*{videoType}*全屏播放"/>
<expectation id="4" value="*{videoType}*退出全屏播放"/>
</expectations>
</case>
</cases>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templet>
<fields type="Zendao">
<field name=""/>
</fields>
</templet>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="GBK"?>
<bug>
<projected name="泰滴项目">
<version version="0.22" time="20181019-20181019">
<one number="0"/>
<two number="3"/>
<three number="4"/>
<four number="1"/>
</version>
<version version="0.21" time="20181008-20181011">
<one number="0"/>
<two number="14"/>
<three number="32"/>
<four number="12"/>
</version>
<version version="0.17" time="20181027-20181105">
<one number="0"/>
<two number="0"/>
<three number="0"/>
<four number="0"/>
</version>
<version version="0.30" time="20190124-20190202">
<one number="0"/>
<two number="12"/>
<three number="27"/>
<four number="1"/>
</version>
</projected>
<projected name="隆安县公安局OA办公系统">
<version version="0.11" time="20181027-20181105">
<one number="0"/>
<two number="9"/>
<three number="13"/>
<four number="3"/>
</version>
</projected>
<projected name="隆安县公安局办公OA">
<version version="0.11" time="20181215-20181224">
<one number="0"/>
<two number="0"/>
<three number="0"/>
<four number="0"/>
</version>
<version version="0.12" time="20181105-20181105">
<one number="0"/>
<two number="0"/>
<three number="0"/>
<four number="0"/>
</version>
</projected>
<projected name="隆安县公安局OA办公APP">
<version version="0.7" time="20181125-20181204">
<one number="0"/>
<two number="0"/>
<three number="0"/>
<four number="0"/>
</version>
</projected>
<projected name="那坡县精准扶贫管理系统三期">
<version version="0.16" time="20181125-20181204">
<one number="1"/>
<two number="2"/>
<three number="3"/>
<four number="4"/>
</version>
<version version="0.17" time="20181125-20181204">
<one number="5"/>
<two number="6"/>
<three number="7"/>
<four number="8"/>
</version>
<version version="0.18" time="20181125-20181204">
<one number="2"/>
<two number="3"/>
<three number="4"/>
<four number="5"/>
</version>
<version version="0.19" time="20181125-20181204">
<one number="5"/>
<two number="2"/>
<three number="6"/>
<four number="9"/>
</version>
<version version="0.20" time="20181210-20181219">
<one number="0"/>
<two number="0"/>
<three number="0"/>
<four number="0"/>
</version>
</projected>
<projected name="新能源共享汽车后台管理系统">
<version version="1.1.3" time="20180106-20180110">
<one number="0"/>
<two number="0"/>
<three number="2"/>
<four number="0"/>
</version>
</projected>
</bug>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="GBK"?>
<!-- <!DOCTYPE CONFIGURATION SYSTEM "TestReportConfigurationDTD.dtd"> -->
<test type="Zentao">
<!-- 设置火狐浏览器的位置、配置文件的名称以及自动下载的文件保存的位置 -->
<firefox directory="" profiles="pyqone" download_save_directory="D:\下载内容\火狐下载\自动化下载\"/>
<!-- 设置禅道的访问地址 -->
<url url="http://116.10.187.227:88/zentao/user-login.html"/>
<!-- 设置进入禅道的用户名及密码 -->
<user username="pengyuqi" password="123456"/>
<!-- 设置通过搜索能得到的项目关键词,请保证通过该关键词搜索到的项目是唯一的 -->
<project name="汽车共享"/>
<!-- 设置测试报告的内容 -->
<report days="10" range="全面测试" download_file_name="1" print_name="HP LaserJet Professional M1216nfh MFP">
<!-- 设置测试人员属性participation表示是否参与 -->
<testperson>
<person name="彭宇琦" participation="true" mail="465615774@qq.com"/>
<person name="李健梅" participation="false" mail="1150327894@qq.com"/>
<person name="赵莉宽" participation="false" mail="1632262743@qq.com"/>
</testperson>
<!-- 设置测试报告内容,在自动发送邮件且需要更改测试报告内容时在此进行编辑,若无需自动发送邮件,可不更改此处内容 -->
<content>
<!-- 修改测试时间若自动生成的时间正确则设置is_change为false当其设置为true时则读取该标签的测试时间填入模版 -->
<!-- 时间的格式为yyyy.MM.dd例如“2018.4.23” -->
<time is_change="false">
<starttime>2018.5.4</starttime>
<endtime>2018.5.5</endtime>
</time>
<!-- 修改测试目的 -->
<purpose>
<step>验证版本的基本功能点</step>
<step>验证版本稳定性</step>
</purpose>
<!-- 修改测试依据,需要使用程序中的字段或参数时,请用${XXX}将其作为标记 -->
<gist>
<step>${name}软件需求规格说明书</step>
<step>${name}测试用例</step>
</gist>
</content>
</report>
<!-- 设置发送邮件的参数,邮箱信息,若无特殊要求,请勿更改此处内容 -->
<mail smtp="smtp.163.com" username="15877163862@163.com" password="Syh123456" name="彭宇琦">
<!-- 设置收信人 -->
<to project="隆安县公安局办公OA项目">
<person name="苏政彪" mail="492538422@qq.com" remark="技术经理"/>
<person name="梁增杰" mail="2839525326@qq.com" remark="项目经理"/>
</to>
<to project="隆安OA扶贫项目">
<person name="苏政彪" mail="492538422@qq.com" remark="技术经理"/>
<person name="梁增杰" mail="2839525326@qq.com" remark="项目经理"/>
</to>
<to project="那坡县精准扶贫管理系统三期">
<person name="董志伟" mail="272001838@qq.com" remark="技术经理"/>
<person name="蓝石玉" mail="395464985@qq.com" remark="项目经理"/>
</to>
<to project="泰滴项目">
<person name='彭沙为' mail='pyqone@outlook.com' remark='测试帐号1' />
<person name='濮蛤' mail='1097273754@qq.com' remark='测试帐号2' />
</to>
<to project="12320项目">
<person name="苏政彪" mail="492538422@qq.com" remark="技术经理"/>
<person name="吴琰堂" mail="9941126@qq.com" remark="运维科技术经理"/>
</to>
<!-- 设置抄送人,测试组人员可在程序中自动添加,此处则无需放入,若无特殊要求时,也请勿更改此处内容 -->
<!--
<cc>
<person name="刘勇" mail="390272048@qq.com" remark="软件部经理"/>
<person name="韦青权" mail="124055091@qq.com" remark="软件部副经理(兼开发科科长)"/>
<person name="彭宇琦" mail="465615774@qq.com" remark="品控科科长"/>
</cc>
-->
<!-- 测试帐号 -->
<cc>
<person name="奚夕木" mail="pyqone@163.com" remark="测试帐号4"/>
<person name="彭宇琦" mail="465615774@qq.com" remark="品控科科长"/>
</cc>
<addcontent></addcontent>
</mail>
</test>
<!--
<person name='彭沙为' mail='710557391@qq.com' remark='测试帐号1' />
<person name='濮蛤' mail='1097273754@qq.com' remark='测试帐号2' />
<person name='邴句弱' mail='pyqone@outlook.com' remark='测试帐号3' />
<person name='奚夕木' mail='pyqone@163.com' remark='测试帐号4' />
<person name='刘勇' mail='390272048@qq.com' remark='软件部经理' />
<person name='韦青权' mail='124055091@qq.com' remark='软件部副经理(兼开发科科长)' />
<person name='吴琰堂' mail='9941126@qq.com' remark='运维科技术经理' />
<person name='蓝石玉' mail='395464985@qq.com' remark='项目经理' />
<person name='梁增杰' mail='2839525326@qq.com' remark='项目经理' />
<person name='董志伟' mail='272001838@qq.com' remark='技术经理' />
<person name='苏政彪' mail='492538422@qq.com' remark='技术经理' />
<person name='甘露' mail='38432741@qq.com' remark='项目经理' />
-->

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT test (firefox,url,user,project,report,mail)>
<!ELEMENT firefox EMPTY>
<!ELEMENT url EMPTY>
<!ELEMENT user EMPTY>
<!ELEMENT project EMPTY>
<!ELEMENT report (testperson,content)>
<!ELEMENT person EMPTY>
<!ATTLIST firefox directory CDATA #IMPLIED>
<!ATTLIST firefox profiles CDATA #REQUIRED>
<!ATTLIST firefox download_save_directory CDATA #REQUIRED>
<!ATTLIST url url CDATA #REQUIRED>
<!ATTLIST user username CDATA #REQUIRED>
<!ATTLIST user password CDATA #REQUIRED>
<!ATTLIST project name CDATA #REQUIRED>
<!ATTLIST information days CDATA #REQUIRED>
<!ATTLIST information range CDATA #REQUIRED>
<!ATTLIST information download_file_name CDATA #REQUIRED>
<!ATTLIST person name CDATA #REQUIRED>
<!ATTLIST person participation CDATA #REQUIRED>

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="GBK"?>
<project name="ZendaoElementXpath">
<element name="用户名">
<xpath>//*[@name="account"]</xpath>
</element>
<element name="密码">
<xpath>//*[@name="password"]</xpath>
</element>
<element name="登录">
<xpath>//*[@id="submit"]</xpath>
</element>
<element name="测试">
<xpath>/html/body/header/nav[1]/ul/li[4]/a</xpath>
</element>
<element name="Bug">
<xpath>/html/body/header/nav[2]/ul/li[@data-id='bug']/a</xpath>
</element>
<element name="项目下拉框">
<xpath>/html/body/header/nav[2]/ul/li[1]/a</xpath>
</element>
<element name="项目搜索框">
<xpath>/html/body/header/nav[2]/ul/li[1]/div/input</xpath>
</element>
<element name="项目选项">
<xpath>/html/body/header/nav[2]/ul/li[1]/div/div/div[1]/ul/li/a</xpath>
</element>
<element name="所有">
<xpath>/html/body/div[1]/div[1]/div[2]/ul/li[3]/a</xpath>
</element>
<element name="ID">
<xpath>/html/body/div[1]/div[1]/div[4]/form/table/thead/tr/th[1]/div/a</xpath>
</element>
<element name="第一条Bug的ID">
<xpath>/html/body/div[1]/div[1]/div[4]/form/table/tbody/tr[1]/td[1]/a</xpath>
</element>
<element name="导出">
<xpath>/html/body/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]/button</xpath>
</element>
<element name="导出数据">
<xpath>/html/body/div[1]/div[1]/div[2]/div[1]/div[1]/div[1]/ul/li/a</xpath>
</element>
<element name="导出数据窗口">
<xpath>/html/body/div[3]/div[2]/div/div[2]/iframe</xpath>
</element>
<element name="文件名">
<xpath>/html/body/form/table/tbody/tr/td[1]/div/input</xpath>
</element>
<element name="文件格式下拉框">
<xpath>/html/body/form/table/tbody/tr/td[2]/select</xpath>
</element>
<element name="编码格式下拉框">
<xpath>/html/body/form/table/tbody/tr/td[3]/select</xpath>
</element>
<element name="记录下拉框">
<xpath>/html/body/form/table/tbody/tr/td[4]/select</xpath>
</element>
<!-- 禅道的导出按钮无法点击,故需要通过提交表单的方法来导出 -->
<element name="导出数据表单">
<xpath>/html/body/form</xpath>
</element>
</project>

View File

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<templet>
<sheet id="case" name="测试用例" freeze="3">
<column id="case_id" name="用例编号" wide="17" align="center" link="run:case_id"/>
<column id="module" name="所属模块" wide="25" 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"/>
</sheet>
<sheet id="run" name="运行记录" freeze="6" >
<column id="id" name="序号" wide="8" align="center"/>
<column id="case_id" name="用例编号" wide="17" align="center" link="case:case_id"/>
<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="error: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="bug_number" name="Bug数量" wide="10" align="center"/>
<column id="screenshot_position" name="截图位置" wide="25" align="center" link="run_screenshot:id"/>
<column id="use_time" name="执行耗时(s)" 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"/>
</sheet>
<sheet id="run_screenshot" 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="run:id"/>
<column id="screenshot" name="截图" wide="25" align="left" link="本地"/>
</sheet>
<sheet id="error" 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="run:id"/>
<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="error_screenshot:id"/>
</sheet>
<sheet id="error_screenshot" 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="error:id"/>
<column id="screenshot" name="截图" wide="25" align="left" link="本地"/>
</sheet>
</templet>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,203 @@
{
"id": "b109b5e98b68afe07bef4918da",
"class": "sheet",
"title": "画布 1",
"rootTopic": {
"id": "",
"class": "topic",
"title": "",
"structureClass": "org.xmind.ui.map.clockwise",
"customWidth": 388.33289802144977,
"extensions": [
{
"content": [
{
"content": "1",
"name": "right-number"
}
],
"provider": "org.xmind.ui.map.unbalanced"
}
]
},
"theme": {
"id": "d3983b42f1b90d4d50101b083f",
"importantTopic": {
"type": "topic",
"properties": {
"fo:font-weight": "bold",
"fo:color": "#434B54",
"svg:fill": "#FFEC00"
}
},
"minorTopic": {
"type": "topic",
"properties": {
"fo:font-weight": "bold",
"fo:color": "#434B54",
"svg:fill": "#FFA400"
}
},
"expiredTopic": {
"type": "topic",
"properties": {
"fo:font-style": "italic",
"fo:text-decoration": " line-through"
}
},
"centralTopic": {
"properties": {
"svg:fill": "#39BFC2",
"border-line-width": "5pt",
"border-line-color": "#CDE7EB",
"fo:color": "#F4F9FA",
"fo:font-family": "Times New Roman",
"fo:font-weight": "normal",
"fo:font-style": "italic",
"fo:font-size": "30pt",
"line-color": "#CDE7EB",
"line-class": "org.xmind.branchConnection.bight"
},
"styleId": "9c6b189e5ccbb87cd77a7830ae",
"type": "topic"
},
"floatingTopic": {
"properties": {
"svg:fill": "#39BFC2",
"line-width": "2px",
"line-class": "org.xmind.branchConnection.bight"
},
"styleId": "eadb271f6bba50b5b834c9836c",
"type": "topic"
},
"mainTopic": {
"properties": {
"svg:fill": "none",
"fo:color": "#39BFC2",
"fo:font-family": "Times New Roman",
"fo:font-weight": "normal",
"fo:font-size": "18pt",
"fo:text-align": "center",
"line-width": "2pt",
"line-class": "org.xmind.branchConnection.bight",
"border-line-width": "0"
},
"styleId": "8c8befaca46add0bbd37485296",
"type": "topic"
},
"subTopic": {
"properties": {
"fo:font-family": "Times New Roman",
"fo:font-weight": "normal",
"shape-class": "org.xmind.topicShape.roundedRect",
"svg:fill": "none",
"border-line-width": "0",
"fo:color": "#8793A5",
"fo:text-align": "left",
"line-class": "org.xmind.branchConnection.bight",
"line-color": "#CDE7EB"
},
"styleId": "bd4b3b9be19b419c650599c59b",
"type": "topic"
},
"summary": {
"type": "summary",
"properties": {
"line-width": "1px",
"shape-class": "org.xmind.summaryShape.curly"
}
},
"summaryTopic": {
"properties": {
"svg:fill": "#39BFC2",
"line-class": "org.xmind.branchConnection.bight"
},
"styleId": "4f7943898688787bc8037b38b1",
"type": "topic"
},
"boundary": {
"properties": {
"line-color": "#267D81",
"fo:color": "#FFFFFF"
},
"styleId": "0b6bc0207299eca8537d9affd8",
"type": "boundary"
},
"relationship": {
"properties": {
"line-color": "#267D81"
},
"styleId": "236b59db2f9818d5a010a9d869",
"type": "relationship"
},
"map": {
"properties": {
"line-tapered": "tapered",
"svg:fill": "#F4F9FA"
},
"styleId": "c9c904312f6968e676f4fafd22",
"type": "map"
}
},
"topicPositioning": "free",
"relationships": [
{
"id": "f0bc043c-671a-49a9-811e-1140cffdb7cd",
"end1Id": "960ad385-0c18-493d-9b37-1388c69e8c60",
"end2Id": "5329e7f1-33f4-4b00-8386-fb369cd3ec66",
"controlPoints": {
"0": {
"x": 764.1495997023039,
"y": -26.164953617783909
},
"1": {
"x": 2028.1260057364903,
"y": 27.56399207932236
}
},
"titleUnedited": true
},
{
"id": "7f1a995f-4dbc-40ac-9d0e-9c5a327c01a0",
"end1Id": "a1d8d2d4-a3f9-406d-9304-2ea8ffea6306",
"end2Id": "f97a529b-44cd-4374-a9d9-58998efda10f",
"controlPoints": {
"0": {
"x": 522.7298780505266,
"y": 1.9739065068178548
},
"1": {
"x": 694.7075962998249,
"y": -1.9739065068178548
}
},
"titleUnedited": true
},
{
"id": "28853890-b223-4dd8-8471-594ae4002034",
"end1Id": "7f609811-fa0f-4752-8a3b-d0f07927ddfd",
"end2Id": "8e6d91f7-146a-4e48-baba-1c687b9f64b4",
"controlPoints": {
"0": {
"x": 393.58217786594039,
"y": -2.8936990505694668
},
"1": {
"x": 423.60532213405966,
"y": -4.918800949430505
}
},
"titleUnedited": true
}
],
"legend": {
"visibility": "hidden"
},
"topicOverlapping": "overlap",
"style": {
"id": "13694d6b-0f40-4e88-89c0-27705cb9e249",
"properties": {
"multi-line-colors": "#5BD4FF #38B2FF #2589E5 #005FA2 #253777 #14235A"
}
}
}

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><xmap-content xmlns="urn:xmind:xmap:xmlns:content:2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" modified-by="bruce" timestamp="1503058545540" version="2.0"><sheet id="7abtd0ssc7n4pi1nu6i7b6lsdh" modified-by="bruce" theme="0kdeemiijde6nuk97e4t0vpp54" timestamp="1503058545540"><topic id="1vr0lcte2og4t2sopiogvdmifc" modified-by="bruce" structure-class="org.xmind.ui.logic.right" timestamp="1503058545417"><title>Warning
警告
Attention
Warnung
경고</title><children><topics type="attached"><topic id="71h1aip2t1o8vvm0a41nausaar" modified-by="bruce" timestamp="1503058545423"><title svg:width="500">This file can not be opened normally, please do not modify and save, otherwise the contents will be permanently lost</title><children><topics type="attached"><topic id="428akmkh9a0tog6c91qj995qdl" modified-by="bruce" timestamp="1503058545427"><title>You can try using XMind 8 Update 3 or later version to open</title></topic></topics></children></topic><topic id="2kb87f8m38b3hnfhp450c7q35e" modified-by="bruce" timestamp="1503058545434"><title svg:width="500">该文件无法正常打开,请勿修改并保存,否则文件内容将会永久性丢失!</title><children><topics type="attached"><topic id="3m9hoo4a09n53ofl6fohdun99f" modified-by="bruce" timestamp="1503058545438"><title>你可以尝试使用 XMind 8 Update 3 或更新版本打开</title></topic></topics></children></topic><topic id="7r3r4617hvh931ot9obi595r8f" modified-by="bruce" timestamp="1503058545444"><title svg:width="500">該文件無法正常打開,請勿修改並保存,否則文件內容將會永久性丟失!</title><children><topics type="attached"><topic id="691pgka6gmgpgkacaa0h3f1hjb" modified-by="bruce" timestamp="1503058545448"><title>你可以嘗試使用 XMind 8 Update 3 或更新版本打開</title></topic></topics></children></topic><topic id="0f2e3rpkfahg4spg4nda946r0b" modified-by="bruce" timestamp="1503058545453"><title svg:width="500">この文書は正常に開かないので、修正して保存しないようにしてください。そうでないと、書類の内容が永久に失われます。!</title><children><topics type="attached"><topic id="4vuubta53ksc1falk46mevge0t" modified-by="bruce" timestamp="1503058545457"><title>XMind 8 Update 3 や更新版を使って開くこともできます</title></topic></topics></children></topic><topic id="70n9i4u3lb89sq9l1m1bs255j5" modified-by="bruce" timestamp="1503058545463"><title svg:width="500">Datei kann nicht richtig geöffnet werden. Bitte ändern Sie diese Datei nicht und speichern Sie sie, sonst wird die Datei endgültig gelöscht werden.</title><children><topics type="attached"><topic id="1qpc5ee298p2sqeqbinpca46b7" modified-by="bruce" timestamp="1503058545466"><title svg:width="500">Bitte versuchen Sie, diese Datei mit XMind 8 Update 3 oder später zu öffnen.</title></topic></topics></children></topic><topic id="4dmes10uc19pq7enu8sc4bmvif" modified-by="bruce" timestamp="1503058545473"><title svg:width="500">Ce fichier ne peut pas ouvert normalement, veuillez le rédiger et sauvegarder, sinon le fichier sera perdu en permanence. </title><children><topics type="attached"><topic id="5f0rivgubii2launodiln7sdkt" modified-by="bruce" timestamp="1503058545476"><title svg:width="500">Vous pouvez essayer d'ouvrir avec XMind 8 Update 3 ou avec une version plus récente.</title></topic></topics></children></topic><topic id="10pn1os1sgfsnqa8akabom5pej" modified-by="bruce" timestamp="1503058545481"><title svg:width="500">파일을 정상적으로 열 수 없으며, 수정 및 저장하지 마십시오. 그렇지 않으면 파일의 내용이 영구적으로 손실됩니다!</title><children><topics type="attached"><topic id="0l2nr0fq3em22rctapkj46ue58" modified-by="bruce" timestamp="1503058545484"><title svg:width="500">XMind 8 Update 3 또는 이후 버전을 사용하여</title></topic></topics></children></topic></topics></children><extensions><extension provider="org.xmind.ui.map.unbalanced"><content><right-number>-1</right-number></content></extension></extensions></topic><title>Sheet 1</title></sheet></xmap-content>

View File

@ -0,0 +1 @@
{"file-entries":{"content.json":{},"metadata.json":{},"Thumbnails/thumbnail.png":{}}}

View File

@ -0,0 +1 @@
{"creator":{"name":"Vana","version":"9.2.1.201906120058"}}

BIN
lib/beautyeye_lnf.jar Normal file

Binary file not shown.

BIN
lib/commons-codec-1.10.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/commons-logging-1.2.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/csv/opencsv-4.1.jar Normal file

Binary file not shown.

BIN
lib/curvesapi-1.04.jar Normal file

Binary file not shown.

BIN
lib/dom4j-1.6.1.jar Normal file

Binary file not shown.

BIN
lib/javax.mail-1.6.1.jar Normal file

Binary file not shown.

BIN
lib/jaxen-1.1-beta-6.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/jfreechart/servlet.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/junit-4.12.jar Normal file

Binary file not shown.

BIN
lib/log4j-1.2.17.jar Normal file

Binary file not shown.

BIN
lib/opencsv-4.1.jar Normal file

Binary file not shown.

BIN
lib/poi-3.17.jar Normal file

Binary file not shown.

BIN
lib/poi-examples-3.17.jar Normal file

Binary file not shown.

BIN
lib/poi-excelant-3.17.jar Normal file

Binary file not shown.

BIN
lib/poi-ooxml-3.17.jar Normal file

Binary file not shown.

Binary file not shown.

BIN
lib/poi-scratchpad-3.17.jar Normal file

Binary file not shown.

BIN
lib/print/jacob.jar Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
lib/stax-api-1.0.1.jar Normal file

Binary file not shown.

BIN
lib/xmlbeans-2.3.0.jar Normal file

Binary file not shown.

105
pom.xml Normal file
View File

@ -0,0 +1,105 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>pres.appnium.test</groupId>
<artifactId>Autest</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Autest</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.141.0</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>4.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>1.1-beta-6</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.jfree</groupId>
<artifactId>jfreechart</artifactId>
<version>1.0.19</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>com.hynnet</groupId>
<artifactId>jacob</artifactId>
<version>1.14.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.0.2</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,38 @@
package pres.auxiliary.directory.exception;
/**
* 该异常为传入的文件夹路径不正确时抛出的异常继承RuntimeException
* @author 彭宇琦
* @version Ver1.0
*/
public class IncorrectDirectoryException extends RuntimeException {
private static final long serialVersionUID = 1L;
public IncorrectDirectoryException() {
super();
// TODO Auto-generated constructor stub
}
public IncorrectDirectoryException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IncorrectDirectoryException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IncorrectDirectoryException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IncorrectDirectoryException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,38 @@
package pres.auxiliary.directory.exception;
/**
* 该异常在未指定文件路径或者文件名时抛出的异常继承RuntimeException
*
* @author 彭宇琦
* @version Ver1.0
*/
public class UndefinedDirectoryException extends RuntimeException {
private static final long serialVersionUID = 1L;
public UndefinedDirectoryException() {
super();
// TODO Auto-generated constructor stub
}
public UndefinedDirectoryException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public UndefinedDirectoryException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public UndefinedDirectoryException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public UndefinedDirectoryException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,233 @@
package pres.auxiliary.directory.operate;
import java.io.File;
import pres.auxiliary.directory.exception.IncorrectDirectoryException;
import pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface.AddSeparatorProcessor;
import pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface.FormatSeparatorProcessor;
import pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface.RelativeToAbsoluteProcessor;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
/**
* 该类为创建文件工具类通过该类可辅助创建文件
*
* @author Administrator
*
*/
public class MakeDirectory {
// 该属性用于存储文件的路径字符串
private static StringBuilder savePath = new StringBuilder("C:\\AutoTest\\");
/**
* 私有构造禁止创建对象
*/
private MakeDirectory() {
}
/**
* 该方法用于返回文件定位的路径
*
* @return 返回在类中存储的文件路径
*/
public static String getSavePath() {
return savePath.toString();
}
/**
* 用于设置文件夹的根路径
*
* @param savePath
* 传入的新文件夹目录
*/
public static void setSavePath(String savePath) {
// 将传入的参数进行格式化
StringBuilder sb = new StringBuilder(savePath);
sb = formatPath(sb);
// 判断格式化后的文件路径格式是否符合windonws下文件路径的命名规则,不符合则抛出异常
if (!isPath(sb.toString())) {
System.out.println(sb.toString());
throw new IncorrectDirectoryException("不合理的文件夹路径,文件路径:"
+ sb.toString());
}
// 判断传入的路径是否只是硬盘的根目录若是则加上AutoTest文件夹
if (isDisk(sb.toString())) {
// 判断传入的硬盘根目录中是否包含文件夹分隔符\\若不包含则在后面加上
if (sb.indexOf("\\") < 0) {
sb.append("\\");
}
// 补上AutoTest文件夹
sb.append("AutoTest\\");
}
// 将文件路径设置入属性中
MakeDirectory.savePath = sb;
}
/**
* 该方法用于判断传入的路径输入是否正确
*
* @param path
* 传入的文件路径
* @return 返回路径是否正确
*/
public static boolean isPath(String path) {
// 判断path是否为空为空则返回false
if (path == null) {
return false;
}
// 判断path的内容是否为空为空则返回false
if ("".equals(path)) {
return false;
}
// 判断path中的内容是否为满足路径的要求不满足则返回false
// 可匹配相对路径和绝对路径
// 正则中只检测windows下创建文件夹或文件时不允许输入的字符
if (!path.matches("^([A-z]:\\\\)?([^ :\\*\\?<\">|\\/\\\\]+?(\\\\)?)*$")) {
return false;
}
// 若能满足上述条件则返回true
return true;
}
/**
* 该方法用于判断传入的参数是否符合在windows下文件名的命名规则不判断后缀名
*
* @param fileName
* 传入的待判断的文件夹名称
* @return 返回判断的结果
*/
public static boolean isFileName(String fileName) {
// 判断path是否为空为空则返回false
if (fileName == null) {
return false;
}
// 判断path的内容是否为空为空则返回false
if ("".equals(fileName)) {
return false;
}
// 通过正则判断文件名中是否包含windows不允许输入的特殊字符并匹配在传入的文件名中是否至少包含一个.若符合正则则返回true
if (fileName.matches("^([^:\\*\\?<\">|\\/\\\\])+?$")) {
return true;
}
// 若未通过判断则返回false
return false;
}
/**
* 该方法用于判断路径是否是硬盘的根目录
*
* @param path
* 传入的路径
* @return 返回判断的结果
*/
public static boolean isDisk(String path) {
// 判断path是否为空为空则返回false
if (path == null) {
return false;
}
// 判断path的内容是否为空为空则返回false
if ("".equals(path)) {
return false;
}
// 匹配只有盘符时的正则
if (path.matches("^[A-z]:(\\\\)?$")) {
return true;
}
// 若未通过判断则返回false
return false;
}
/**
* 该方法将对传入文件路径进行三种处理
* <ol>
* <li>将所有的分隔符/改为\\</li>
* <li>末尾未添加分隔符的加上\\</li>
* <li>将传入的相对路径改为绝对路径</li>
* </ol>
*
* @param path
* 传入的文件路径为StringBuilder对象
* @return 返回格式化后的路径为StringBuilder对象
*/
public static StringBuilder formatPath(StringBuilder path) {
// 创建处理链
ProcessorChain pc = new ProcessorChain();
// 添加处理器
pc.add(new FormatSeparatorProcessor());
pc.add(new RelativeToAbsoluteProcessor());
pc.add(new AddSeparatorProcessor());
// 返回格式化后的路径
return pc.doProcessor(path, pc);
}
/**
* 该方法用于创建使用辅助包时需要创建的文件夹
*/
public static void createAllFolder() {
// TODO 创建日志文件
// 创建文件夹先判断文件夹是否已被创建未被创建则创建文件夹
// 创建根文件夹
File f = new File(savePath.toString());
if (!f.exists()) {
f.mkdir();
}
// 创建存放测试报告的文件夹
f = new File(savePath.toString() + "Report");
if (!f.exists()) {
f.mkdir();
}
// 创建存放Bug汇总表的文件夹
f = new File(savePath.toString() + "BugSummarySheet");
if (!f.exists()) {
f.mkdir();
}
// 创建存放自动化运行结果的文件夹
f = new File(savePath.toString() + "Selenium");
if (!f.exists()) {
f.mkdir();
}
// 创建存放自动化运行结果截图的文件夹
f = new File(savePath.toString() + "Selenium\\Screenshot");
if (!f.exists()) {
f.mkdir();
}
// 创建存放自动化运行结果日志的文件夹
f = new File(savePath.toString() + "Selenium\\Log");
if (!f.exists()) {
f.mkdir();
}
// 创建存放待测页面定位方式的xml文件的文件夹
f = new File(savePath.toString() + "Xml");
if (!f.exists()) {
f.mkdir();
}
// 创建存放生成的测试用例文件的文件夹
f = new File(savePath.toString() + "Case");
if (!f.exists()) {
f.mkdir();
}
// 创建存放浏览器下载的文件的文件夹
f = new File(savePath.toString() + "BrowersDownload");
if (!f.exists()) {
f.mkdir();
}
}
}

View File

@ -0,0 +1,29 @@
package pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
import pres.auxiliary.directory.processor.directoryprocessor.processorinterface.ProcessorInterface;
/**
* 该处理器用于判断路径末尾是否含有分隔符\\若不包含则添加上
* @author 彭宇琦
* @version Ver1.0
*/
public class AddSeparatorProcessor implements ProcessorInterface {
@Override
public StringBuilder doProcessor(StringBuilder path, ProcessorChain chain) {
// 判断字符串的最后一位是否为含分隔符若不为分隔符则说明路径末尾没有分隔符则说明文件路径的末尾不含\\需要再添加
if (path.lastIndexOf("\\") != (path.length() - 1)) {
path.append("\\");
}
chain.doProcessor(path, chain);
// 返回文件路径
return path;
}
@Override
public String toString() {
return "AddSeparatorProcessor";
}
}

View File

@ -0,0 +1,46 @@
package pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
import pres.auxiliary.directory.processor.directoryprocessor.processorinterface.ProcessorInterface;
/**
* 该类用于对传入的文件路径进行文件夹分隔符格式化的处理处理的方法是将所有的分隔符/改为\\
*
* @author 彭宇琦
* @version Ver1.0
*/
public class FormatSeparatorProcessor implements ProcessorInterface {
@Override
public StringBuilder doProcessor(StringBuilder path, ProcessorChain chain) {
// 用于存储循环查询字符串得到的下标
int i = 0;
// 循环查询path中的/并将/字符改为\\
while (true) {
// 判断字符串查询到的字符串是否为/若为/则修改
if ((i = path.indexOf("/")) > -1) {
// 删除当前字符
path.delete(i, i + 1);
// 将字符\\插入到删除的位置由于需要转译\\在存储时应为\\\\
path.insert(i, "\\");
// 继续循环
continue;
}
// 若未找到字符/则结束循环
break;
}
chain.doProcessor(path, chain);
// 返回格式化后的路径
return path;
}
@Override
public String toString() {
return "FormatSeparatorProcessor";
}
}

View File

@ -0,0 +1,31 @@
package pres.auxiliary.directory.processor.directoryprocessor.impprocessorinterface;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
import pres.auxiliary.directory.processor.directoryprocessor.processorinterface.ProcessorInterface;
/**
* 该处理器用于将相对路径改为绝对路径判断相对路径的依据是路径中是否包含字符:
* 相对路径中不可能还含有字符:windows下不允许创建带:的字符故若路径
* 中含有:则说明路径为绝对路径<br/><br/>
* <i><b>注意使用该处理器时需要保证相对路径的命名正确</b></i>
* @author 彭宇琦
* @version Ver1.0
*/
public class RelativeToAbsoluteProcessor implements ProcessorInterface {
@Override
public StringBuilder doProcessor(StringBuilder path, ProcessorChain chain) {
// 判断传入的路径是绝对路径还是相对路径若是相对路径则在相对路径前加上当前位置
if (path.indexOf(":") < 0) {
path.insert(0, (System.getProperty("user.dir") + "\\"));
}
chain.doProcessor(path, chain);
return path;
}
@Override
public String toString() {
return "RelativeToAbsoluteProcessor";
}
}

View File

@ -0,0 +1,171 @@
package pres.auxiliary.directory.processor.directoryprocessor.processorchain;
import java.util.ArrayList;
import java.util.List;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
import pres.auxiliary.directory.processor.directoryprocessor.processorinterface.ProcessorInterface;
public class ProcessorChain implements ProcessorInterface {
//用于存储处理方法的类对象
private List<ProcessorInterface> processorChain = new ArrayList<>();
//用于记录调用的处理器在processorChain中的下标
private int index = -1;
/**
* 该构造方法不做任何处理
*/
public ProcessorChain() {
}
/**
* 该构造方法用于向处理链中添加一条或多条处理器
* @param processor 待添加的处理器
*/
public ProcessorChain(ProcessorInterface... processor) {
//循环向集合中添加处理器
for ( ProcessorInterface p : processor ) {
add(p);
}
}
/**
* 该方法用于向处理器链末尾添加一个处理器
* @param processor 待添加的处理器
* @return 返回添加状态
*/
public boolean add(ProcessorInterface processor) {
return processorChain.add(processor);
}
/**
* 该方法用于向处理器链指定位置添加一个处理器
* @param index 指定的处理器链位置
* @param processor 待添加的处理器
*/
public void add(int index, ProcessorInterface processor) {
processorChain.add(index, processor);
}
/**
* 该方法用于向处理器链末尾添加一组处理器
* @param processors 待添加的处理器组
* @return 返回添加状态
*/
public boolean addAll(List<ProcessorInterface> processors) {
return processorChain.addAll(processors);
}
/**
* 该方法用于向处理器链指定位置添加一组处理器
* @param index 指定的处理器链位置
* @param processors 待添加的处理器组
* @return 返回添加状态
*/
public boolean addAll(int index, List<ProcessorInterface> processors) {
return processorChain.addAll(index, processors);
}
/**
* 该方法用于移除指定位置的处理器
* @param index 指定的位置
* @return 返回被移除的处理器
*/
public ProcessorInterface remove(int index) {
return processorChain.remove(index);
}
/**
* 该方法用于移除指定的处理器
* @param processor 指定的处理器
* @return 返回被移除的处理器
*/
public boolean remove(ProcessorInterface processor) {
return processorChain.remove(processor);
}
/**
* 该方法用于返回指定位置的处理器
* @param index 指定的处理器位置
* @return 返回对应位置的处理器
*/
public ProcessorInterface get(int index) {
return processorChain.get(index);
}
/**
* 该方法用于替换指定位置的处理器
* @param index 指定的处理器位置
* @param processor 待替换的处理器
* @return 返回原处理器
*/
public ProcessorInterface set(int index, ProcessorInterface processor) {
return processorChain.set(index, processor);
}
/**
* 该方法用于返回处理链的长度
* @return 处理链的长度
*/
public int size() {
return processorChain.size();
}
/**
* 该方法通过传入的处理器名称来查找处理链中是否存在该处理器存在则返回对应
* 的下标不存在则返回-1调用该方法时需要处理器重写的toString()方法是输出类名的
* @param processorName 待搜索的处理器名称
* @return 对应的下标或者-1
*/
public int indexOf(String processorName) {
//循环遍历数组
for (int i = 0; i < processorChain.size(); i++) {
//判断每一个元素的toSting()方法得到的字符串是否存在与传入的参数相同忽略大小写若有相同则返回相应的下标
if ( processorChain.get(i).toString().equalsIgnoreCase(processorName) ) {
return i;
}
}
//循环结束则表示未找到对应的处理器则返回-1
return -1;
}
/**
* 该方法通过传入处理器类对象来来查找处理链中是否存在该处理器存在则返回对应的下标不存在则返回-1
* @param processor 传入的处理器类对象
* @return 对应的下标或者-1
*/
public int indexOf(ProcessorInterface processor) {
return processorChain.indexOf(processor);
}
/**
* 用于对所有的处理器进行处理
* @param 传入的文件路径
* @return 返回处理后的路径
*/
@Override
public StringBuilder doProcessor(StringBuilder path, ProcessorChain chain) {
//下标向前移动
index++;
if ( index == chain.size() ) {
return null;
}
//调用处理器的doProcessor()对象
processorChain.get(index).doProcessor(path, chain);
//返回处理后的文件路径
return path;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder("ProcessorChain [ ");
for ( ProcessorInterface p : processorChain ) {
s.append(p.toString());
s.append(" ");
}
s.append("]");
return s.toString();
}
}

View File

@ -0,0 +1,26 @@
package pres.auxiliary.directory.processor.directoryprocessor.processorinterface;
import pres.auxiliary.directory.processor.directoryprocessor.processorchain.ProcessorChain;
/**
* 该接口定义处理传入的文件路径的方法
*
* @author 彭宇琦
* @version Ver1.0
*/
public interface ProcessorInterface {
/**
* 该方法用于处理传入的文件路径
*
* @param path
* 指定的文件路径
* @return 返回处理后的文件路径
*/
public abstract StringBuilder doProcessor(StringBuilder path, ProcessorChain chain);
/**
* 重写toString()方法用于输出类名
* */
@Override
public abstract String toString();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
package pres.auxiliary.report;
import java.io.File;
import java.io.IOException;
public class AutoTestReport extends AbstractReport implements ReportInter {
/**
* 该构造只用于创建对象
*/
public AutoTestReport() {
}
/**
* 该构造方法用于设置测试报告保存位置
*
* @param savePath
* 测试报告保存位置
*/
public AutoTestReport(String savePath) {
setSavePath(savePath);
}
@Override
public String createReport(File excel, int testDay, String person,
String range) throws IOException {
// TODO Auto-generated method stub
return "";
}
@Override
public String createReport(String name, String version, int testDay, String person, String range, int activeOne,
int activeTwo, int activeThree, int activeFour, int one, int two, int three, int four, int noSulveOne,
int noSulveTwo, int delayOne, int delayTwo, String accessory) throws IOException {
// TODO 自动生成的方法存根
return null;
}
/*
* @Override public void createReport(File folder, int[] testDay, String[]
* person, String[] range) throws IOException { // TODO Auto-generated
* method stub
*
* }
*/
}

View File

@ -0,0 +1,269 @@
package pres.auxiliary.report;
import java.io.File;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
class BugFilePosition {
/**
* 设置配置文件存放的位置
*/
private final static String xml = "ConfigurationFiles/ReportConfigurationFile/TestReportConfiguration.xml";
/**
* Bug编号
*/
public static int ID;
/**
* 所属产品
*/
public static int PRODUCT;
/**
* 所属模块
*/
public static int MODULE;
/**
* 所属项目
*/
public static int PROJECT;
/**
* Bug标题
*/
public static int TITLE;
/**
* 严重程度
*/
public static int SIGNIFICANCE;
/**
* Bug类型
*/
public static int TYPE;
/**
* 步骤
*/
public static int STEP;
/**
* 激活次数
*/
public static int ACTIVE_COUNT;
/**
* 创建者
*/
public static int CREATE_PERSON;
/**
* 创建时间
*/
public static int CREATE_TIME;
/**
* 影响版本
*/
public static int VERSION;
/**
* 指派给
*/
public static int ASSIGN_PERSON;
/**
* 解决方案
*/
public static int SOULVE_WAY;
//通过静态代码块的方式在未构造类的情况下根据配置文件中的值来初始化其列数
static {
// 读取配置好的XML文件
Document dom = null;
try {
dom = new SAXReader().read(new File(xml));
} catch (DocumentException e) {
e.printStackTrace();
}
// 获取测试报告中的内容
String type = dom.getRootElement().attributeValue("type");
//判断测试由何处导出之后初始化其值
if ( type.equalsIgnoreCase("Zentao") || type.equalsIgnoreCase("") ) {
ID = Zentao.ID.getCell();
PRODUCT = Zentao.PRODUCT.getCell();
MODULE = Zentao.MODULE.getCell();
PROJECT = Zentao.PROJECT.getCell();
TITLE = Zentao.TITLE.getCell();
SIGNIFICANCE = Zentao.SIGNIFICANCE.getCell();
TYPE = Zentao.TYPE.getCell();
STEP = Zentao.STEP.getCell();
ACTIVE_COUNT = Zentao.ACTIVE_COUNT.getCell();
CREATE_PERSON = Zentao.CREATE_PERSON.getCell();
CREATE_TIME = Zentao.CREATE_TIME.getCell();
VERSION = Zentao.VERSION.getCell();
VERSION = Zentao.VERSION.getCell();
ASSIGN_PERSON = Zentao.ASSIGN_PERSON.getCell();
SOULVE_WAY = Zentao.SOULVE_WAY.getCell();
} else if ( type.equalsIgnoreCase("TFS") ) {
ID = TFS.ID.getCell();
PRODUCT = TFS.PRODUCT.getCell();
MODULE = TFS.MODULE.getCell();
PROJECT = TFS.PROJECT.getCell();
TITLE = TFS.TITLE.getCell();
SIGNIFICANCE = TFS.SIGNIFICANCE.getCell();
TYPE = TFS.TYPE.getCell();
STEP = TFS.STEP.getCell();
ACTIVE_COUNT = TFS.ACTIVE_COUNT.getCell();
CREATE_PERSON = TFS.CREATE_PERSON.getCell();
CREATE_TIME = TFS.CREATE_TIME.getCell();
VERSION = TFS.VERSION.getCell();
VERSION = TFS.VERSION.getCell();
ASSIGN_PERSON = TFS.ASSIGN_PERSON.getCell();
SOULVE_WAY = TFS.SOULVE_WAY.getCell();
} else {
throw new InvalidBugListFileSignException("无效的Bug汇总表文件标识" + type);
}
}
/**
* 用于指向禅道导出的BUG汇总表文件中的各个信息
*
* @author 彭宇琦
*/
private enum Zentao {
/**
* Bug编号
*/
ID(0),
/**
* 所属产品
*/
PRODUCT(1),
/**
* 所属模块
*/
MODULE(2),
/**
* 所属项目
*/
PROJECT(3),
/**
* Bug标题
*/
TITLE(6),
/**
* 严重程度
*/
SIGNIFICANCE(8),
/**
* Bug类型
*/
TYPE(10),
/**
* 步骤
*/
STEP(13),
/**
* 激活次数
*/
ACTIVE_COUNT(16),
/**
* 创建者
*/
CREATE_PERSON(19),
/**
* 创建时间
*/
CREATE_TIME(20),
/**
* 影响版本
*/
VERSION(21),
/**
* 指派给
*/
ASSIGN_PERSON(22),
/**
* 解决方案
*/
SOULVE_WAY(25);
private int cell;
private Zentao(int cell) {
this.cell = cell;
}
public int getCell() {
return cell;
}
}
/**
* 用于指向TFS导出的BUG汇总表文件中的各个信息
*
* @author 彭宇琦
*/
private enum TFS {
/**
* Bug编号
*/
ID(-1),
/**
* 所属产品
*/
PRODUCT(-1),
/**
* 所属模块
*/
MODULE(-1),
/**
* 所属项目
*/
PROJECT(-1),
/**
* Bug标题
*/
TITLE(-1),
/**
* 严重程度
*/
SIGNIFICANCE(-1),
/**
* Bug类型
*/
TYPE(-1),
/**
* 步骤
*/
STEP(-1),
/**
* 激活次数
*/
ACTIVE_COUNT(-1),
/**
* 创建者
*/
CREATE_PERSON(-1),
/**
* 创建时间
*/
CREATE_TIME(-1),
/**
* 影响版本
*/
VERSION(-1),
/**
* 指派给
*/
ASSIGN_PERSON(-1),
/**
* 解决方案
*/
SOULVE_WAY(-1);
private int cell;
private TFS(int cell) {
this.cell = cell;
}
public int getCell() {
return cell;
}
}
}

View File

@ -0,0 +1,38 @@
package pres.auxiliary.report;
/**
* 在格式不兼容时抛出的异常
*
* @author 彭宇琦
*/
public class IncompatibleFileLayoutException extends RuntimeException {
public IncompatibleFileLayoutException() {
super();
// TODO Auto-generated constructor stub
}
public IncompatibleFileLayoutException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IncompatibleFileLayoutException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IncompatibleFileLayoutException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IncompatibleFileLayoutException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,33 @@
package pres.auxiliary.report;
public class IncorrectBugVersionException extends RuntimeException {
private static final long serialVersionUID = 1L;
public IncorrectBugVersionException() {
super();
// TODO 自动生成的构造函数存根
}
public IncorrectBugVersionException(String arg0, Throwable arg1, boolean arg2, boolean arg3) {
super(arg0, arg1, arg2, arg3);
// TODO 自动生成的构造函数存根
}
public IncorrectBugVersionException(String arg0, Throwable arg1) {
super(arg0, arg1);
// TODO 自动生成的构造函数存根
}
public IncorrectBugVersionException(String arg0) {
super(arg0);
// TODO 自动生成的构造函数存根
}
public IncorrectBugVersionException(Throwable arg0) {
super(arg0);
// TODO 自动生成的构造函数存根
}
}

View File

@ -0,0 +1,36 @@
package pres.auxiliary.report;
/**
* 该异常在XML文件语法出错时抛出的异常
* @author 彭宇琦
*/
public class IncorrectGrammarException extends RuntimeException {
public IncorrectGrammarException() {
super();
// TODO Auto-generated constructor stub
}
public IncorrectGrammarException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IncorrectGrammarException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IncorrectGrammarException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IncorrectGrammarException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,36 @@
package pres.auxiliary.report;
public class InvalidBugListFileSignException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public InvalidBugListFileSignException() {
super();
// TODO 自动生成的构造函数存根
}
public InvalidBugListFileSignException(String arg0, Throwable arg1, boolean arg2, boolean arg3) {
super(arg0, arg1, arg2, arg3);
// TODO 自动生成的构造函数存根
}
public InvalidBugListFileSignException(String arg0, Throwable arg1) {
super(arg0, arg1);
// TODO 自动生成的构造函数存根
}
public InvalidBugListFileSignException(String arg0) {
super(arg0);
// TODO 自动生成的构造函数存根
}
public InvalidBugListFileSignException(Throwable arg0) {
super(arg0);
// TODO 自动生成的构造函数存根
}
}

View File

@ -0,0 +1,45 @@
package pres.auxiliary.report;
/**
* 该类用于创建报告文件对象的类型传入TestReport表示测试报告传入AutoTestPath表示自动化测试报告
*
* @author 彭宇琦
* @version Ver1.0
*/
public class ReportFactory {
/**
* 该方法用于通过带参构造的方法创建报告类对象
*
* @param report
* 报告的类型
* @param savePath
* 报告的输出位置
* @return 报告类对象
*/
public static AbstractReport newInstance(String report, String savePath) {
if (report.equalsIgnoreCase("TestReport")) {
return new TestReport(savePath);
} else if (report.equalsIgnoreCase("AutoTestPath")) {
return new AutoTestReport(savePath);
} else {
return null;
}
}
/**
* 该方法用于通过无参构造的方法创建报告类对象
*
* @param report
* 报告的类型
* @return 报告类对象
*/
public static AbstractReport newInstance(String report) {
if (report.equalsIgnoreCase("TestReport")) {
return new TestReport();
} else if (report.equalsIgnoreCase("AutoTestPath")) {
return new AutoTestReport();
} else {
return null;
}
}
}

View File

@ -0,0 +1,118 @@
package pres.auxiliary.report;
import java.io.File;
import java.io.IOException;
/**
* 该接口定义了测试报告类应实现的方法
*
* @author 彭宇琦
* @version Ver1.0
*/
public interface ReportInter {
/**
* 该方法用于生成测试报告的参数
*
* @param name
* 项目名称
* @param version
* 项目版本号
* @param testDay
* 测试的天数
* @param person
* 测试人员
* @param range
* 测试的范围
* @param one
* 一级Bug的数量
* @param two
* 二级Bug的数量
* @param three
* 三级Bug的数量
* @param four
* 四级Bug的数量
* @param noSulveOne
* 原版本中未解决的一级Bug的数量
* @param noSulveTwo
* 原版本中未解决的二级Bug的数量
* @param delayOne 原版本中延期解决的一级Bug的数量
* @param delayTwo 原版本中延期解决的二级Bug的数量
* @param accessory
* 附件存放位置
* @param activeOne
* 激活的一级BUG的数量
* @param activeTwo
* 激活的二级BUG的数量
* @param activeThree
* 激活的三级BUG的数量
* @param activeFour
* 激活的四级BUG的数量
* @return 测试报告邮件中正文的内容
*
* @see #createReport(File, int, String, String)
*
* @throws IOException
*/
public abstract String createReport(String name, String version,
int testDay, String person, String range, int activeOne,
int activeTwo, int activeThree, int activeFour, int one, int two,
int three, int four, int noSulveOne,
int noSulveTwo, int delayOne, int delayTwo, String accessory)
throws IOException;
/**
* 该方法用于通过读取BUG汇总表中的信息来生成测试报告
*
* @param excel
* BUG汇总表文件
* @param testDay
* 测试的天数
* @param person
* 测试人员
* @param range
* 测试范围
* @return 测试报告邮件中正文的内容
* @see #createReport(String, String, int, String, String, int, int, int,
* int, String)
* @throws IOException
*/
public abstract String createReport(File excel, int testDay, String person,
String range) throws IOException;
/**
* 该方法用于读取Bug汇总表其返回的数组存储的信息如下表所示<br/>
* <table border="1">
* <tr>
* <td>s[0]:项目名称</td>
* <td>s[1]:当前版本</td>
* <td>s[2]:1级BUG数量</td>
* <td>s[3]:2级BUG数量</td>
* </tr>
* <tr>
* <td>s[4]:3级BUG数量</td>
* <td>s[5]:4级BUG数量</td>
* <td>s[6]:激活1级BUG数量</td>
* <td>s[7]:激活2级BUG数量</td>
* </tr>
* <tr>
* <td>s[8]:激活3级BUG数量</td>
* <td>s[9]:激活4级BUG数量</td>
* <td>s[10]:未解决的1级BUG数量</td>
* <td>s[11]:未解决的2级BUG数量</td>
* </tr>
* <tr>
* <td>s[12]:延期解决1级BUG数量</td>
* <td>s[13]:延期解决2级BUG数量</td>
* </tr>
* </table>
*
* @param excel
* BUG汇总表
* @param testDay
* 测试的天数
* @return Bug汇总表中提取的信息
* @throws IOException
*/
public abstract String[] readFile(File excel, int testDay)
throws IOException;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,185 @@
package pres.auxiliary.report.ui;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.mail.MessagingException;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.EmptyBorder;
import org.dom4j.DocumentException;
/**
* FileName: SandMailFrame.java
*
* 用于给出一个发送邮件确认的弹窗在该弹窗上可以修改邮件收件人和抄送人
*
* @author 彭宇琦
* @Deta 2018年4月27日 下午4:49:26
* @version ver1.0
*/
public class SandMailFrame extends JFrame {
private static final long serialVersionUID = -1048290948430116615L;
private JPanel contentPane;
protected static JTextArea to;
protected static JTextArea cc;
protected static JTextArea content;
static SandMailFrame frame = new SandMailFrame();
/**
* Create the frame.
*/
public SandMailFrame() {
setTitle("\u68C0\u67E5\u90AE\u4EF6\u63A5\u6536\u4EBA");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 487, 607);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel label = new JLabel("\u6536\u4EF6\u4EBA\uFF1A");
label.setBounds(10, 10, 65, 15);
contentPane.add(label);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 35, 414, 93);
contentPane.add(scrollPane);
to = new JTextArea();
to.setEditable(false);
to.setLineWrap(true);
scrollPane.setViewportView(to);
JLabel label_1 = new JLabel("\u6284\u9001\u4EBA\uFF1A");
label_1.setBounds(10, 138, 65, 15);
contentPane.add(label_1);
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(10, 163, 414, 93);
contentPane.add(scrollPane_1);
cc = new JTextArea();
cc.setEditable(false);
cc.setLineWrap(true);
scrollPane_1.setViewportView(cc);
JButton yes = new JButton("\u786E\u5B9A");
yes.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 执行发送邮件的方法
try {
TestReportMainFrame.tr.sandMail(TestReportFrame.content.getText(),
TestReportFrame.projectName.getText(),
(TestReportFrame.Version.getText() + "版本测试报告"), TestReportFrame.range.getText(),
new File(TestReportMainFrame.tr.getSavePath()
+ TestReportMainFrame.tr.getFileName()
+ ".zip"));
} catch (DocumentException | MessagingException
| IOException e1) {
e1.printStackTrace();
}
new File(TestReportMainFrame.tr.getSavePath()
+ TestReportMainFrame.tr.getFileName() + ".zip")
.delete();
frame.setVisible(false);
// 弹出一个提示框表示测试报告生成完毕
JOptionPane.showMessageDialog(TestReportFrame.purpose, "邮件已发送成功,请在邮箱中查看");
}
});
yes.setBounds(171, 498, 93, 23);
contentPane.add(yes);
JButton no = new JButton("\u53D6\u6D88");
no.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//隐藏窗口
frame.setVisible(false);
}
});
no.setBounds(331, 498, 93, 23);
contentPane.add(no);
JButton refresh = new JButton("\u5237\u65B0");
refresh.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//刷新数据即调用初始化数据方法
initData();
}
});
refresh.setBounds(11, 498, 93, 23);
contentPane.add(refresh);
JLabel label_2 = new JLabel("\u5185\u5BB9\u9884\u89C8\uFF1A");
label_2.setBounds(10, 266, 94, 15);
contentPane.add(label_2);
JScrollPane scrollPane_2 = new JScrollPane();
scrollPane_2.setBounds(10, 291, 414, 197);
contentPane.add(scrollPane_2);
content = new JTextArea();
content.setLineWrap(true);
scrollPane_2.setViewportView(content);
}
public static void showFrame() {
initData();
frame.setVisible(true);
}
/**
* 初始化数据
*/
public static void initData() {
//根据项目名称获取邮件的收件人与抄送人
String[][] strs = TestReportMainFrame.tr.getMailToAndCc(TestReportFrame.projectName.getText());
StringBuilder sb = new StringBuilder();
//获取收件人
for (String s : strs[0]) {
sb.append(s + "\n");
}
sb.delete(sb.lastIndexOf("\n"), sb.length());
//填写收件人到界面中
to.setText(sb.toString());
//清空存储的收件人
sb.delete(0, sb.length());
//获取抄送人
for (String s : strs[1]) {
sb.append(s + "\n");
}
sb.delete(sb.lastIndexOf("\n"), sb.length());
//填写抄送人到界面中
cc.setText(sb.toString());
String text = "";
try {
text = TestReportMainFrame.tr.getMailContent(TestReportFrame.content.getText(),
TestReportFrame.projectName.getText(),
(TestReportFrame.Version.getText() + "版本测试报告"), TestReportFrame.range.getText());
} catch (DocumentException | MessagingException | IOException e) {
e.printStackTrace();
}
//在预览信息中添加文本
content.setText(text);
}
}

View File

@ -0,0 +1,823 @@
package pres.auxiliary.report.ui;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerDateModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.dom4j.io.SAXReader;
import pres.auxiliary.report.AbstractReport.BugInformation;
import pres.auxiliary.tool.ui.control.AutoNumberJTextArea;
/**
* FileName: TestReportFrame.java
*
* 该界面是生成测试报告程序的主界面可在此编辑测试报告的内容并生成测试报告
*
* @author 彭宇琦
* @Deta 2018年4月26日 下午2:52:49
* @version ver1.3
*/
public class TestReportFrame extends JFrame {
private static final long serialVersionUID = 4597332795736199596L;
private JPanel contentPane;
private static JTextField showBugFilePath;
protected static JTextField projectName;
protected static JTextField Version;
private JLabel label_2;
protected static JSpinner startTime;
private JLabel label_3;
protected static JSpinner endTime;
protected static JTextField range;
protected static JTextField person;
protected static JTextArea purpose;
protected static JTextArea gist;
protected static JSpinner activeOneBug;
protected static JSpinner activeTwoBug;
protected static JSpinner activeThreeBug;
protected static JSpinner activeFourBug;
protected static JSpinner newOneBug;
protected static JSpinner newTwoBug;
protected static JSpinner newThreeBug;
protected static JSpinner newFourBug;
protected static JCheckBox isPass;
protected static JTextArea content;
static TestReportFrame frame = new TestReportFrame();
private JButton printReport;
/**
* Launch the application.
*/
static void Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
frame.setVisible(true);
// 设置窗体显示在屏幕中心
frame.setLocationRelativeTo(null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestReportFrame() {
setResizable(false);
setTitle("\u6D4B\u8BD5\u62A5\u544A\u751F\u6210\u5668");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 634, 791);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblNewLabel = new JLabel("Bug\u5217\u8868\u6587\u4EF6\u4F4D\u7F6E\uFF1A");
lblNewLabel.setBounds(10, 10, 118, 15);
contentPane.add(lblNewLabel);
showBugFilePath = new JTextField();
showBugFilePath.setEditable(false);
showBugFilePath.setBounds(127, 7, 361, 21);
contentPane.add(showBugFilePath);
showBugFilePath.setColumns(10);
JButton button = new JButton("\u4FEE\u6539");
button.setBounds(498, 6, 69, 23);
contentPane.add(button);
JLabel label = new JLabel("\u9879\u76EE\u540D\u79F0\uFF1A");
label.setBounds(10, 38, 69, 15);
contentPane.add(label);
projectName = new JTextField();
projectName.setBounds(82, 35, 485, 21);
contentPane.add(projectName);
projectName.setColumns(10);
JLabel label_1 = new JLabel("\u7248\u672C\u4FE1\u606F\uFF1A");
label_1.setBounds(10, 69, 69, 15);
contentPane.add(label_1);
Version = new JTextField();
Version.setColumns(10);
Version.setBounds(82, 66, 485, 21);
contentPane.add(Version);
label_2 = new JLabel("\u6D4B\u8BD5\u65F6\u95F4\uFF1A");
label_2.setBounds(10, 125, 69, 15);
contentPane.add(label_2);
SpinnerDateModel model = new SpinnerDateModel();
startTime = new JSpinner(model);
startTime.setValue(new Date());
JSpinner.DateEditor de_startTime = new JSpinner.DateEditor(startTime, "yyyy.MM.dd");
startTime.setEditor(de_startTime);
startTime.setBounds(82, 122, 93, 28);
contentPane.add(startTime);
label_3 = new JLabel("\uFF5E");
label_3.setBounds(185, 129, 22, 15);
contentPane.add(label_3);
SpinnerDateModel model2 = new SpinnerDateModel();
endTime = new JSpinner(model2);
endTime.setValue(new Date());
JSpinner.DateEditor de_endTime = new JSpinner.DateEditor(endTime, "yyyy.MM.dd");
endTime.setEditor(de_endTime);
endTime.setBounds(206, 122, 93, 28);
contentPane.add(endTime);
person = new JTextField();
person.setColumns(10);
person.setBounds(82, 160, 485, 21);
contentPane.add(person);
JLabel label_4 = new JLabel("\u6D4B\u8BD5\u6210\u5458\uFF1A");
label_4.setBounds(10, 163, 69, 15);
contentPane.add(label_4);
JLabel label_5 = new JLabel("\u6D4B\u8BD5\u76EE\u7684\uFF1A");
label_5.setBounds(10, 191, 69, 15);
contentPane.add(label_5);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setBounds(10, 216, 557, 70);
contentPane.add(scrollPane);
purpose = new AutoNumberJTextArea();
purpose.setLineWrap(true);
scrollPane.setViewportView(purpose);
JLabel label_6 = new JLabel("\u6D4B\u8BD5\u4F9D\u636E\uFF1A");
label_6.setBounds(10, 296, 69, 15);
contentPane.add(label_6);
JScrollPane scrollPane_1 = new JScrollPane();
scrollPane_1.setBounds(10, 321, 557, 70);
contentPane.add(scrollPane_1);
gist = new AutoNumberJTextArea();
gist.setLineWrap(true);
scrollPane_1.setViewportView(gist);
JLabel lblbug = new JLabel("\u6FC0\u6D3BBug\u6570\uFF1A");
lblbug.setBounds(10, 401, 84, 15);
contentPane.add(lblbug);
JLabel label_7 = new JLabel("\u4E00\u7EA7\uFF1A");
label_7.setBounds(10, 433, 44, 15);
contentPane.add(label_7);
activeOneBug = new JSpinner();
activeOneBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
activeOneBug.setBounds(48, 426, 46, 28);
contentPane.add(activeOneBug);
JLabel label_8 = new JLabel("\u4E8C\u7EA7\uFF1A");
label_8.setBounds(123, 433, 44, 15);
contentPane.add(label_8);
activeTwoBug = new JSpinner();
activeTwoBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
activeTwoBug.setBounds(161, 426, 46, 28);
contentPane.add(activeTwoBug);
JLabel label_9 = new JLabel("\u4E09\u7EA7\uFF1A");
label_9.setBounds(235, 433, 44, 15);
contentPane.add(label_9);
activeThreeBug = new JSpinner();
activeThreeBug.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updataContent();
}
});
activeThreeBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
activeThreeBug.setBounds(273, 426, 46, 28);
contentPane.add(activeThreeBug);
JLabel label_10 = new JLabel("\u56DB\u7EA7\uFF1A");
label_10.setBounds(345, 433, 44, 15);
contentPane.add(label_10);
activeFourBug = new JSpinner();
activeFourBug.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updataContent();
}
});
activeFourBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
activeFourBug.setBounds(383, 426, 46, 28);
contentPane.add(activeFourBug);
JLabel lblbug_1 = new JLabel("\u65B0\u63D0\u4EA4Bug\u6570\uFF1A");
lblbug_1.setBounds(10, 458, 93, 15);
contentPane.add(lblbug_1);
JLabel label_12 = new JLabel("\u4E00\u7EA7\uFF1A");
label_12.setBounds(10, 488, 44, 15);
contentPane.add(label_12);
newOneBug = new JSpinner();
newOneBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
newOneBug.setBounds(48, 481, 46, 28);
contentPane.add(newOneBug);
JLabel label_13 = new JLabel("\u4E8C\u7EA7\uFF1A");
label_13.setBounds(123, 488, 44, 15);
contentPane.add(label_13);
newTwoBug = new JSpinner();
newTwoBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
newTwoBug.setBounds(161, 481, 46, 28);
contentPane.add(newTwoBug);
JLabel label_14 = new JLabel("\u4E09\u7EA7\uFF1A");
label_14.setBounds(235, 488, 44, 15);
contentPane.add(label_14);
newThreeBug = new JSpinner();
newThreeBug.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updataContent();
}
});
newThreeBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
newThreeBug.setBounds(273, 481, 46, 28);
contentPane.add(newThreeBug);
JLabel label_15 = new JLabel("\u56DB\u7EA7\uFF1A");
label_15.setBounds(345, 488, 44, 15);
contentPane.add(label_15);
newFourBug = new JSpinner();
newFourBug.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
updataContent();
}
});
newFourBug.setModel(new SpinnerNumberModel(0, 0, null, 1));
newFourBug.setBounds(383, 481, 46, 28);
contentPane.add(newFourBug);
JLabel label_11 = new JLabel("\u662F\u5426\u901A\u8FC7\uFF1A");
label_11.setBounds(447, 444, 69, 15);
contentPane.add(label_11);
isPass = new JCheckBox("\u4E0D\u901A\u8FC7");
isPass.setToolTipText(
"\u6839\u636E\u4E00\u3001\u4E8C\u7EA7Bug\u7684\u6570\u91CF\u81EA\u52A8\u66F4\u6539\uFF0C\u4E5F\u53EF\u4EE5\u624B\u52A8\u66F4\u6539");
isPass.addChangeListener(new ChangeListener() {
// 不添加状态改变事件会导致增加一二级BUG数后复选框不自动勾选
@Override
public void stateChanged(ChangeEvent e) {
if (isPass.isSelected()) {
isPass.setText("通过");
} else {
isPass.setText("不通过");
}
updataContent();
}
});
isPass.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (isPass.isSelected()) {
isPass.setText("通过");
} else {
isPass.setText("不通过");
}
updataContent();
}
});
isPass.setBounds(447, 465, 103, 23);
contentPane.add(isPass);
final JButton createReport = new JButton("\u751F\u6210\u62A5\u544A");
createReport.setBounds(10, 672, 93, 23);
contentPane.add(createReport);
final JButton sandMail = new JButton("\u53D1\u9001\u90AE\u4EF6");
sandMail.setEnabled(false);
sandMail.setBounds(241, 672, 93, 23);
contentPane.add(sandMail);
JButton reset = new JButton("\u91CD\u7F6E");
reset.setBounds(359, 672, 93, 23);
contentPane.add(reset);
JButton showCode = new JButton("\u751F\u6210\u4EE3\u7801");
showCode.setBounds(474, 672, 93, 23);
contentPane.add(showCode);
JLabel label_16 = new JLabel("\u6D4B\u8BD5\u8303\u56F4\uFF1A");
label_16.setBounds(10, 97, 69, 15);
contentPane.add(label_16);
range = new JTextField();
range.setColumns(10);
range.setBounds(82, 94, 485, 21);
contentPane.add(range);
JLabel label_17 = new JLabel("\u62A5\u544A\u5185\u5BB9\uFF1A");
label_17.setBounds(10, 519, 69, 15);
contentPane.add(label_17);
JScrollPane scrollPane_2 = new JScrollPane();
scrollPane_2.setBounds(10, 544, 557, 118);
contentPane.add(scrollPane_2);
content = new JTextArea();
content.setToolTipText(
"\u6D4B\u8BD5\u62A5\u544A\u7684\u5185\u5BB9\u53EF\u6839\u636E\u5176\u4E0A\u65B9\u7684\u8BBE\u7F6E\u81EA\u52A8\u53D8\u66F4\u6587\u5B57\uFF0C\u4E5F\u53EF\u4EE5\u5728\u6B64\u5904\u66F4\u6539\uFF0C\u66F4\u6539\u540E\u6587\u5B57\u5C06\u53CD\u6620\u5230\u6D4B\u8BD5\u62A5\u544A\u548C\u90AE\u4EF6\u5185\u5BB9\u4E2D");
content.setLineWrap(true);
scrollPane_2.setViewportView(content);
printReport = new JButton("\u6253\u5370\u62A5\u544A");
printReport.setEnabled(false);
printReport.setBounds(125, 672, 93, 23);
contentPane.add(printReport);
final JButton refreshBug = new JButton("\u5237\u65B0Bug\u6570\u91CF");
refreshBug.setToolTipText(
"\u80FD\u6839\u636E\u6D4B\u8BD5\u65F6\u95F4\u6765\u91CD\u65B0\u83B7\u53D6Bug\u6570\u91CF");
refreshBug.setBounds(326, 124, 126, 23);
contentPane.add(refreshBug);
activeOneBug.addChangeListener(new ChangeListener() {
// 判断激活或者新提交的BUG是否有一级与二级的BUG若有则将是否通过的选择框设为勾选状态
@Override
public void stateChanged(ChangeEvent e) {
if ((int) activeOneBug.getValue() > 0 || (int) activeTwoBug.getValue() > 0
|| (int) newOneBug.getValue() > 0 || (int) newTwoBug.getValue() > 0) {
isPass.setSelected(false);
} else {
isPass.setSelected(true);
}
updataContent();
}
});
activeTwoBug.addChangeListener(new ChangeListener() {
// 判断激活或者新提交的BUG是否有一级与二级的BUG若有则将是否通过的选择框设为勾选状态
@Override
public void stateChanged(ChangeEvent e) {
if ((int) activeOneBug.getValue() > 0 || (int) activeTwoBug.getValue() > 0
|| (int) newOneBug.getValue() > 0 || (int) newTwoBug.getValue() > 0) {
isPass.setSelected(false);
} else {
isPass.setSelected(true);
}
updataContent();
}
});
newOneBug.addChangeListener(new ChangeListener() {
// 判断激活或者新提交的BUG是否有一级与二级的BUG若有则将是否通过的选择框设为勾选状态
@Override
public void stateChanged(ChangeEvent e) {
if ((int) activeOneBug.getValue() > 0 || (int) activeTwoBug.getValue() > 0
|| (int) newOneBug.getValue() > 0 || (int) newTwoBug.getValue() > 0) {
isPass.setSelected(false);
} else {
isPass.setSelected(true);
}
updataContent();
}
});
newTwoBug.addChangeListener(new ChangeListener() {
// 判断激活或者新提交的BUG是否有一级与二级的BUG若有则将是否通过的选择框设为勾选状态
@Override
public void stateChanged(ChangeEvent e) {
if ((int) activeOneBug.getValue() > 0 || (int) activeTwoBug.getValue() > 0
|| (int) newOneBug.getValue() > 0 || (int) newTwoBug.getValue() > 0) {
isPass.setSelected(false);
} else {
isPass.setSelected(true);
}
updataContent();
}
});
// TODO 修改按钮的点击事件
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
sandMail.setEnabled(false);
printReport.setEnabled(false);
refreshBug.setEnabled(true);
TestReportMainFrame.frame.setVisible(true);
}
});
// TODO 生成报告按钮点击事件
createReport.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 弹出一个确认弹框的方法
// JOptionPane.showMessageDialog(confirm, "未选择测试用例文件");
// System.out.println(endTime.getValue().toString());
String[] s = TestReportMainFrame.s;
// 拼接测试时间
StringBuilder time = new StringBuilder();
time.append(new SimpleDateFormat("yyyy.MM.dd").format(startTime.getValue()));
time.append("-");
time.append(new SimpleDateFormat("yyyy.MM.dd").format(endTime.getValue()));
TestReportMainFrame.tr.setFileName(Version.getText() + "版本测试报告");
// new File(TestReportMainFrame.bugFileEdit.getText()).delete();
try {
TestReportMainFrame.tr.createReport(projectName.getText(), Version.getText(), time.toString(),
person.getText(), range.getText(), purpose.getText(), gist.getText(), content.getText(),
("附:" + Version.getText() + "版本Bug汇总表"));
} catch (IOException e1) {
e1.printStackTrace();
}
// 生成报告时需要更新手动输入的BUG数量此时需要重新获取并存储BUG数量之后写入xml文件中
s[0] = projectName.getText();
s[1] = Version.getText().split("Ver")[1];
s[2] = String.valueOf(newOneBug.getValue());
s[3] = String.valueOf(newTwoBug.getValue());
s[4] = String.valueOf(newThreeBug.getValue());
s[5] = String.valueOf(newFourBug.getValue());
// 循环删除time变量中所有的.
while (true) {
// 判断time中是否还包含.没有则结束循环
if (time.indexOf(".") == -1) {
break;
}
// 删除.
time.deleteCharAt(time.indexOf("."));
}
try {
TestReportMainFrame.tr.writeVersionBugNumber(s, time.toString());
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
// 弹出一个提示框表示测试报告生成完毕
JOptionPane.showMessageDialog(purpose, "测试报告生成完毕,详见:" + TestReportMainFrame.tr.getSavePath()
+ TestReportMainFrame.tr.getFileName() + "\\" + TestReportMainFrame.tr.getFileName() + ".docx");
sandMail.setEnabled(true);
printReport.setEnabled(true);
refreshBug.setEnabled(false);
}
});
// TODO 打印报告按钮点击事件
printReport.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 弹出提示框提示用户确认发送邮件的信息无误后方可发送邮件
int choose = JOptionPane.showConfirmDialog(purpose, "请确认测试报告内容无误后,点击“是”按钮来打印测试报告");
// 若用户点击取消按钮则终止方法运行
if (choose != 0) {
return;
}
// 执行发送邮件的方法
try {
TestReportMainFrame.tr.printReport(
new File(TestReportMainFrame.tr.getSavePath() + Version.getText() + "版本测试报告\\"
+ Version.getText() + "版本测试报告.docx"),
new SAXReader().read(TestReportMainFrame.tr.xml).getRootElement().element("report")
.attributeValue("print_name"));
} catch (Exception e1) {
}
// 弹出一个提示框表示测试报告生成完毕
JOptionPane.showMessageDialog(purpose, "测试报告已进入打印队列,网络问题可能会造成延迟,若长时间打印机无反应,则打印可能失败了");
}
});
// TODO 发送邮件按钮点击事件
sandMail.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
SandMailFrame.showFrame();
}
});
// TODO 重置按钮点击事件
reset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
iniData();
}
});
// TODO 生成代码按钮点击事件
showCode.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 计算测试时间天数
long time = ((Date) (endTime.getValue())).getTime() - ((Date) (startTime.getValue())).getTime();
// TODO 由于平板上无法完成界面的编辑故先将代码存储回去后编辑文本域使其反映到文本域上
// 用于存储生成的代码
StringBuilder code = new StringBuilder();
code.append("//TODO 若需要包名,请自行添加\n");
code.append("//package \n\n");
code.append("import java.io.File;\n");
code.append("import java.io.IOException;\n");
code.append("import java.io.UnsupportedEncodingException;\n\n");
code.append("import javax.mail.MessagingException;\n\n");
code.append("import org.dom4j.DocumentException;\n\n");
code.append("import pres.auxiliary.report.TestReport;\n\n");
code.append("public class ReportCode {\n");
code.append("\tpublic static void main(String[] args) {\n");
code.append("\t\tTestReport tr = new TestReport();\n");
code.append("\t\t//设置测试报告保存位置\n");
code.append("\t\t//TODO 此处需要自行将单个反斜杠变为两个反斜杠,否则会报错\n");
code.append("\t\ttr.setSavePath(\"" + TestReportMainFrame.tr.getSavePath() + "\");\n");
code.append("\t\t//创建测试报告\n");
code.append("\t\t//TODO 此处需要自行将单个反斜杠变为两个反斜杠,否则会报错\n");
code.append("\t\ttry {\n");
code.append("\t\t\ttr.createReport(new File(\"" + TestReportMainFrame.bugFileEdit.getText() + "\"), "
+ ((time / 1000 / 60 / 60 / 24) + 1) + ", \"" + person.getText() + "\", \"" + range.getText()
+ "\");\n");
code.append("\t\t} catch (IOException e1) {\n");
code.append("\t\t\te1.printStackTrace();\n");
code.append("\t\t}\n\n");
code.append("\t\t//发送邮件,可按需自行放开注释\n");
code.append("\t\t/*\n");
code.append("\t\ttry {\n");
code.append("\t\t\ttr.sandMail(tr.getMailContent(), \"" + projectName.getText() + "版本测试报告" + "\", \""
+ Version.getText() + "\", new File(tr.getSavePath() + tr.getFileName() + \".zip\"));\n");
code.append("\t\t} catch (UnsupportedEncodingException e1) {\n");
code.append("\t\t\te1.printStackTrace();\n");
code.append("\t\t} catch (DocumentException e1) {\n");
code.append("\t\t\te1.printStackTrace();\n");
code.append("\t\t} catch (MessagingException e1) {\n");
code.append("\t\t\te1.printStackTrace();\n");
code.append("\t\t} catch (IOException e1) {\n");
code.append("\t\t\te1.printStackTrace();\n");
code.append("\t\t}\n");
code.append("\t\t*/\n\n");
code.append("\t\t//打印测试报告,可按需自行放开注释\n");
code.append("\t\t/*\n");
code.append("\t\ttry {\n");
code.append(
"\t\t\ttr.printReport(new File(tr.getSavePath() + tr.getFileName() + \".docx\"), new SAXReader().read(new File(\"ConfigurationFiles/ReportConfigurationFile/TestReportConfiguration.xml\")).getRootElement().element(\"report\").attributeValue(\"print_name\"));\n");
code.append("\t\t} catch (DocumentException e) {\n");
code.append("\t\t\te.printStackTrace();\n");
code.append("\t\t}\n");
code.append("\t\t*/\n\n");
code.append("\t\t//若XML文件配置无误则可调用以下代码\n");
code.append("\t\t//TestReport tr = new TestReport();\n");
code.append("\t\t//tr.setSavePath(\"" + TestReportMainFrame.tr.getSavePath() + "\");\n");
code.append("\t\t//tr.autoWriteReport(true, true)\n");
code.append("\t}\n");
code.append("}\n");
// System.out.println(code.toString());
// 创建存储测试报告代码存放的文件夹
File f = new File("Code\\Report\\");
f.mkdirs();
// 创建写入流保存生成的代码
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(new File(f + "\\ReportCode.java")));
} catch (IOException e1) {
e1.printStackTrace();
}
// 写入代码
try {
bw.write(code.toString());
} catch (IOException e1) {
e1.printStackTrace();
}
// 关闭流
try {
bw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
// 弹出文件夹
try {
java.awt.Desktop.getDesktop().open(f);
} catch (IOException e1) {
e1.printStackTrace();
}
// 弹出一个提示框表示测试报告生成完毕
JOptionPane.showMessageDialog(purpose,
"代码已生成,详见项目路径下:" + new File(f + "\\ReportCode.java").getAbsolutePath());
}
});
// TODO 刷新Bug数量按钮事件
refreshBug.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 读取BUG列表文件重新刷新BUG数量
// 读取Bug列表文件
String[] ss = null;
try {
ss = TestReportMainFrame.tr.readFile(new File(TestReportMainFrame.bugFileEdit.getText()),
projectName.getText(), Version.getText().split("Ver")[1],
new SimpleDateFormat("yyyyMMdd").format(startTime.getValue()),
new SimpleDateFormat("yyyyMMdd").format(endTime.getValue()));
} catch (NumberFormatException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
activeOneBug.setValue(Integer.valueOf(ss[6]));
activeTwoBug.setValue(Integer.valueOf(ss[7]));
activeThreeBug.setValue(Integer.valueOf(ss[8]));
activeFourBug.setValue(Integer.valueOf(ss[9]));
newOneBug.setValue(Integer.valueOf(ss[2]));
newTwoBug.setValue(Integer.valueOf(ss[3]));
newThreeBug.setValue(Integer.valueOf(ss[4]));
newFourBug.setValue(Integer.valueOf(ss[5]));
}
});
}
/**
* 该方法用于在其他界面需要显示窗口时调用
*/
public static void showFrame() {
iniData();
frame.setVisible(true);
}
private static void iniData() {
// 设置读取到的参数
showBugFilePath.setText(TestReportMainFrame.bugFileEdit.getText());
projectName.setText(TestReportMainFrame.s[0]);
Version.setText(TestReportMainFrame.s[0] + "Ver" + TestReportMainFrame.s[1]);
try {
startTime.setValue(new SimpleDateFormat("yyyy.MM.dd").parse(TestReportMainFrame.s[14]));
} catch (ParseException e) {
e.printStackTrace();
}
try {
endTime.setValue(new SimpleDateFormat("yyyy.MM.dd").parse(TestReportMainFrame.s[15]));
} catch (ParseException e) {
e.printStackTrace();
}
range.setText(TestReportMainFrame.s[16]);
person.setText(TestReportMainFrame.s[17]);
purpose.setText(TestReportMainFrame.s[18]);
gist.setText(TestReportMainFrame.s[19]);
activeOneBug.setValue(Integer.valueOf(TestReportMainFrame.s[6]));
activeTwoBug.setValue(Integer.valueOf(TestReportMainFrame.s[7]));
activeThreeBug.setValue(Integer.valueOf(TestReportMainFrame.s[8]));
activeFourBug.setValue(Integer.valueOf(TestReportMainFrame.s[9]));
newOneBug.setValue(Integer.valueOf(TestReportMainFrame.s[2]));
newTwoBug.setValue(Integer.valueOf(TestReportMainFrame.s[3]));
newThreeBug.setValue(Integer.valueOf(TestReportMainFrame.s[4]));
newFourBug.setValue(Integer.valueOf(TestReportMainFrame.s[5]));
// 设置是否通过的复选框
if ((int) activeOneBug.getValue() > 0 || (int) activeTwoBug.getValue() > 0 || (int) newOneBug.getValue() > 0
|| (int) newTwoBug.getValue() > 0) {
isPass.setSelected(false);
} else {
isPass.setSelected(true);
}
updataContent();
}
private static void updataContent() {
StringBuilder testResult = new StringBuilder();
if ((int) activeOneBug.getValue() != 0 || (int) activeTwoBug.getValue() != 0
|| (int) activeThreeBug.getValue() != 0 || (int) activeFourBug.getValue() != 0) {
testResult.append("回归测试发现并激活" + String.valueOf((int) activeOneBug.getValue() + (int) activeTwoBug.getValue()
+ (int) activeThreeBug.getValue() + (int) activeFourBug.getValue()) + "个Bug其中");
if ((int) activeOneBug.getValue() != 0) {
testResult.append("一级Bug有" + (int) activeOneBug.getValue() + "个,");
}
if ((int) activeTwoBug.getValue() != 0) {
testResult.append("二级Bug有" + (int) activeTwoBug.getValue() + "个,");
}
if ((int) activeThreeBug.getValue() != 0) {
testResult.append("三级Bug有" + (int) activeThreeBug.getValue() + "个,");
}
if ((int) activeFourBug.getValue() != 0) {
testResult.append("四级Bug有" + (int) activeFourBug.getValue() + "个,");
}
testResult.replace(testResult.lastIndexOf(""), testResult.lastIndexOf("") + 1, "");
}
testResult.append("新发现并提交" + String.valueOf((int) newOneBug.getValue() + (int) newTwoBug.getValue()
+ (int) newThreeBug.getValue() + (int) newFourBug.getValue()) + "个Bug其中");
testResult.append("一级Bug有" + (int) newOneBug.getValue() + "个,");
testResult.append("二级Bug有" + (int) newTwoBug.getValue() + "个,");
testResult.append("三级Bug有" + (int) newThreeBug.getValue() + "个,");
testResult.append("四级Bug有" + (int) newFourBug.getValue() + "个;");
testResult.append("详情请查看禅道系统或者问题汇总中的Bug记录详情。");
// 多选框是否被勾选根据判断给出相应的文字结果
if (!isPass.isSelected()) {
testResult.append("由于该版本存在二级以上的Bug根据测试依据软件测试通过准则判定该版本测试结果为不通过。\n");
} else {
testResult.append("由于该版本未发现二级以上的Bug根据测试依据软件测试通过准则判定该版本测试结果为通过。\n");
}
//若有严重的BUG存在则获取其信息列表之后将严重的BUG信息放入报告中
if ( (int) newOneBug.getValue() != 0 || (int) newTwoBug.getValue() != 0) {
List<BugInformation> bugInformation = TestReportMainFrame.tr.getBugInformations();
testResult.append("其中严重的BUG基本信息如下\n");
for (int i = 0; i < bugInformation.size(); i++) {
testResult.append("");
testResult.append(bugInformation.get(i).bugTitle);
testResult.append(""+ bugInformation.get(i).bugLv + "级BUG禅道编号为" + bugInformation.get(i).bugID + "\n");
}
}
//添加未处理的BUG数量
if ( Integer.valueOf(TestReportMainFrame.s[10]) != 0 || Integer.valueOf(TestReportMainFrame.s[11]) != 0 ||
Integer.valueOf(TestReportMainFrame.s[12]) != 0 || Integer.valueOf(TestReportMainFrame.s[13]) != 0 ) {
testResult.append("在往期版本中发现存在未解决、延期处理的一、二级Bug总数为" +
(Integer.valueOf(TestReportMainFrame.s[10]) +
Integer.valueOf(TestReportMainFrame.s[11]) +
Integer.valueOf(TestReportMainFrame.s[12]) +
Integer.valueOf(TestReportMainFrame.s[13])) + "个,其中,");
if ( Integer.valueOf(TestReportMainFrame.s[10]) != 0 ) {
testResult.append("未解决的一级Bug有" + Integer.valueOf(TestReportMainFrame.s[10]) + "个,");
}
if ( Integer.valueOf(TestReportMainFrame.s[11]) != 0 ) {
testResult.append("未解决二级Bug有" + Integer.valueOf(TestReportMainFrame.s[11]) + "个,");
}
if ( Integer.valueOf(TestReportMainFrame.s[12]) != 0 ) {
testResult.append("延期解决的一级Bug有" + Integer.valueOf(TestReportMainFrame.s[12]) + "个,");
}
if ( Integer.valueOf(TestReportMainFrame.s[13]) != 0 ) {
testResult.append("延期解决的二级Bug有" + Integer.valueOf(TestReportMainFrame.s[13]) + "个,");
}
testResult.append("望技术经理、开发人员及项目经理重视!\n");
}
content.setText(testResult.toString());
}
}

View File

@ -0,0 +1,411 @@
package pres.auxiliary.report.ui;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.filechooser.FileNameExtensionFilter;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import pres.auxiliary.report.TestReport;
/**
* 测试报告主界面用于设置报告生成位置以及Bug列表文件的位置
* @author 彭宇琦
* @version Ver1.0
*/
public class TestReportMainFrame extends JFrame {
private static final long serialVersionUID = 1L;
static TestReport tr = new TestReport();
// 设置默认的文件保存位置
static String saveFilePath = "C:\\AutoTest\\Report";
/**
* 存储测试报告中的所有内容以下是存储的信息<br/>
* <table border="1">
* <tr>
* <td>s[0]:项目名称</td>
* <td>s[1]:当前版本</td>
* <td>s[2]:1级BUG数量</td>
* <td>s[3]:2级BUG数量</td>
* </tr>
* <tr>
* <td>s[4]:3级BUG数量</td>
* <td>s[5]:4级BUG数量</td>
* <td>s[6]:激活1级BUG数量</td>
* <td>s[7]:激活2级BUG数量</td>
* </tr>
* <tr>
* <td>s[8]:激活3级BUG数量</td>
* <td>s[9]:激活4级BUG数量</td>
* <td>s[10]:未解决的1级BUG数量</td>
* <td>s[11]:未解决的2级BUG数量</td>
* </tr>
* <tr>
* <td>s[12]:延期解决的1级BUG数量</td>
* <td>s[13]:延期解决的2级BUG数量</td>
* <td>s[14]:测试开始时间</td>
* <td>s[15]:测试结束时间</td>
* </tr>
* <tr>
* <td>s[16]:测试范围</td>
* <td>s[17]:测试人员</td>
* <td>s[18]:测试目的</td>
* <td>s[19]:测试依据</td>
* </tr>
* </table>
* <br/>
* <font size="3"><b>千万不要随意改动顺序需要添加则向下加不要覆盖前面的否则主界面会有BUG!</b></font>
*
*/
static String[] s = new String[20];
private JPanel contentPane;
static JTextField bugFileEdit;
private JTextField reportSavePathEdit;
// 创建自身窗口
static TestReportMainFrame frame = new TestReportMainFrame();
// 设置选择器选择默认位置为C:\\AutoTest\\Report
private JFileChooser chooser = new JFileChooser(new File(saveFilePath));
private JButton createFileButton = new JButton("\u9009\u62E9\u6587\u4EF6");
private JButton storyFileButton = new JButton("\u9009\u62E9\u6587\u4EF6");
private JLabel createFileLabel = new JLabel(
"\u8BF7\u9009\u62E9Bug\u6587\u4EF6\u4F4D\u7F6E\uFF1A");
private JLabel storyFileLabel = new JLabel(
"\u8BF7\u9009\u62E9\u62A5\u544A\u4FDD\u5B58\u4F4D\u7F6E\uFF1A");
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
frame.setVisible(true);
// 设置窗体显示在屏幕中心
frame.setLocationRelativeTo(null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 可以通过该方法调用测试报告主界面
*/
public static void Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
frame.setVisible(true);
// 设置窗体显示在屏幕中心
frame.setLocationRelativeTo(null);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public TestReportMainFrame() {
setTitle("\u6D4B\u8BD5\u62A5\u544A\u751F\u6210\u5668");
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 530, 207);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
final JButton confirm = new JButton("\u786E\u5B9A");
confirm.setBounds(193, 90, 93, 23);
contentPane.add(confirm);
JButton cancel = new JButton("\u53D6\u6D88");
// 添加取消按钮事件
cancel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 关闭窗体
Runtime.getRuntime().exit(0);
}
});
cancel.setBounds(369, 90, 93, 23);
contentPane.add(cancel);
createFileLabel.setBounds(10, 14, 134, 15);
contentPane.add(createFileLabel);
bugFileEdit = new JTextField();
bugFileEdit.setEditable(false);
bugFileEdit.setColumns(10);
bugFileEdit.setBounds(143, 11, 218, 21);
contentPane.add(bugFileEdit);
createFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 不允许用户多选
chooser.setMultiSelectionEnabled(false);
// 1表示文件夹0表示文件
chooser.setFileSelectionMode(0);
// 设置其选择的路径
chooser.setCurrentDirectory(new File(bugFileEdit.getText()));
// 判断文件是否存在若存在则设置在下一次打开选择文件窗口时能选中当前选择的文件
if (bugFileEdit.getText().isEmpty()) {
chooser.setSelectedFile(new File(bugFileEdit.getText()));
}
// 设置文件过滤器
chooser.setFileFilter(new FileNameExtensionFilter(
"请选择Excel文件或CSV文件(.xlsx .xls .csv)", "xlsx", "xls", "csv"));
// showOpenDialog(button)方法返回用户是否选择了文件夹
int returnVal = chooser.showOpenDialog(createFileButton);
if (returnVal == JFileChooser.APPROVE_OPTION) {
// chooser.getSelectedFile()方法返回一个File对象
bugFileEdit.setText(
chooser.getSelectedFile().getAbsolutePath());
}
}
});
createFileButton.setBounds(371, 10, 93, 23);
contentPane.add(createFileButton);
storyFileLabel.setBounds(10, 50, 134, 15);
contentPane.add(storyFileLabel);
reportSavePathEdit = new JTextField();
reportSavePathEdit.setText("C:\\AutoTest\\Report");
reportSavePathEdit.setEditable(false);
reportSavePathEdit.setColumns(10);
reportSavePathEdit.setBounds(143, 47, 218, 21);
contentPane.add(reportSavePathEdit);
storyFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// 不允许用户多选
chooser.setMultiSelectionEnabled(false);
// 1表示文件夹0表示文件
chooser.setFileSelectionMode(1);
// 设置其选择的路径
chooser.setCurrentDirectory(
new File(reportSavePathEdit.getText()));
// showOpenDialog(button)方法返回用户是否选择了文件夹
int returnVal = chooser.showOpenDialog(storyFileButton);
if (returnVal == JFileChooser.APPROVE_OPTION) {
// chooser.getSelectedFile()方法返回一个File对象
reportSavePathEdit.setText(
chooser.getSelectedFile().getAbsolutePath());
}
//设置测试报告的存放路径
tr.setSavePath(reportSavePathEdit.getText() + "\\");
}
});
storyFileButton.setBounds(371, 46, 93, 23);
contentPane.add(storyFileButton);
JButton btnbug = new JButton("\u5BFC\u51FA\u6587\u4EF6");
btnbug.setToolTipText("\u6839\u636E\u914D\u7F6E\u6587\u4EF6\u4E2D\u7684\u5185\u5BB9\uFF0C\u81EA\u52A8\u5411\u7985\u9053\u4E0A\u5BFC\u51FABug\u5217\u8868\u6587\u4EF6\uFF0C\u5E76\u5C06\u8DEF\u5F84\u586B\u5165Bug\u6587\u4EF6\u4F4D\u7F6E\u4E2D");
btnbug.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
Document dom = null;
try {
dom = new SAXReader().read(tr.xml);
} catch (DocumentException e1) {
e1.printStackTrace();
}
// 获取基本信息并存储
String url = dom.getRootElement().element("url")
.attributeValue("url");
String firefoxDirectory = dom.getRootElement()
.element("firefox").attributeValue("directory");
String firefoxProfiles = dom.getRootElement().element("firefox")
.attributeValue("profiles");
String username = dom.getRootElement().element("user")
.attributeValue("username");
String password = dom.getRootElement().element("user")
.attributeValue("password");
String search = dom.getRootElement().element("project")
.attributeValue("name");
String downloadSaveDirectory = dom.getRootElement()
.element("firefox")
.attributeValue("download_save_directory");
String downloadFileName = dom.getRootElement().element("report")
.attributeValue("download_file_name");
// 对禅道进行操作
try {
tr.operationZendao(firefoxDirectory, firefoxProfiles, url,
username, password, search, downloadFileName);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
bugFileEdit.setText(
downloadSaveDirectory + downloadFileName + ".csv");
}
});
btnbug.setBounds(10, 90, 93, 23);
contentPane.add(btnbug);
// 添加确定按钮的点击事件
confirm.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
Document dom = null;
try {
dom = new SAXReader().read(tr.xml);
} catch (DocumentException e1) {
e1.printStackTrace();
}
// 读取Bug列表文件
String[] ss = null;
try {
ss = tr.readFile(new File(bugFileEdit.getText()),
Integer.valueOf(dom.getRootElement()
.element("report").attributeValue("days")));
} catch (NumberFormatException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
// 记录从BUG列表文件中读取到的信息
int i = 0;
for (String str : ss) {
s[i++] = str;
}
// 存储测试开始和结束时间
// 判断是否需要修改测试时间若不需要则自动计算需要则直接读取
if (dom.getRootElement().element("report").element("content")
.element("time").attributeValue("is_change")
.equalsIgnoreCase("false")) {
// 存储测试结束时间即当前的时间
Date d = new Date();
// 设置测试开始时间调用Calendar类进行处理
Calendar calendar = Calendar.getInstance();
// 设置当前时间
calendar.setTime(d);
// 设置当前的天数减去测试时间得到测试开始时间
calendar.add(Calendar.DAY_OF_MONTH,
(1 - Integer.valueOf(
dom.getRootElement().element("report")
.attributeValue("days"))));
// 将得到的时间转换为Date进行返回
d = calendar.getTime();
// 存储测试开始时间
s[i++] = new SimpleDateFormat("yyyy.MM.dd").format(d);
d = new Date();
s[i++] = new SimpleDateFormat("yyyy.MM.dd").format(d);
// d.setDate(d.getDate() - testDay);//方法过时
} else {
s[i++] = dom.getRootElement().element("report")
.element("content").element("time")
.element("starttime").getText();
s[i++] = dom.getRootElement().element("report")
.element("content").element("time")
.element("endtime").getText();
}
// 添加测试范围
s[i++] = dom.getRootElement().element("report")
.attributeValue("range");
// 添加参与测试的人员
@SuppressWarnings("unchecked")
List<Element> l = dom.getRootElement().element("report")
.element("testperson").elements();
// 初始化存储的空间
s[i] = "";
for (Element ee : l) {
if (ee.attributeValue("participation")
.equalsIgnoreCase("true")) {
s[i] += ee.attributeValue("name");
s[i] += "";
}
}
// 截断字符串使其不包含最后一个顿号
s[i] = s[i].substring(0, s[i].lastIndexOf(""));
// 下标前进1
i++;
// 添加测试目的
@SuppressWarnings("unchecked")
List<Element> purposes = (List<Element>) dom.getRootElement()
.element("report").element("content").element("purpose")
.elements();
s[i] = "";
// 获取测试目的
for (int j = 0; j < purposes.size(); j++) {
s[i] += ((j + 1) + "." + purposes.get(j).getText() + "\n");
}
// 截断字符串使其不包含最后一个顿号
s[i] = s[i].substring(0, s[i].lastIndexOf("\n"));
// 下标前进1
i++;
// 读取配置文件中的测试依据
StringBuilder gist = new StringBuilder();
@SuppressWarnings("unchecked")
List<Element> gists = (List<Element>) dom.getRootElement()
.element("report").element("content").element("gist")
.elements();
s[i] = "";
// 获取测试目的
for (int j = 0; j < gists.size(); j++) {
// 修改带${name}
if (gists.get(j).getText().indexOf("${name}") > -1) {
gist.append((j + 1) + "." + gists.get(j).getText() + "\n");
//注意s[0]中存储的是项目名称
gist.replace(gist.indexOf("$"), gist.indexOf("}") + 1, s[0]);
} else {
gist.append((j + 1) + "." + gists.get(j).getText() + "\n");
}
}
s[i] = gist.toString();
// 截断字符串使其不包含最后一个换行符
s[i] = s[i].substring(0, s[i].lastIndexOf("\n"));
// // 设置本窗体不显示
frame.setVisible(false);
// 弹出TestReportFrame界面
TestReportFrame.showFrame();
}
});
}
}

View File

@ -0,0 +1,26 @@
package pres.auxiliary.report.ui;
import javax.swing.UIManager;
/**
* <p><b>文件名</b>TestReportUI.java</p>
* <p><b>用途</b>用于设置界面的样式并初始化测试报告UI界面</p>
* <p><b>编码时间</b>2018年12月19日 上午9:27:20</p>
* @author 彭宇琦
*/
public class TestReportUI {
/**
* 打开UI界面
*/
public static void open() {
//设置BeautyEye L&F样式
try{
org.jb2011.lnf.beautyeye.BeautyEyeLNFHelper.launchBeautyEyeLNF();
UIManager.put("RootPane.setupButtonVisible", false);
}
catch(Exception e){
}
TestReportMainFrame.Main();
}
}

View File

@ -0,0 +1,250 @@
package pres.auxiliary.selenium.browers;
import java.util.concurrent.TimeUnit;
import org.openqa.selenium.WebDriver;
/**
* 该类定义启动浏览器时必要的方法以及打开浏览器创建WebDriver对象的操作由新添加的各个浏览器子类可进行继承
*
* @author 彭宇琦
* @version Ver1.1
*
*/
public abstract class AbstractBrower {
/**
* 用于接收用户需要进入的网站
*/
private String url = "";
/**
* 用于接收浏览器启动所需的文件路径
*/
private String browserRunPath = "";
/**
* 存储页面加载等待时间
*/
private int loadTime = 120;
/**
* 用于存储目标站点的title
*/
private StringBuilder pageTitle = new StringBuilder("");
/**
* 用于存储页面自动刷新的次数默认为0次
*/
private int rafreshCount = 0;
/**
* 用于存储获取到的浏览器对象
*/
WebDriver driver = null;
/**
* 该方法用于返回待链接的站点
*
* @return 返回待链接的站点
*/
public String getURL() {
return url.toString();
}
/**
* 该方法用于设置待链接的站点
*
* @param uRL
* 待链接的站点
*/
public void setURL(String uRL) {
//判断待测站点是否有发生改变若未发生改变则不重新设置
if (!url.equalsIgnoreCase(uRL)) {
// 由于改变了浏览器的条件故初始化driver变量以便于重新打开浏览器
driver = null;
url = uRL;
}
}
/**
* 用于返回浏览器的启动路径对于火狐则为浏览器可执行文件所在路径对于谷歌浏览器即浏览器驱动所在路径
*
* @return 浏览器的启动路径
*/
public String getBrowserRunPath() {
return browserRunPath;
}
/**
* 用于设置浏览器的启动路径对于火狐则为浏览器可执行文件所在路径对于谷歌浏览器即浏览器驱动所在路径
*
* @param startBrowserPath
* 浏览器的启动路径
*/
public void setBrowserRunPath(String browserRunPath) {
//判断待测站点是否有发生改变若未发生改变则不重新设置
if (!this.browserRunPath.equalsIgnoreCase(browserRunPath)) {
// 由于改变了浏览器的条件故初始化driver变量以便于重新打开浏览器
driver = null;
this.browserRunPath = browserRunPath;
}
}
/**
* 该方法用于返回设置的目标站点的title
*
* @return 返回设置的目标站点的title
*/
public String getPageTitle() {
return pageTitle.toString();
}
/**
* 该方法用于设置目标站点的title以便进行链接是否正确的判断
*
* @param pageTitle
* 设置的目标站点title
*/
public void setPageTitle(String pageTitle) {
this.pageTitle.delete(0, this.pageTitle.length());
this.pageTitle.append(pageTitle);
}
/**
* 该方法用于返回设置的页面等待时间默认时间为120秒
*
* @return 返回页面等待时间
*/
public int getLoadTime() {
return loadTime;
}
/**
* 该方法用于设置页面等待时间整形单位为秒
*
* @param LoadTime
* 传入的时间
*/
public void setLoadTime(int loadTime) {
this.loadTime = loadTime;
}
/**
* 该方法用于返回自动刷新的次数默认为0次
*
* @return 返回自动刷新的次数
*/
public int getRafreshCount() {
return rafreshCount;
}
/**
* 该方法用于设置页面的自动刷新次数当设置该值后则开启自动刷新
*
* @param rafreshCount
* 自动刷新的次数
*/
public void setRafreshCount(int rafreshCount) {
this.rafreshCount = rafreshCount;
}
/**
* 该方法用于启动浏览器并返回WebDriver对象
*
* @return 指向浏览器的WebDriver对象
*/
public abstract WebDriver getDriver();
/**
* 获取浏览器的名称
*
* @return 浏览器名称
*/
public abstract String getBrowerName();
/**
* 获取浏览器版本
*
* @return 浏览器版本
*/
public abstract String getBrowerVersion();
/**
* 获取操作系统信息
*
* @return 操作系统信息
*/
public abstract String getSystemInformation();
/**
* 用于初始化浏览器
*/
public WebDriver initialization() {
driver.close();
driver = null;
return getDriver();
}
/**
* 用于关闭浏览器
*/
public void close() {
driver.quit();
driver = null;
}
/**
* 该方法用于对浏览器的一系列操作包括全屏浏览器跳转相应的站点等待页面加载以及自动刷新
* 使用该方法时会抛出两个运行时异常分别为IncorrectPageTitleException和PageNotFoundException
*
* @param driver
* 通过start()方法创建的WebDriver对象
* @return 返回对浏览器进行操作后的得到的WebDriver对象
* @throws IncorrectPageTitleException
* 页面title与设置的title不一致时抛出的异常
* @throws PageNotFoundException
* 页面加载失败时抛出的异常
*/
protected WebDriver oprateBrower(WebDriver driver) {
// 将设置的自动刷新次数存储在临时变量中并加上1
// 加1的目的是自动刷新判断是用do...while循环实现若不事先加上1在会导致循环少1次
int rafresh = rafreshCount + 1;
String errorTitle = "页面载入出错";
// 进入站点
driver.get(url);
// 全屏浏览器
driver.manage().window().maximize();
// 循环执行页面加载判断判断其是否加载出目标站点若加载出来页面则结束循环若用户设置的自动刷新次数循环完还没加载出页面
// 抛出PageNotFoundException异常页面加载判断必须读取一次所以使用do...while循环
do {
// 读取并设置浏览器等待时间
driver.manage().timeouts().pageLoadTimeout(loadTime, TimeUnit.SECONDS);
// 判断进入站点后页面的title是否为页面载入出错若为该title则刷新页面重新加载
// 注意在火狐浏览器中凡是加载不出的页面其页面title都是页面载入出错所以该方法只适用于火狐浏览器
if (errorTitle.equals(driver.getTitle())) {
// 将刷新次数减1
rafresh--;
// 刷新网页
driver.navigate().refresh();
// 不执行后续代码继续循环
continue;
}
// 若页面加载成功则判断加载的页面是否与用户设置的一致若用户未设置目标站点的title则跳过判断
// 判断pageTitle中存储的信息是否为空若不为空则再判断页面的title是否与设置的title一致若不一致则抛出IncorrectPageTileException
if (!pageTitle.toString().equals("") && !driver.getTitle().equals(pageTitle.toString())) {
continue;
}
// 若页面能正常加载置空pageTitle并返回WebDriver对象
pageTitle.delete(0, pageTitle.length());
return driver;
// 判断的条件刷新次数rafresh为0时则结束循环
} while (rafresh != 0);
// 若循环结束则说明页面无法正常加载则置空pageTitle抛出PageNotFountException
pageTitle.delete(0, pageTitle.length());
throw new IncorrectPageTitleException("页面载入出错");
}
}

View File

@ -0,0 +1,153 @@
package pres.auxiliary.selenium.browers;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
/**
* <p><b>文件名</b>ChromeBrower.java</p>
* <p><b>用途</b>
* 该类用于启动谷歌浏览器并通过getDriver()方法获取当前浏览器的WebDriver对象调用本类时可通过
* set方法设置chromedriver的所在路径待测试的站点也可通过构造方法进行设置亦可通过在
* getDriver()方法直接设置参数以达到启动浏览器的目的
* </p>
* <p><b>修改时间</b>2019年6月5日下午4:24:23</p>
*
* @author 彭宇琦
* @version Ver1.0
* @since Selenium 2.53.0
* @since JDK 1.7
*/
public class ChromeBrower extends AbstractBrower {
/**
* 定义ChromeOptions类当需要控制已打开的浏览器时则定义该类
* */
ChromeOptions cp = null;
/**
* 双参构造用于设置谷歌浏览器启动驱动路径及待测试的站点并创建对象
*
* @param driverPath
* 谷歌浏览器启动驱动路径
* @param url
* 待测试的站点
*/
public ChromeBrower(String driverPath, String url) {
setBrowserRunPath(driverPath);
setURL(url);
}
/**
* 该构造用于使用已打开的浏览器对浏览器进行操作
* @param port 端口号
*/
public ChromeBrower(String driverPath, int port) {
setBrowserRunPath(driverPath);
//构造ChromeOptions类设置传入的浏览器打开的端口号
cp = new ChromeOptions();
cp.setExperimentalOption("debuggerAddress", "127.0.0.1:" + port);
}
@Override
public String getBrowerName() {
return ((ChromeDriver) driver).getCapabilities().getBrowserName();
}
@Override
public String getBrowerVersion() {
return ((ChromeDriver) driver).getCapabilities().getVersion();
}
@Override
public String getSystemInformation() {
String s = ((ChromeDriver) driver).getCapabilities().getPlatform().name();
s += ((ChromeDriver) driver).getCapabilities().getPlatform().getMajorVersion();
return s;
}
@Override
public void close() {
//若是控制已打开的浏览器时其quit()方法无法关闭浏览器故需要用close()方法来关闭
if (cp == null) {
driver.quit();
driver = null;
} else {
driver.close();
driver = null;
}
}
/**
* 该方法用于设置需要控制的已打开的浏览器端口<br>
* <b>注意为了安全调用该方法时会将传入的url待测站点值清空</b>
* @param port 端口
*/
public void setPort(int port) {
//构造ChromeOptions类设置传入的浏览器打开的端口号
cp = new ChromeOptions();
cp.setExperimentalOption("debuggerAddress", "127.0.0.1:" + port);
//将WebDriver对象置空以便于重新制定WebDriver对象
driver = null;
//将待测站点的信息也置空
setURL("");
}
/**
* 该方法用于解除对已打开的浏览器的控制调用该方法后重新获取的WebDriver对象将重新打开浏览器
*/
public void removeControl() {
cp = null;
driver = null;
}
/**
* 该方法通过类中的属性打开浏览器跳转相应的站点并创建WebDriver对象使用前需要通过类中的set()方法为属性进行赋值
* 在运行过程中可能会抛出两个运行时异常分别为IncorrectPageTitleException和PageNotFoundException <br/>
* <b><i>注意若未传入目标站点或者目标站点为空则返回null</i></b>
*
* @return 返回浏览器的WebDriver对象
* @throws IncorrectPageTitleException
* 页面title与设置的title不一致时抛出的异常
* @throws PageNotFoundException
* 页面加载失败时抛出的异常
*/
@Override
public WebDriver getDriver() {
// 判断类中的driver是否为null不为null则直接返回
if (driver != null) {
return driver;
}
// 判断传入的站点信息是否为空若为空则返回null
if ("".equals(getURL()) && cp == null) {
return null;
}
// 判断是否存在谷歌浏览器启动驱动的安装路径若存在则添加谷歌浏览器启动驱动启动路径若不存在则抛出ChromedriverNotFoundException异常
if (!"".equals(getBrowserRunPath())) {
System.setProperty("webdriver.chrome.driver", getBrowserRunPath());
} else {
throw new ChromedriverNotFoundException("chromedriver文件没有找到");
}
//判断当前是否通过已打开的浏览器来进行测试
if (cp != null) {
//通过已打开的浏览器参数来创建WebDiver对象
driver = new ChromeDriver(cp);
//判断当前是否有传入url若url为空则不改变页面的url若url不为空则进行更改
if (!"".equals(getURL())) {
//获取并判断浏览器当前站点是否与传入的站点一致若不一致则改变url
if (!getURL().equalsIgnoreCase(driver.getCurrentUrl())) {
driver.get(getURL());
}
}
return driver;
} else {
// 创造WebDriver对象
driver = new ChromeDriver();
// 调用OprateBrower()方法并返回其操作后的WebDriver对象
return oprateBrower(driver);
}
}
}

View File

@ -0,0 +1,40 @@
package pres.auxiliary.selenium.browers;
/**
* 该异常在没有找到Chromedriver路径时抛出的异常继承于RuntimeException
* @author 彭宇琦
* @version Ver1.0
*/
public class ChromedriverNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ChromedriverNotFoundException() {
super();
// TODO Auto-generated constructor stub
}
public ChromedriverNotFoundException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public ChromedriverNotFoundException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public ChromedriverNotFoundException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public ChromedriverNotFoundException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,147 @@
package pres.auxiliary.selenium.browers;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.firefox.FirefoxDriver;
/**
* 该类用于启动火狐浏览器并通过getDriver()方法获取当前浏览器的WebDriver对象调用本类时可通过
* set方法设置火狐浏览器的启动路径待测试的站点和配置文件的位置也可通过构造方法进行设置亦可通过在
* getDriver()方法直接设置参数以达到启动浏览器的目的
*
* @author 彭宇琦
* @version Ver1.0
* @since Selenium 2.53.0
* @since JDK 1.7
*/
public class FirefoxBrower extends AbstractBrower {
// 存储配制文件名称
private String settingName = "";
/**
* 单参构造用于设置待测试的站点并创建对象
*
* @param url
* 待测试的站点
*/
public FirefoxBrower(String url) {
setURL(url);
}
/**
* 双参构造用于设置火狐浏览器安装路径及待测试的站点并创建对象
*
* @param firefoxPath
* 火狐浏览器的安装路径
* @param url
* 待测试的站点
*/
public FirefoxBrower(String firefoxPath, String url) {
setBrowserRunPath(firefoxPath);
setURL(url);
}
/**
* 叁参构造用于设置火狐浏览器安装路径及待测试的站点并创建对象
*
* @param firefoxPath
* 火狐浏览器的安装路径
* @param settingName
* 配置文件名称
* @param uRL
* 待测试的站点
*/
public FirefoxBrower(String firefoxPath, String settingName, String url) {
setBrowserRunPath(firefoxPath);
setSettingName(settingName);
setURL(url);
}
/**
* 该方法用于返回火狐浏览器配置文件的文件名
*
* @return 返回火狐浏览器配置文件的文件名
*/
public String getSettingName() {
return settingName;
}
/**
* 该方法用于设置火狐浏览器配置文件的文件名
*
* @param settingName
* 配置文件的文件名
*/
public void setSettingName(String settingName) {
//若配置文件名未改变则不重新赋值
if ( !this.settingName.equalsIgnoreCase(settingName) ) {
// 由于改变了浏览器的条件故初始化driver变量以便于重新打开浏览器
driver = null;
this.settingName = settingName;
}
}
@Override
public String getBrowerName() {
return ((FirefoxDriver) driver).getCapabilities().getBrowserName();
}
@Override
public String getBrowerVersion() {
return ((FirefoxDriver) driver).getCapabilities().getVersion();
}
@Override
public String getSystemInformation() {
String s = ((FirefoxDriver) driver).getCapabilities().getPlatform().name();
s += ((FirefoxDriver) driver).getCapabilities().getPlatform().getMajorVersion();
return s;
}
/**
* 该方法通过类中的属性打开浏览器跳转相应的站点并创建WebDriver对象使用前需要通过类中的set()方法为属性进行赋值
* 在运行过程中可能会抛出两个运行时异常分别为IncorrectPageTitleException和PageNotFoundException <br/>
* <b><i>注意若未传入目标站点或者目标站点为空则返回null</i></b>
*
* @return 返回浏览器的WebDriver对象
* @throws IncorrectPageTitleException
* 页面title与设置的title不一致时抛出的异常
* @throws PageNotFoundException
* 页面加载失败时抛出的异常
*/
@Override
public WebDriver getDriver() {
// 判断类中的driver是否为null不为null则直接返回
if (driver != null) {
return driver;
}
// 判断传入的站点信息是否为空若为空则返回null
if ("".equals(getURL())) {
return null;
}
// 判断是否存在火狐的安装路径若存在则添加火狐启动路径
if (!"".equals(getBrowserRunPath())) {
System.setProperty("webdriver.firefox.bin", getBrowserRunPath());
}
// 判断火狐的配置文件名是否为空若不为空则通过配置文件创建webdriver对象若为空则不使用配置文件创建对象
if (!"".equals(settingName)) {
// 通过配置文件创建webdriver对象并启动浏览器
//driver = new FirefoxDriver(new ProfilesIni().getProfile(settingName.toString()));
} else {
// 通过默认方式创建webdriver对象并启动浏览器
// 在创建对象时若火狐的路径不正确则会抛出WebDriverException异常捕捉该异常后再抛出FirefoxPathNotFountException的异常
try {
driver = new FirefoxDriver();
} catch (WebDriverException e) {
throw new FirefoxPathNotFoundException("指定的火狐浏览器安装路径不正确");
}
}
// 调用OprateBrower()方法并返回其操作后的WebDriver对象
return oprateBrower(driver);
}
}

View File

@ -0,0 +1,39 @@
package pres.auxiliary.selenium.browers;
/**
* 该异常在没有找到火狐路径时抛出的异常继承于RuntimeException
* @author 彭宇琦
* @version Ver1.0
*/
public class FirefoxPathNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public FirefoxPathNotFoundException() {
super();
// TODO Auto-generated constructor stub
}
public FirefoxPathNotFoundException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public FirefoxPathNotFoundException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public FirefoxPathNotFoundException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public FirefoxPathNotFoundException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,39 @@
package pres.auxiliary.selenium.browers;
/**
* 该异常在目标站点Title与设置的目标站点Title不一致的情况下抛出的异常继承于RuntimeException
*
* @author 彭宇琦
* @version Ver1.0
*/
public class IncorrectPageTitleException extends RuntimeException {
private static final long serialVersionUID = 1L;
public IncorrectPageTitleException() {
super();
// TODO Auto-generated constructor stub
}
public IncorrectPageTitleException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IncorrectPageTitleException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IncorrectPageTitleException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IncorrectPageTitleException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

View File

@ -0,0 +1,39 @@
package pres.auxiliary.selenium.browers;
/**
* 该异常为在页面无法加载出来时抛出的异常继承于RuntimeException
*
* @author 彭宇琦
* @version Ver1.0
*/
public class PageNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public PageNotFoundException() {
super();
// TODO Auto-generated constructor stub
}
public PageNotFoundException(String message, Throwable cause, boolean enableSuppression,
boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public PageNotFoundException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public PageNotFoundException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public PageNotFoundException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
package pres.auxiliary.selenium.datadriven;
/**
* 用于定义可向数据驱动中添加的预设模型
* @author 彭宇琦
*
*/
public enum DataMode {
/**
* 生成一组身份证号码
*/
IDCARD,
/**
* 生成一组手机号码
*/
MOBLE_PHONE,
/**
* 生成一组座机号码
*/
FIXED_PHONE,
/**
* 生成一组民用车牌
*/
CIVIL_CAR_LICECEN,
/**
* 生成一组警用车牌
*/
POLICE_CAR_LICECEN,
/**
* 生成一组大使馆车牌
*/
ELCHEE_CAR_LICECEN,
/**
* 生成一组新能源汽车车牌
*/
ENERGY_CAR_LICECEN,
/**
* 生成一组姓名
*/
NAME;
}

View File

@ -0,0 +1,27 @@
package pres.auxiliary.selenium.datadriven;
public class DataNotFoundException extends Exception {
public DataNotFoundException() {
super();
}
public DataNotFoundException(String arg0, Throwable arg1, boolean arg2, boolean arg3) {
super(arg0, arg1, arg2, arg3);
}
public DataNotFoundException(String arg0, Throwable arg1) {
super(arg0, arg1);
}
public DataNotFoundException(String arg0) {
super(arg0);
}
public DataNotFoundException(Throwable arg0) {
super(arg0);
}
private static final long serialVersionUID = -3984909521119511723L;
}

View File

@ -0,0 +1,169 @@
package pres.auxiliary.selenium.datadriven;
public class NumberDataDriven extends DataDriven {
// /**
// * 无参构造不做任何操作请使用{@link #setDataFile(File)}方法定义数据驱动文件
// */
// public NumberDataDriven() {
// super();
// }
//
// /**
// * 用于指定数据驱动文件
// *
// * @param dataFile
// * 数据驱动文件对象
// */
// public NumberDataDriven(File dataFile) {
// super(dataFile);
// }
//
// @Override
// public File createDataFile(String saveFileName, int minSize, int maxSize, int length) throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 0; i < length; i++) {
// // 添加随机数字
// sb.append(new RandomString(StringMode.NUM).toString(minSize, maxSize));
// sb.append("\r\n");
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
//
// @Override
// public File createDataFile(String saveFileName, int size, int length) throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 0; i < length; i++) {
// // 添加随机数字
// sb.append(new RandomString(StringMode.NUM).toString(size));
// sb.append("\r\n");
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
//
// /**
// * 该方法用于从数字1开始每次增加1步长来生成自然顺序的数字并写入文件中
// *
// * @param saveFileName
// * 数据驱动文件的文件名若为空或为null则默认为NewDataDriven文件的后缀为.txt
// * @param length
// * 数据生成个数
// * @return 生成的数据驱动文件对象
// * @throws IOException
// *
// * @see #createDataFile(String, int, int)
// * @see #createDataFile(String, int, int, int)
// */
// public File createContinuesNumberDataFile(String saveFileName, int length) throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 1; i < length + 1; i++) {
// // 添加随机数字
// sb.append("" + i);
// sb.append("\r\n");
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
//
// /**
// * 该方法用于根据起始数字通过增加一定的步长来生成自然顺序的数字并写入文件中
// *
// * @param saveFileName
// * 数据驱动的文件名
// * @param startNum
// * 起始数字
// * @param step
// * 步长
// * @param length
// * 生成数字的个数
// * @return 数据驱动文件对象
// * @throws IOException
// */
// public File createContinuesNumberDataFile(String saveFileName, int startNum, int step, int length)
// throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 0; i < length; i++) {
// // 添加随机数字
// sb.append("" + startNum);
// sb.append("\r\n");
//
// // 数字增加一步
// startNum += step;
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
//
// /**
// * 该方法用于向文件中添加身份证信息
// *
// * @param saveFileName
// * 数据驱动的文件名
// * @param length
// * 生成身份证的个数
// * @return 数据驱动文件对象
// * @throws IOException
// */
// public File createIDCardDataFile(String saveFileName, int length) throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 0; i < length; i++) {
// // 添加随机数字
// sb.append(PresetString.IdentityCard());
// sb.append("\r\n");
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
//
// /**
// * 该方法用于向文件中添加手机号码信息
// *
// * @param saveFileName
// * 数据驱动的文件名
// * @param length
// * 生成手机号码的个数
// * @return 数据驱动文件对象
// * @throws IOException
// */
// public File createPhoneDataFile(String saveFileName, int length) throws IOException {
// //用于存储生成的字符
// StringBuilder sb = new StringBuilder("");
// // 循环向文件中添加随机数字
// for (int i = 0; i < length; i++) {
// // 添加随机数字
// sb.append("139" + new RandomString(StringMode.NUM).toString(8));
// sb.append("\r\n");
// }
// //删除最后一个换行符
// sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
//
// // 返回数据驱动文件
// return createDataFile(saveFileName, sb);
// }
}

View File

@ -0,0 +1,41 @@
package pres.auxiliary.selenium.datadriven;
public class StringDataDriven extends DataDriven {
/*
@Override
public File createDataFile(String saveFileName, int minSize, int maxSize, int length) throws IOException, DataNotFoundException {
// 用于存储生成的字符
StringBuilder sb = new StringBuilder("");
// 循环向文件中添加随机数字
for (int i = 0; i < length; i++) {
// 添加随机字母
sb.append(new RandomString(StringMode.LOW, StringMode.CAP).toString(minSize, maxSize));
sb.append("\r\n");
}
// 删除最后一个换行符
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
// 返回数据驱动文件
return createDataFile(saveFileName, sb);
}
@Override
public File createDataFile(String saveFileName, int size, int length) throws IOException {
// 用于存储生成的字符
StringBuilder sb = new StringBuilder("");
// 循环向文件中添加随机数字
for (int i = 0; i < length; i++) {
// 添加随机数字
sb.append(new RandomString(StringMode.LOW, StringMode.CAP).toString(size));
sb.append("\r\n");
}
// 删除最后一个换行符
sb.delete(sb.lastIndexOf("\r\n"), sb.lastIndexOf("\r\n") + "\r\n".length());
// 返回数据驱动文件
return createDataFile(saveFileName, sb);
}
*/
}

View File

@ -0,0 +1,604 @@
package pres.auxiliary.selenium.event;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import org.dom4j.InvalidXPathException;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import pres.auxiliary.selenium.tool.RecordTool;
import pres.auxiliary.selenium.xml.PosMode;
import pres.auxiliary.selenium.xml.ReadXml;
import pres.auxiliary.selenium.xml.UndefinedElementException;
/**
* <p><b>文件名</b>AbstractEvent.java</p>
* <p><b>用途</b>所有事件类的基类包含了事件类所用到的基础方法以及弹窗处理方法和窗体窗口的切换方法</p>
* <p><b>编码时间</b>2019年9月24日下午4:24:15</p>
* <p><b>修改时间</b>2019年11月29日上午9:53:37</p>
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public abstract class AbstractEvent {
/**
* 用于存储浏览器的WebDriver对象设为静态保证所有的子类只使用一个WebDriver对象以避免造成WebDriver不正确导致的Bug
*/
private static WebDriver driver;
/**
* 用于指向存储控件定位方式的xml文件
*/
private static ReadXml xml;
/**
* 设置显示等待的超时时间默认3秒
*/
private long waitTime = 3;
/**
* 用于构造显示等待类对象
*/
private WebDriverWait wait;
/**
* 存储单个控件的等待时间
*/
private HashMap<String, Long> controlWaitTime = new HashMap<String, Long>();
/**
* 用于存储当前浏览器窗口的Handles值
*/
private String browserHandles;
/**
* 存储当前定位的窗体层级
*/
private static ArrayList<String> iframeNames = new ArrayList<>();
/**
* 控制是否自动切换窗体由于通过Event类调用时会构造另一个事件类但每个类都应共享一个开关故需要加上static
*/
private static boolean switchIframe = true;
/**
* 用于存储上一个获取到的元素
*/
private WebElement oldElement = null;
/**
* 用于存储上一个获取到的元素的style属性
*/
private String oldElementStyle = "";
/**
* 返回是否自动切换窗体
* @return 是否自动切换窗体
*/
public boolean isSwitchIframe() {
return switchIframe;
}
/**
* 设置是否自动切换窗体
* @param switchIframe 是否自动切换窗体
*/
public void setSwitchIframe(boolean switchIframe) {
this.switchIframe = switchIframe;
}
/**
* 构造对象并存储浏览器的WebDriver对象
*
* @param driver 浏览器的WebDriver对象
*/
public AbstractEvent(WebDriver driver) {
this.driver = driver;
browserHandles = this.driver.getWindowHandle();
wait = new WebDriverWait(driver, waitTime, EventConstants.FIND_TIME);
}
/**
* 用于返回等待时间
*
* @return 等待时间
*/
public long getWaitTime() {
return waitTime;
}
/**
* 用于设置等待时间
*
* @param waitTime 等待时间
*/
public void setWaitTime(long waitTime) {
this.waitTime = waitTime;
wait = new WebDriverWait(driver, this.waitTime, 200);
}
/**
* 该方法用于返回浏览器的WebDriver对象
*
* @return 浏览器的WebDriver对象
*/
public WebDriver getDriver() {
return driver;
}
/**
* 该方法用于设置浏览器的WebDriver对象
*
* @param driver 浏览器的WebDriver对象
*/
public void setDriver(WebDriver driver) {
// 判断传入WebDriver对象是否为空为空则抛出异常
if (driver == null) {
throw new WebDriverException("无效的WebDriver对象");
}
this.driver = driver;
browserHandles = this.driver.getWindowHandle();
}
/**
* 用于设置指向存储元素定位方式的xml文件对象
*
* @param xmlFile 存储元素定位方式的xml文件对象
*/
public void setXmlFile(File xmlFile) {
xml = new ReadXml(xmlFile);
}
/**
* 用于返回ReadXml类对象
* @return ReadXml类对象
*/
public ReadXml getXml() {
return xml;
}
/**
* 用于返回写入xml文件的或传入的元素定位方式mode=position的形式输出
*
* @param name 控件的名称或xpath与css定位方式
* @return 元素定位方式
*/
public String getElementPosition(String name) {
// 智能匹配方式
// 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
throw new TimeoutException("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
} else {
// 页面查找元素并存储该元素
return mode + "=" + xml.getValue(name, mode);
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素定位方式类型无法识别:" + name);
// 若都不匹配则抛出异常
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + name);
} else {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
return PosMode.XPATH.getValue() + "=" + name;
case CSS:
return PosMode.CSS.getValue() + "=" + name;
default:
return "";
}
}
}
}
/**
* 用于对单个控件设置等待时间
*
* @param name 控件名称
* @param waitTime 等待时间
*/
public void setContorlWaitTime(String name, long waitTime) {
controlWaitTime.put(name, waitTime);
}
/**
* 该方法用于将窗体切回顶层当本身是在最顶层时则该方法将使用无效
*/
public void switchRootFrame() {
driver.switchTo().defaultContent();
iframeNames.clear();
}
/**
* 该方法用于将窗体切换到上一层父层当本身是在最顶层时则该方法将使用无效
*/
public void switchParentFrame() {
driver.switchTo().parentFrame();
iframeNames.remove(iframeNames.size() - 1);
}
/**
* 该方法用于通过悬浮窗名称使用xpath的定位方式将页面切换至悬浮窗iframe标签
*
* @param name 悬浮窗的名称
*/
public void switchFrame(String name) {
//获取父窗体的窗体名称
String parentIframeName = xml.getIframeName(name);
//判断窗体是否存在父窗体若不存在父窗体返回值为空则切换若有则递归调用该方法直到找到最顶层窗体为止
if (parentIframeName.isEmpty()) {
//清空iframeNames中的内容
iframeNames.clear();
//将窗体切换到顶层
driver.switchTo().defaultContent();
} else {
switchFrame(parentIframeName);
}
//记录当前自动切换的窗体的状态
boolean isSwitchFrame = isSwitchIframe();
//切换窗体前设置不自动切换窗体避免窗体的循环切换
setSwitchIframe(false);
//切换窗体
driver.switchTo().frame(judgeElementMode(name));
//切换窗体后还原原始的切换窗体状态
setSwitchIframe(isSwitchFrame);
//存储窗体切换记录
iframeNames.add(name);
}
/**
* 该方法可用于切换弹出的窗口新标签或新窗口并返回新窗口的WebDriver对象若无新窗口则返回当前的窗口的WebDriver对象
* 注意该方法只能切换弹出一个窗口的情况若有多个窗口通过该方法无法准确定位可参考方法{@link #switchWindow(String)}
*/
public void switchWindow() {
Set<String> handles = driver.getWindowHandles();
// 判断是否只存在一个窗体若只存在一个则直接返回当前浏览器的WebDriver对象
if (handles.size() == 1) {
return;
}
// 获取当前窗口的handle
String winHandle = driver.getWindowHandle();
// 循环获取所有的页面handle
for (String newWinHandle : handles) {
// 判断获取到的窗体handle是否为当前窗口的handle若不是则将其定位到获取的handle对应的窗体上
if (!newWinHandle.equals(winHandle)) {
driver.switchTo().window(newWinHandle);
}
}
throw new NoSuchWindownException("未找到相应的窗体");
}
/**
* 该方法用于将窗口切换回最原始的窗口上
*/
public void switchOldWindow() {
driver.switchTo().window(browserHandles);
}
/**
* 该方法可根据控件名称之后对比每一个弹窗若某一个弹窗上存在元素名对应的元素则返回相应
* 窗口的WebDriver对象,若无新窗口则返回当前的窗口的WebDriver对象当所有的窗体都
* 不包含相应的元素时则抛出NoSuchWindownException异常
*
* @param controlName 控件名称
* @throws NoSuchWindownException 窗口未找到时抛出的异常
*/
public void switchWindow(String controlName) {
Set<String> handles = driver.getWindowHandles();
// 判断是否只存在一个窗体若只存在一个则直接返回当前浏览器的WebDriver对象
if (handles.size() == 1) {
return;
}
// 循环获取所有的页面handle
for (String newWinHandle : handles) {
driver.switchTo().window(newWinHandle);
// 调用judgeElementMode()方法来判断元素是否存在如果元素存在则返回相应页面的WebDriver对象若抛出异常元素不存在则返回当前
try {
judgeElementMode(controlName);
} catch (TimeoutException e) {
continue;
}
}
throw new NoSuchWindownException("未找到存在元素" + controlName + "所在的窗体");
}
/**
* 定位到弹框上并且点击确定按钮
*
* @return 弹框上的文本
*/
public String alertAccept() {
String text = alertGetText();
driver.switchTo().alert().accept();
return text;
}
/**
* 定位到弹框上并且点击取消按钮
*
* @return 弹框上的文本
*/
public String alertDimiss() {
String text = alertGetText();
driver.switchTo().alert().dismiss();
return text;
}
/**
* 定位到弹框上并且在其文本框中输入信息
*
* @param content 需要输入的信息
* @return 弹框上的文本
*/
public String alertInput(String content) {
String text = alertGetText();
driver.switchTo().alert().sendKeys("");
return text;
}
/**
* 获取弹框上的文本
*
* @return 弹框上的文本
*/
public String alertGetText() {
return driver.switchTo().alert().getText();
}
/**
* <p>
* 用于根据传入的控件名称或定位方式对控件在页面上定位返回其WebElement对象形参可以传入在xml文件中元素的名称
* 亦可以传入页面元素的定位方式但目前识别只支持xpath和css两种方式
* 该方法获取的是单个元素但本质是调用了{@link #judgeElementModes(String)}方法只是将其容器中第一个元素进行返回
* 可用于普通元素事件获取页面元素中使用
* </p>
* <p>
* 元素识别判断方式按照以下步骤进行<br>
* 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止<br>
* 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置<br>
* 3.若仍找不到元素则抛出UnrecognizableLocationModeException
* </p>
*
* @param text 元素名称或元素的定位方式
* @return 返回页面元素WebElement对象
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
protected WebElement judgeElementMode(String name) {
return judgeElementModes(name).get(0);
}
/**
* <p>
* 用于根据传入的控件名称或定位方式对控件在页面上定位返回其WebElement对象形参可以传入在xml文件中元素的名称
* 亦可以传入页面元素的定位方式但目前识别只支持xpath和css两种方式
* 该方法获取的是一组元素可用于对列表元素事件中
* </p>
* <p>
* 元素识别判断方式按照以下步骤进行<br>
* 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止<br>
* 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置<br>
* 3.若仍找不到元素则抛出UnrecognizableLocationModeException
* </p>
*
* @param name 元素名称或元素的定位方式
* @return 返回页面一组元素WebElement的对象
* @throws TimeoutException 元素在指定时间内未查找到时抛出的异常
* @throws UnrecognizableLocationModeException 元素无法识别时抛出的异常
*/
protected List<WebElement> judgeElementModes(String name) {
// 获取当前的等待时间若有对单个控件设置等待时间时此处可以将等待时间设置回原来的时间
long time = getWaitTime();
// 判断是否有设置对单个控件增加等待时间若存在该控件则将等待时间设置为该控件设置的等待时间
if (controlWaitTime.containsKey(name)) {
setWaitTime(controlWaitTime.get(name));
}
// 存储最终识别得到元素
List<WebElement> elements = null;
// 智能匹配方式
// 1.先对xml文件进行扫描若存在该元素对应的标签则读取xml文件的定位方式并识别有效的定位方式一一匹配直到正确为止
// 2.若在xml文件中查找不到该元素则按照xpath和css的规则进行匹配直到判断出该元素的定位方式位置
// 3.若仍找不到元素则抛出UnrecognizableLocationModeException
try {
PosMode mode = readXml(name);
// 判断readXML()方法的返回值是否为空串若为空串则抛出TimeoutException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
throw new TimeoutException("元素查找超时或不存在请检查xml文件中“" + name + "”对应元素的定位方式");
} else {
// 页面查找元素并存储该元素
elements = driver.findElements(xml.getBy(name, mode));
}
} catch (UndefinedElementException | NullPointerException | InvalidXPathException e) {
PosMode mode = readValue(driver, name);
// 判断readValue()方法的返回值是否为空串若为空串则抛出UnrecognizableLocationModeException
if (mode == null) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素定位方式类型无法识别:" + name);
// 若都不匹配则抛出异常
throw new UnrecognizableLocationModeException("元素定位方式类型无法识别:" + name);
} else {
//若有返回定位方式则根据定位方式类型获取其元素
switch (mode) {
case XPATH:
elements = driver.findElements(By.xpath(name));
break;
case CSS:
elements = driver.findElements(By.cssSelector(name));
break;
default:
break;
}
}
}
// 设置等待时间为原来的等待时间
setWaitTime(time);
// 返回页面元素对象
return elements;
}
/**
* 该方法用于通过传入的控件名称在xml文件中查找其元素相应的定位方式并在页面上进行查找 若在相应的时间内查找到该元素则将其定位方式进行返回
*
* @param name 控件名称
* @return 查找到的定位方式名称
*/
protected PosMode readXml(String name) {
// 循环逐个在页面上配对有效的标签对应的定位方式
for (PosMode mode : xml.getElementMode(name)) {
// 在页面上查找元素定位方式
try {
//自动定位元素所在的窗体
if (isSwitchIframe()) {
autoSwitchIframe(xml.getIframeName(name));
}
//查找元素
wait.until(ExpectedConditions.presenceOfElementLocated(xml.getBy(name, mode)));
} catch (TimeoutException exception) {
// 若查找超时则重新查找
continue;
}
// 若在页面上找到该元素则将该元素的定位方式存储
return mode;
}
// 若循环结束后仍未能找到该元素则返回一个空串
return null;
}
/**
* 用于自动定位元素所在窗体
* @param iframeName 元素所在窗体名称
*/
protected void autoSwitchIframe(String iframeName) {
//判断传入的窗体名称是否为空若为空说明元素在主窗体上
if (iframeName.isEmpty()) {
//判断当前定位是否在主窗体上iframeNames无元素时若不在主窗体上则切换到主窗体若在则直接结束
if (iframeNames.size() != 0) {
//将窗体切换到顶层
switchRootFrame();
return;
} else {
return;
}
}
//判断当前元素所在的窗体是否与已切换的窗体列表中最后一个元素当前窗体的内容相同相同则直接返回无需操作
//获取最后一层窗体的名称若iframeNames为空则返回空串
String nowIframeName = (iframeNames.isEmpty() ? "" : iframeNames.get(iframeNames.size() - 1));
if (iframeName.equals(nowIframeName)) {
return;
}
//若传入的字符串不为空则表示当前窗体不在主窗体上则判断其是否在已切换的窗体列表中若在则通过层级返回
//无需再次重新定位避免等待时间太长若不在则重新定位窗体
int index = 0;
if ((index = iframeNames.indexOf(iframeName)) > -1) {
//循环将窗体一层一层返回
for(int i = 1; i < iframeNames.size() - index; i++) {
switchParentFrame();
}
} else {
//若当前元素的窗体不在当前窗体的父窗体则重新定位窗体
switchFrame(iframeName);
}
}
/**
* 该方法用于在xml文件查找不到对应的元素时则再对传入的参数进行xpath和css的比较
* 以确认是否为直接传值若不为xpath和css中的一种则抛出UnrecognizableLocationModeException
*
* @param driver WebDriver对象
* @param text 定位方式
* @return 定位方式的类型
*/
protected PosMode readValue(WebDriver driver, String text) {
// 定义判断参数为xpath的字符
String judgeXpath = "/";
// 定义判断参数为css的字符
String judgeCss = "html";
try {
// 如果抛出元素名称查找不到的的异常则对应匹配xpath和css两种定位方式
// 匹配xpath定位判定方法判断text的第一个字符是否是/
if (text.indexOf(judgeXpath) == 0) {
// 查找该定位方式在有限的时间内是否内被查到
wait.until(ExpectedConditions.presenceOfElementLocated(By.xpath(text)));
return PosMode.XPATH;
// 将等待时间设置回原来的
} else if (text.indexOf(judgeCss) == 0) {
// 匹配css判断方法判断text的前四个字符是否是html
wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(text)));
return PosMode.CSS;
} else {
return null;
}
} catch (TimeoutException exception) {
// 将错误信息写入到记录工具的备注中
RecordTool.recordMark("元素查找超时或不存在,请检查“" + text + "”定位方式");
throw new TimeoutException("元素查找超时或不存在,请检查“" + text + "”定位方式");
}
}
/**
* 用于将页面控件元素高亮显示
* @param newElement 当前指向的元素
*/
protected void elementHight(WebElement newElement) {
//判断当前指向的元素是否与原来存储的元素一致若不一致且有之前有存储元素则解除之前元素的控件高亮
if (oldElement != newElement && oldElement != null) {
// 解除控件高亮若因为页面跳转导致页面过期时则不处理其异常
try {
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])",
oldElement, oldElementStyle);
} catch (StaleElementReferenceException exception) {
}
}
//获取当前指向的元素的style属性
String newElementStyle = newElement.getAttribute("style");
// 控件高亮
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])", newElement,
newElementStyle + "background:yellow;solid:red;");
//将当前指向的元素及其属性存储至属性中
oldElement = newElement;
oldElementStyle = newElementStyle;
}
}

View File

@ -0,0 +1,162 @@
package pres.auxiliary.selenium.event;
import org.openqa.selenium.StaleElementReferenceException;
import org.openqa.selenium.TimeoutException;
import org.openqa.selenium.WebDriver;
import pres.auxiliary.selenium.event.inter.ClickEventInter;
import pres.auxiliary.selenium.event.inter.ClickInter;
import pres.auxiliary.selenium.event.inter.DoubleClickInter;
import pres.auxiliary.selenium.event.inter.RightClickInter;
import pres.auxiliary.selenium.tool.RecordTool;
/**
* <p>
* <b>文件名</b>ClickEvent.java
* </p>
* <p>
* <b>用途</b>定义了对控件进行点击操作相关的方法可通过该类对页面进行基本的点击操作
* </p>
* <p>
* <b>编码时间</b>2019年8月29日下午3:24:34
* </p>
* <p>
* <b>修改时间</b>2019年11月29日上午9:53:37
* </p>
*
* @author 彭宇琦
* @version Ver1.0
* @since JDK 12
*
*/
public class ClickEvent extends CommenElementEvent implements ClickEventInter {
/**
* 构造ClickEvent类对象
*
* @param driver WebDriver类对象
*/
public ClickEvent(WebDriver driver) {
super(driver);
}
@Override
public Event click(String name) {
try {
// 为避免出现抛出StaleElementReferenceException页面过期异常则通过循环的方式
// 当抛出异常时则重新获取并操作若未抛出则结束循环
while (true) {
try {
//获取元素
element = judgeElementMode(name);
/*
// 获取原style属性
style = element.getAttribute("style");
// 控件高亮
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])", element,
style + "background:yellow;solid:red;");
*/
//修饰元素
elementHight(element);
//操作元素
ClickInter.click(element);
break;
} catch (StaleElementReferenceException e) {
continue;
}
}
/*
// 解除控件高亮若因为页面跳转导致页面过期时则不处理其异常
try {
((JavascriptExecutor) getDriver()).executeScript("arguments[0].setAttribute('style',arguments[1])",
element, style);
} catch (StaleElementReferenceException exception) {
}
*/
} catch (TimeoutException timeException) {
RecordTool.recordException(new TimeoutException("元素查找超时或不存在,请检查“" + name + "”对应元素的定位方式"));
throw new TimeoutException("元素查找超时或不存在,请检查中“" + name + "”对应元素的定位方式");
} catch (Exception exception) {
// 捕捉到异常后将异常信息记录在工具中并将异常抛出
RecordTool.recordException(exception);
throw exception;
} finally {
RecordTool.recordStep("点击“" + name + "”对应控件");
}
// 返回Event类
return Event.newInstance(getDriver());
}
@Override
public Event doubleClick(String name) {
try {
// 为避免出现抛出StaleElementReferenceException页面过期异常则通过循环的方式
// 当抛出异常时则重新获取并操作若未抛出则结束循环
while (true) {
try {
//获取元素
element = judgeElementMode(name);
//修饰元素
elementHight(element);
//操作元素
DoubleClickInter.doubleClick(getDriver(), element);
break;
} catch (StaleElementReferenceException e) {
continue;
}
}
} catch (TimeoutException timeException) {
RecordTool.recordException(new TimeoutException("元素查找超时或不存在,请检查“" + name + "”对应元素的定位方式"));
throw new TimeoutException("元素查找超时或不存在,请检查中“" + name + "”对应元素的定位方式");
} catch (Exception exception) {
// 捕捉到异常后将异常信息记录在工具中并将异常抛出
RecordTool.recordException(exception);
throw exception;
} finally {
RecordTool.recordStep("双击“" + name + "”对应控件");
}
// 返回Event类
return Event.newInstance(getDriver());
}
@Override
public Event rightClick(String name) {
try {
// 为避免出现抛出StaleElementReferenceException页面过期异常则通过循环的方式
// 当抛出异常时则重新获取并操作若未抛出则结束循环
while (true) {
try {
//获取元素
element = judgeElementMode(name);
//修饰元素
elementHight(element);
//操作元素
RightClickInter.rightClick(getDriver(), element);
break;
} catch (StaleElementReferenceException e) {
continue;
}
}
} catch (TimeoutException timeException) {
RecordTool.recordException(new TimeoutException("元素查找超时或不存在,请检查“" + name + "”对应元素的定位方式"));
throw new TimeoutException("元素查找超时或不存在,请检查中“" + name + "”对应元素的定位方式");
} catch (Exception exception) {
// 捕捉到异常后将异常信息记录在工具中并将异常抛出
RecordTool.recordException(exception);
throw exception;
} finally {
RecordTool.recordStep("右击“" + name + "”对应控件");
}
// 返回Event类
return Event.newInstance(getDriver());
}
}

Some files were not shown because too many files have changed in this diff Show More