├── LICENSE ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── github │ │ └── qihootest │ │ └── leo │ │ ├── dispatch │ │ ├── DispatchConf.java │ │ ├── ExecTask.java │ │ ├── log │ │ │ └── TestngLog.java │ │ ├── report │ │ │ ├── ExportReportHtml.java │ │ │ ├── TestReport.java │ │ │ └── TngCount.java │ │ ├── run │ │ │ ├── TestRunInfo.java │ │ │ ├── TestngRun.java │ │ │ └── TestngRunSingle.java │ │ └── testcase │ │ │ ├── CreateXmlFile.java │ │ │ ├── DataFileCase.java │ │ │ ├── ICase.java │ │ │ ├── JavaFileCase.java │ │ │ ├── SuperCase.java │ │ │ └── XmlFileCase.java │ │ ├── ift │ │ ├── IftConf.java │ │ ├── IftExec.java │ │ ├── core │ │ │ ├── CasesUtils.java │ │ │ ├── CompareResult.java │ │ │ └── IFtResultInfo.java │ │ ├── testcase │ │ │ ├── IftTestCase.java │ │ │ ├── autocreate │ │ │ │ ├── CreateJavaFile.java │ │ │ │ ├── IftDataFileCase.java │ │ │ │ └── JavaCaseInfo.java │ │ │ └── format │ │ │ │ ├── FormatCase.java │ │ │ │ └── ReadCaseFromExcel.java │ │ └── util │ │ │ ├── CommonSign.java │ │ │ └── ExportReportExcel.java │ │ └── toolkit │ │ ├── QtafException.java │ │ ├── TkConf.java │ │ ├── dbunit │ │ ├── DbUnitUtil.java │ │ └── data │ │ │ └── excel │ │ │ ├── XlsDataSet.java │ │ │ ├── XlsDataSetWriter.java │ │ │ ├── XlsTable.java │ │ │ └── XlsTableWrapper.java │ │ ├── httpclient │ │ ├── HttpUtil.java │ │ ├── HttpsUtil.java │ │ └── ResponseInfo.java │ │ ├── mysql │ │ ├── ConnMysql.java │ │ ├── MysqlUtil.java │ │ └── dao │ │ │ ├── DaoUtil.java │ │ │ ├── ITable.java │ │ │ └── Table.java │ │ └── util │ │ ├── CommUtils.java │ │ ├── CompilerUtil.java │ │ ├── ExcelUtil.java │ │ ├── FileUtil.java │ │ ├── FreeMakerUtil.java │ │ ├── JsonUtil.java │ │ ├── LogUtil.java │ │ ├── PropUtil.java │ │ ├── SftpExecUtil.java │ │ ├── SftpFileUtil.java │ │ ├── StringUtil.java │ │ └── XmlUtil.java └── resources │ ├── IftConf.properties │ ├── Template.ftl │ ├── log4j.properties │ └── testng-results.xsl └── test └── java └── com └── github └── qihootest └── leo ├── dispatch ├── TestDispatchConf.java ├── TestExecTask.java └── TestTestngLog.java ├── ift └── core │ └── CompareResultTest.java └── toolkit ├── TestDbunitUtil.java ├── TestMysqlUtil.java └── att_click_info.java /README.md: -------------------------------------------------------------------------------- 1 | Leo 2 | ===== 3 | 4 | 接口自动化测试框架 1.0.7-SNAPSHOT 5 | 6 | 1.0.7-SNAPSHOT 更新内容 7 | ----------------------------------------------------- 8 | 1.增加对cookie的接口依赖;在预期结果中增加${cookie},会将cookie做为变量传递到其它参数中; 9 | 2.增加httpClient线程池管理,解决多线程请求时“[ERROR] CasesUtils - Invalid use of BasicClientConnManager: connection still allocated.”的问题; 10 | 3.修复多线程时更新请求参数时资源同步问题;(现在业务类方法不需要继承casesUtils) 11 | 12 | 13 | 14 | 1.0.6 更新内容 15 | ------------------------------- 16 | 1. 增加接口依赖,以${}标示,预期结果中支持多个相同参数以下划线加后缀进行区分,eg:${key_01}; 17 | 2. 请求参数中支持依赖参数部分替换;eg:value${key_01}value 只会替换${}中的内容; 18 | 3. 修复当有多个数据库连接操作时,只能实例化一个数据库连接; 19 | 20 | 21 | 1.0.5 更新内容 22 | ------------------------------- 23 | 1. 解决生成javadoc时WARNING; 24 | 2. 当预期结果为int类型时,对实际结果为0进行判断(0为int结果匹配中的特殊值,0不包含在关键词int中); 25 | 3. 支持用例多线程方式,提高运行效率; 26 | 4. 支持对Sheet中的多用例进行多线程(即:methods方式);可对多个Sheet页进行多线程执行(即:tests方式); 27 | 5. 可自定义线程数; 28 | 6. 支持实际结果为json数组的处理;相同的key,value用数组表示,预期结果可写成数组行完全匹配,也可以写单个值进行包含匹配; 29 | 30 | 31 | 32 | 1.0.4 更新内容: 33 | ------------------------------- 34 | 1. 增加设置预期结果中"date"关键词dateFormat样式,可自定义关键词date样式; 35 | 2. 预期结果中增加对int关键词的支持,匹配结果中int类型动态值,支持单个和多个实际结果(key=int或key=int^int); 36 | 3. 增加Host关键字及全局配置; 37 | 4. 增加Header全局配置; 38 | 5. 修改注解; 39 | 40 | 41 | 1.0.3 更新内容: 42 | ------------------------------- 43 | 1. pom.xml中增加邮件包依赖; 44 | 2. 增加https请求处理(支持证书认证与非证书认证两种方式) 45 | 3. 修改解析xml时一个key对应多个值时,实际结果值与预期结果值无法进行比较(key=[value1,value2]) 46 | 4. CompareResult.trimActres 修改为public类型提供业务处理使用; 47 | 5. 修改代理默认值bug; -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.sonatype.oss 4 | oss-parent 5 | 7 6 | 7 | 8 | 9 | 10 | 11 | sonatype-nexus-snapshots 12 | Sonatype Nexus Snapshots 13 | https://oss.sonatype.org/content/repositories/snapshots 14 | 15 | 16 | 17 | sonatype-nexus-staging 18 | Nexus Staging Repository 19 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 20 | 21 | 22 | 23 | 4.0.0 24 | com.github.qihootest 25 | leo 26 | 1.0.7-SNAPSHOT 27 | jar 28 | 29 | leo 30 | https://github.com/QihooTest/Leo 31 | 32 | 33 | 34 | The Apache Software License, Version 2.0 35 | http://www.apache.org/licenses/LICENSE-2.0.txt 36 | repo 37 | 38 | 39 | 40 | scm:svn:https://github.com/QihooTest/Leo/trunk/ 41 | scm:svn:https://github.com/QihooTest/Leo/trunk/ 42 | https://github.com/QihooTest/Leo/trunk/ 43 | 44 | 45 | UTF-8 46 | true 47 | 48 | 49 | 50 | 51 | 52 | org.apache.maven.plugins 53 | maven-compiler-plugin 54 | 2.3.2 55 | 56 | 7 57 | 7 58 | UTF-8 59 | UTF-8 60 | 61 | 62 | 63 | org.apache.maven.plugins 64 | maven-surefire-plugin 65 | 2.17 66 | 67 | -Dfile.encoding=UTF-8 68 | 69 | **/*.java 70 | 71 | 72 | once 73 | 74 | 75 | 76 | maven-assembly-plugin 77 | 78 | 79 | jar-with-dependencies 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | src/main/resources 89 | 90 | **/*.* 91 | 92 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | org.testng 104 | testng 105 | 6.8.7 106 | jar 107 | compile 108 | 109 | 110 | 111 | net.sf.saxon 112 | saxon 113 | 8.7 114 | jar 115 | compile 116 | 117 | 118 | 119 | org.freemarker 120 | freemarker 121 | 2.3.20 122 | jar 123 | compile 124 | 125 | 126 | log4j 127 | log4j 128 | 1.2.17 129 | jar 130 | compile 131 | 132 | 133 | org.apache.poi 134 | poi 135 | 3.9 136 | jar 137 | compile 138 | 139 | 140 | org.apache.poi 141 | poi-ooxml 142 | 3.9 143 | jar 144 | compile 145 | 146 | 147 | org.apache.poi 148 | poi-ooxml-schemas 149 | 3.9 150 | jar 151 | compile 152 | 153 | 154 | commons-codec 155 | commons-codec 156 | 1.8 157 | jar 158 | compile 159 | 160 | 161 | commons-lang 162 | commons-lang 163 | 2.6 164 | jar 165 | compile 166 | 167 | 168 | commons-logging 169 | commons-logging 170 | 1.1.3 171 | jar 172 | compile 173 | 174 | 175 | org.apache.httpcomponents 176 | fluent-hc 177 | 4.2.5 178 | jar 179 | compile 180 | 181 | 182 | org.apache.httpcomponents 183 | httpclient 184 | 4.2.5 185 | jar 186 | compile 187 | 188 | 189 | org.apache.httpcomponents 190 | httpclient-cache 191 | 4.2.5 192 | jar 193 | compile 194 | 195 | 196 | org.apache.httpcomponents 197 | httpcore 198 | 4.2.5 199 | jar 200 | compile 201 | 202 | 203 | org.apache.httpcomponents 204 | httpmime 205 | 4.2.5 206 | jar 207 | compile 208 | 209 | 210 | commons-beanutils 211 | commons-beanutils 212 | 1.8.3 213 | jar 214 | compile 215 | 216 | 217 | commons-collections 218 | commons-collections 219 | 3.2.1 220 | jar 221 | compile 222 | 223 | 224 | net.sf.ezmorph 225 | ezmorph 226 | 1.0.6 227 | jar 228 | compile 229 | 230 | 231 | net.sf.json-lib 232 | json-lib 233 | 2.4 234 | jar 235 | jdk15 236 | compile 237 | 238 | 239 | com.jcraft 240 | jsch 241 | 0.1.50 242 | jar 243 | compile 244 | 245 | 246 | dom4j 247 | dom4j 248 | 1.6.1 249 | jar 250 | compile 251 | 252 | 253 | 254 | commons-io 255 | commons-io 256 | 2.4 257 | jar 258 | compile 259 | 260 | 261 | 262 | mysql 263 | mysql-connector-java 264 | 5.1.26 265 | jar 266 | compile 267 | 268 | 269 | 270 | org.dbunit 271 | dbunit 272 | 2.4.9 273 | jar 274 | compile 275 | 276 | 277 | org.slf4j 278 | slf4j-log4j12 279 | 1.7.5 280 | jar 281 | compile 282 | 283 | 284 | org.slf4j 285 | slf4j-api 286 | 1.7.5 287 | jar 288 | compile 289 | 290 | 291 | 292 | javax.mail 293 | mail 294 | 1.4.7 295 | jar 296 | compile 297 | 298 | 299 | 300 | 301 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/DispatchConf.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch; 2 | import java.io.File; 3 | import java.io.FileInputStream; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.io.OutputStream; 9 | import java.util.Properties; 10 | 11 | import org.apache.commons.io.FileUtils; 12 | 13 | 14 | /** 15 | * 配置文件 16 | * @author lianghui (lianghui@360.cn) 17 | * 18 | */ 19 | public class DispatchConf { 20 | 21 | /** 22 | * 类文件输出路径 23 | */ 24 | public static String ClsPath = getClassPath(); 25 | /** 26 | * 项目根目录 27 | */ 28 | public static String RootPath = getRootPath(); 29 | /** 30 | * suites默认存储目录 31 | */ 32 | public static String SuitsXmlPath = RootPath+"leo/dispatch/suites/";//getPropValue("SuitsXmlPath", "tba/suites/"); 33 | /** 34 | * testng默认输出目录 35 | */ 36 | public static String TestNgOutPath = RootPath+"leo/dispatch/testng-out/"; 37 | /** 38 | * html测试报告默认输出目录 39 | */ 40 | public static String HtmlReportOutPath = RootPath+"leo/dispatch/report/"+System.currentTimeMillis()+"/"; 41 | /** 42 | * html测试报告默认标题 43 | */ 44 | public static String HtmlReportTitle = "测试报告"; 45 | /** 46 | * testNGXslt插件配置文件路径 47 | */ 48 | public static String TestNGXsltFile = RootPath+"leo/dispatch/testng-results.xsl"; 49 | 50 | /** 51 | * 写配置文件,如果不存在则创建 52 | * @return boolean 已存在或创建失败时返回false 创建成功返回true 53 | */ 54 | public static boolean writeConf() { 55 | if (!new File(DispatchConf.TestNGXsltFile).exists()) { 56 | return copyFile(DispatchConf.class.getResourceAsStream("/testng-results.xsl"),new File(TestNGXsltFile)); 57 | } 58 | return false; 59 | } 60 | 61 | /** 62 | * 删除默认临时目录 63 | */ 64 | public static void delTmpPath() { 65 | try { 66 | // 清空xml文件生成目录 67 | FileUtils.deleteDirectory(new File(SuitsXmlPath)); 68 | // TestNG输出目录 69 | FileUtils.deleteDirectory(new File(TestNgOutPath)); 70 | } catch (IOException e) { 71 | // e.printStackTrace(); 72 | } 73 | 74 | } 75 | 76 | private static String getClassPath() { 77 | return DispatchConf.class.getClassLoader().getResource("").toString(); 78 | } 79 | private static String getRootPath() { 80 | String path=""; 81 | if (DispatchConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")!=-1) { 82 | path=DispatchConf.class.getClassLoader().getResource("").toString().substring(6, DispatchConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")); 83 | path=path+"/"; 84 | }else { 85 | // path = GlobalSettings.class.getClassLoader().getResource("").toString(); 86 | String temp=System.getProperty("user.dir"); 87 | temp=temp.replace("\\","/"); 88 | path=temp+"/"; 89 | } 90 | return path; 91 | } 92 | 93 | @SuppressWarnings("unused") 94 | private static String getPropValue(String key, String defaultValue) { 95 | return getProperties().getProperty(key, defaultValue); 96 | } 97 | 98 | private static Properties getProperties() { 99 | Properties prop = new Properties(); 100 | try { 101 | FileInputStream file = new FileInputStream("conf.properties"); 102 | prop.load(new InputStreamReader(file,"UTF-8")); 103 | file.close(); 104 | } catch (Exception e) { 105 | // e.printStackTrace(); 106 | } 107 | return prop; 108 | } 109 | 110 | private static boolean copyFile(InputStream from, File to) { 111 | try { 112 | if (! to.getParentFile().exists()) { 113 | to.getParentFile().mkdirs(); 114 | } 115 | OutputStream os = new FileOutputStream(to); 116 | byte[] buffer = new byte[65536]; 117 | int count = from.read(buffer); 118 | while (count > 0) { 119 | os.write(buffer, 0, count); 120 | count = from.read(buffer); 121 | } 122 | os.close(); 123 | return true; 124 | } catch (IOException e) { 125 | // e.printStackTrace(); 126 | return false; 127 | } 128 | 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/ExecTask.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch; 2 | 3 | import com.github.qihootest.leo.dispatch.report.TestReport; 4 | import com.github.qihootest.leo.dispatch.run.TestRunInfo; 5 | import com.github.qihootest.leo.dispatch.run.TestngRunSingle; 6 | import com.github.qihootest.leo.toolkit.util.CommUtils; 7 | import com.github.qihootest.leo.toolkit.util.LogUtil; 8 | 9 | 10 | /** 11 | * 任务执行入口 12 | * @author lianghui (lianghui@360.cn) 13 | * 14 | */ 15 | public class ExecTask { 16 | 17 | private LogUtil log=LogUtil.getLogger(ExecTask.class);//日志记录 18 | private TestngRunSingle task; 19 | private TestRunInfo runInfo; 20 | private TestReport report; 21 | 22 | /** 23 | * 构造函数 24 | */ 25 | public ExecTask() { 26 | task = TestngRunSingle.getInstance(); 27 | report = new TestReport(); 28 | } 29 | /** 30 | * 任务执行 31 | * @return TestReport 32 | */ 33 | public TestReport Exec() { 34 | //传入参数校验 35 | if (runInfo.getCaseList() == null || runInfo.getCaseList().size()<1) { 36 | setResNoAndMsg(-100,"待执行的用例不存在"); 37 | log.error(runInfo.getTaskName()+" 待执行的用例不存在"); 38 | return report; 39 | } 40 | Long startTimeMS=System.currentTimeMillis(); 41 | Long startTime=startTimeMS/1000; 42 | int sumTime=0;//记录等待时长,单位秒 43 | while (true) { 44 | //获取等待的时间 45 | sumTime=(int) (System.currentTimeMillis()/1000-startTime); 46 | //判断当前是否有任务运行 47 | //当前无任务执行,执行当前任务 48 | if (!task.getFlag()) { 49 | //运行任务 设置任务信息 50 | task.setRunInfo(this.runInfo); 51 | report= task.execTask(); 52 | long execTimes=System.currentTimeMillis()-startTimeMS; 53 | log.info(this.runInfo.getTaskName()+" 执行时间:"+execTimes+"毫秒"); 54 | report.setSumTime(execTimes); 55 | return report;//执行完毕后返回测试报告信息 56 | } 57 | 58 | //当前有任务在运行 判断等待时间 59 | if (sumTime>600) {//设置等待超时时间600秒 60 | log.info(this.runInfo.getTaskName()+" 已等待"+sumTime+"秒,超时退出"); 61 | setResNoAndMsg(-203,"任务等待超时,已等待"+sumTime+"秒"); 62 | return report; 63 | } 64 | // 当前有任务在运行 等待10秒后再试试 65 | log.info(this.runInfo.getTaskName()+" 在等待执行,当前有任务在执行中。。。等待10秒后再尝试执行"); 66 | CommUtils.sleep(10000); 67 | }//死循环 68 | } 69 | 70 | /** 71 | * 设置任务运行配置信息 72 | * @param runInfo 73 | */ 74 | public void setRunInfo(TestRunInfo runInfo) { 75 | this.runInfo = runInfo; 76 | } 77 | 78 | private void setResNoAndMsg(int resNo,String resMsg) { 79 | this.report.setResNo(resNo); 80 | this.report.setResMsg(resMsg); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/log/TestngLog.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.log; 2 | 3 | import org.testng.Reporter; 4 | import com.github.qihootest.leo.toolkit.util.LogUtil; 5 | 6 | 7 | 8 | /** 9 | * 封装TestNG log记录 10 | * @author lianghui (lianghui@360.cn) 11 | * 12 | */ 13 | public class TestngLog { 14 | private static LogUtil log=LogUtil.getLogger(TestngLog.class);//日志记录 15 | private static boolean OutputTestNGLog=true;//是否输出到TestNG Log日志 16 | /** 17 | * 说明:记录用例开始,写入TestNG日志 18 | * 19 | * @param testCaseName 用例名称 20 | */ 21 | public static void CaseStart(String testCaseName) { 22 | TestNGLog("用例-------【" + testCaseName 23 | + "】----------开始执行---------------"); 24 | } 25 | 26 | /** 27 | * 说明:记录用例结束,写入TestNG日志 28 | * 29 | * @param testCaseName 用例名称 30 | */ 31 | public static void CaseEnd(String testCaseName) { 32 | TestNGLog("用例-------【" + testCaseName 33 | + "】----------执行完毕---------------"); 34 | TestNGLog( 35 | "///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////"); 36 | } 37 | 38 | /** 39 | * 说明:把指定信息写入TestNG日志 40 | * @param str 字符串 41 | */ 42 | public static void Log(String str) { 43 | TestNGLog(str); 44 | } 45 | 46 | /** 47 | * 设置是否输出TestNG执行记录到TestNG日志中 48 | * @param outputTestNGLog 默认true 49 | */ 50 | public static void setOutputTestNGLog(boolean outputTestNGLog) { 51 | OutputTestNGLog = outputTestNGLog; 52 | } 53 | 54 | private static void TestNGLog(String info) { 55 | log.info(info); 56 | if (OutputTestNGLog) { 57 | Reporter.log(info,false); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/report/ExportReportHtml.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.report; 2 | 3 | import java.io.BufferedOutputStream; 4 | import java.io.FileOutputStream; 5 | 6 | import javax.xml.transform.Result; 7 | import javax.xml.transform.Source; 8 | import javax.xml.transform.Transformer; 9 | import javax.xml.transform.TransformerFactory; 10 | import javax.xml.transform.stream.StreamResult; 11 | 12 | import com.github.qihootest.leo.dispatch.DispatchConf; 13 | import com.github.qihootest.leo.toolkit.util.FileUtil; 14 | import com.github.qihootest.leo.toolkit.util.LogUtil; 15 | 16 | 17 | /** 18 | * TestNG的原生报告转换为美化后的Html格式测试报告 19 | * @author lianghui (lianghui@360.cn) 20 | * 21 | */ 22 | public class ExportReportHtml { 23 | 24 | private static LogUtil log=LogUtil.getLogger(ExportReportHtml.class);//日志记录 25 | 26 | /** 27 | * 根据TestNG结果输出的xml文件,优化生成html格式测试报告 28 | * @param tngOutFilePath TestNG的结果xml文件路径 29 | * @param htmlReportPath html报告的目录 30 | * @param htmlReportTitle 测试报告标题 31 | * @return boolean 创建成功返回true 32 | */ 33 | public static boolean createHtmlReport(String tngOutFilePath,String htmlReportPath,String htmlReportTitle) { 34 | if (!FileUtil.isExist(tngOutFilePath) ) { 35 | log.error("生成Html报告出错-testng输出的xml文件不存在:"+tngOutFilePath); 36 | return false; 37 | } 38 | if (!FileUtil.createDictory(htmlReportPath)){ 39 | log.error("生成Html报告出错-输出目录创建失败:"+htmlReportPath); 40 | return false; 41 | } 42 | try { 43 | Source xml = new javax.xml.transform.stream.StreamSource(tngOutFilePath); 44 | Source xsl = new javax.xml.transform.stream.StreamSource(DispatchConf.TestNGXsltFile); 45 | Result out = new StreamResult(new BufferedOutputStream(new FileOutputStream(htmlReportPath+"/index.html"))); 46 | // 创建转换器工厂 47 | TransformerFactory tfactory = TransformerFactory.newInstance(); 48 | // 创建 XSL 转换器 49 | Transformer transformer = tfactory.newTransformer(xsl); 50 | //参数设置 51 | transformer.setParameter("testNgXslt.outputDir",htmlReportPath); 52 | //transformer.setParameter("testNgXslt.showRuntimeTotals", true); 53 | transformer.setParameter("testNgXslt.reportTitle", htmlReportTitle); 54 | transformer.transform(xml, out); 55 | log.info("生成Html测试报告成功:"+htmlReportPath+"/index.html"); 56 | return true; 57 | } catch (Exception e) { 58 | log.error("生成Html报告出错-xml转换异常:"+e.getMessage()); 59 | return false; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/report/TestReport.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.report; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * 测试任务执行完毕后输出的测试报告摘要信息
7 | * 8 | * @author lianghui (lianghui@360.cn) 9 | */ 10 | public class TestReport { 11 | 12 | /** 13 | * 任务ID 14 | */ 15 | private String taskId; 16 | /** 17 | * 任务名称 18 | */ 19 | private String taskName; 20 | /** 21 | * html报告存储位置 22 | */ 23 | private String htmlReport; 24 | /** 25 | * 测试任务执行时长,单位:毫秒 26 | */ 27 | private Long sumTime; 28 | /** 29 | * 测试套/集 结果信息 30 | */ 31 | private TngCount tngSuiteCount; 32 | /** 33 | * 测试套中所有测试集结果信息 34 | */ 35 | private ArrayList tngTestCountList;// 36 | /** 37 | * 任务运行结果返回码 38 | */ 39 | private int resNo; 40 | /** 41 | * 任务运行结果返回信息 42 | */ 43 | private String resMsg; 44 | 45 | 46 | public String getHtmlReport() { 47 | return htmlReport; 48 | } 49 | public void setHtmlReport(String htmlReport) { 50 | this.htmlReport = htmlReport; 51 | } 52 | public TngCount getTngSuiteCount() { 53 | return tngSuiteCount; 54 | } 55 | public void setTngSuiteCount(TngCount tngSuiteCount) { 56 | this.tngSuiteCount = tngSuiteCount; 57 | } 58 | public ArrayList getTngTestCountList() { 59 | return tngTestCountList; 60 | } 61 | public void setTngTestCountList(ArrayList tngTestCountList) { 62 | this.tngTestCountList = tngTestCountList; 63 | } 64 | public String getTaskId() { 65 | return taskId; 66 | } 67 | public void setTaskId(String taskId) { 68 | this.taskId = taskId; 69 | } 70 | public String getTaskName() { 71 | return taskName; 72 | } 73 | public void setTaskName(String taskName) { 74 | this.taskName = taskName; 75 | } 76 | public Long getSumTime() { 77 | return sumTime; 78 | } 79 | public void setSumTime(Long sumTime) { 80 | this.sumTime = sumTime; 81 | } 82 | public int getResNo() { 83 | return resNo; 84 | } 85 | public void setResNo(int resNo) { 86 | this.resNo = resNo; 87 | } 88 | public String getResMsg() { 89 | return resMsg; 90 | } 91 | public void setResMsg(String resMsg) { 92 | this.resMsg = resMsg; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/report/TngCount.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.report; 2 | 3 | /** 4 | * 一个testng的测试集或测试套的执行结果信息 5 | * @author lianghui (lianghui@360.cn) 6 | */ 7 | public class TngCount { 8 | /** 9 | * 测试套/集名称 10 | */ 11 | private String name; 12 | /** 13 | * 所属的测试套的名称,为空标识无所属测试套 14 | */ 15 | private String suiteName; 16 | /** 17 | * 失败数 18 | */ 19 | private int failed; 20 | /** 21 | * 通过数 22 | */ 23 | private int passed; 24 | /** 25 | * 跳过数 26 | */ 27 | private int skipped; 28 | public String getName() { 29 | return name; 30 | } 31 | public void setName(String name) { 32 | this.name = name; 33 | } 34 | public String getSuiteName() { 35 | return suiteName; 36 | } 37 | public void setSuiteName(String suiteName) { 38 | this.suiteName = suiteName; 39 | } 40 | public int getFailed() { 41 | return failed; 42 | } 43 | public void setFailed(int failed) { 44 | this.failed = failed; 45 | } 46 | public int getPassed() { 47 | return passed; 48 | } 49 | public void setPassed(int passed) { 50 | this.passed = passed; 51 | } 52 | public int getSkipped() { 53 | return skipped; 54 | } 55 | public void setSkipped(int skipped) { 56 | this.skipped = skipped; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/run/TestRunInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.run; 2 | 3 | import java.util.List; 4 | 5 | import com.github.qihootest.leo.dispatch.testcase.ICase; 6 | 7 | 8 | /** 9 | * TestNG运行信息 10 | * @author lianghui (lianghui@360.cn) 11 | */ 12 | public class TestRunInfo { 13 | private String taskName;//任务名称 14 | private String testng_OutPut;//TestNG输出目录 15 | private String htmlReportOutPath;//Html报告输出路径 16 | private String htmlReportTitle;//Html报告标题 17 | private List caseList;//用例信息 18 | public String getTaskName() { 19 | return taskName; 20 | } 21 | public void setTaskName(String taskName) { 22 | this.taskName = taskName; 23 | } 24 | public String getTestng_OutPut() { 25 | return testng_OutPut; 26 | } 27 | public void setTestng_OutPut(String testng_OutPut) { 28 | this.testng_OutPut = testng_OutPut; 29 | } 30 | public String getHtmlReportOutPath() { 31 | return htmlReportOutPath; 32 | } 33 | public void setHtmlReportOutPath(String htmlReportOutPath) { 34 | this.htmlReportOutPath = htmlReportOutPath; 35 | } 36 | public List getCaseList() { 37 | return caseList; 38 | } 39 | public void setCaseList(List caseList) { 40 | this.caseList = caseList; 41 | } 42 | public String getHtmlReportTitle() { 43 | return htmlReportTitle; 44 | } 45 | public void setHtmlReportTitle(String htmlReportTitle) { 46 | this.htmlReportTitle = htmlReportTitle; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/run/TestngRun.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.run; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.testng.ITestContext; 7 | import org.testng.TestListenerAdapter; 8 | import org.testng.TestNG; 9 | 10 | import com.github.qihootest.leo.dispatch.DispatchConf; 11 | import com.github.qihootest.leo.dispatch.report.ExportReportHtml; 12 | import com.github.qihootest.leo.dispatch.report.TestReport; 13 | import com.github.qihootest.leo.dispatch.report.TngCount; 14 | import com.github.qihootest.leo.dispatch.testcase.ICase; 15 | import com.github.qihootest.leo.toolkit.util.CommUtils; 16 | import com.github.qihootest.leo.toolkit.util.FileUtil; 17 | import com.github.qihootest.leo.toolkit.util.LogUtil; 18 | 19 | /** 20 | * 执行testng, 21 | * @author lianghui (lianghui@360.cn) 2012-10-29 22 | * 23 | */ 24 | public class TestngRun { 25 | private LogUtil log=LogUtil.getLogger(TestngRun.class);//日志记录 26 | private TestNG tng;//运行TestNG 27 | private TestListenerAdapter listener;//运行的监听器 28 | 29 | private TestRunInfo runInfo; 30 | private List xmlFileList; 31 | 32 | private TestReport testReport; 33 | 34 | /* 35 | * 构造函数 初始化 36 | */ 37 | public TestngRun() { 38 | tng=new TestNG(); 39 | listener=new TestListenerAdapter();//定义监听器类型 40 | tng.addListener(listener); 41 | xmlFileList=new ArrayList<>();//记录测试使用的xml文件路径列表 42 | testReport=new TestReport();//记录测试报告测试报告信息 43 | runInfo=new TestRunInfo(); 44 | } 45 | 46 | /** 47 | * 设置运行配置信息 48 | * @param runInfo 49 | */ 50 | public void setRunInfo(TestRunInfo runInfo) { 51 | this.runInfo=runInfo; 52 | log.info(this.runInfo.getTaskName()+"配置任务信息成功"); 53 | for (ICase icase : this.runInfo.getCaseList()) { 54 | addXmlFileList(icase.getCaseList()); 55 | } 56 | } 57 | 58 | /** 59 | * 执行用例 60 | * @return boolean 执行成功返回true 61 | */ 62 | public boolean run() { 63 | if (getXmlFileList().size()<1) { 64 | this.testReport.setResNo(-6000); 65 | this.testReport.setResMsg("Xml文件列表为空"); 66 | log.error(getTaskName()+" :Xml文件列表为空"); 67 | return false; 68 | } 69 | //运行相关参数配置 70 | //检查xlst文件,不存在则创建 71 | DispatchConf.writeConf(); 72 | tng.setOutputDirectory(getTestNgOut()); 73 | 74 | try { 75 | tng.setTestSuites(getXmlFileList()); 76 | tng.run(); 77 | } catch (Exception e) { 78 | // e.printStackTrace(); 79 | this.testReport.setResNo(-7000); 80 | this.testReport.setResMsg("执行用例异常: "+e.getMessage()); 81 | log.error(getTaskName()+" :执行用例异常--"+e.getMessage()); 82 | return false; 83 | } 84 | //记录测试报告摘要 85 | createTestReport(); 86 | //输出html测试报告 87 | if (!createHtmlReport()) { 88 | this.testReport.setResNo(1); 89 | this.testReport.setResMsg("任务执行成功,转换Html格式报告出错"); 90 | log.info(getTaskName()+" :任务执行成功,转换Html格式报告出错"); 91 | }else{ 92 | this.testReport.setResNo(0); 93 | this.testReport.setResMsg("任务执行成功"); 94 | log.info(getTaskName()+" :任务执行成功"); 95 | } 96 | return true; 97 | } 98 | 99 | /** 100 | * 获取测试报告 101 | * @return TestReport 102 | */ 103 | public TestReport getTestReport() { 104 | return this.testReport; 105 | } 106 | 107 | //私有方法 108 | private String getTestNgOut(){ 109 | String out= this.runInfo.getTestng_OutPut(); 110 | if (out == null || out.length()<1) { 111 | log.info("设置TestNG输出目录失败:"+this.runInfo.getTestng_OutPut()); 112 | log.info("使用默认路径:"+DispatchConf.TestNgOutPath); 113 | return DispatchConf.TestNgOutPath;//默认的TestNG输出目录 114 | } 115 | if (!out.endsWith("/")) { 116 | out=out+"/"; 117 | } 118 | return out; 119 | } 120 | 121 | private String getTaskName() { 122 | if (this.runInfo.getTaskName() == null || this.runInfo.getTaskName().length()<1) { 123 | String taskName = "未命名测试任务"+CommUtils.getRandomStr(5); 124 | log.info("设置任务名失败:"+this.runInfo.getTaskName()); 125 | log.info("使用默认任务名:"+taskName); 126 | return taskName;//默认的TestNG输出目录 127 | } 128 | return this.runInfo.getTaskName(); 129 | } 130 | 131 | private String getHtmlReportOut(){ 132 | if (this.runInfo.getHtmlReportOutPath() == null || this.runInfo.getHtmlReportOutPath().length()<1) { 133 | log.info("设置Html输出目录失败:"+this.runInfo.getHtmlReportOutPath()); 134 | log.info("使用默认Html输出目录:"+DispatchConf.HtmlReportOutPath); 135 | return DispatchConf.HtmlReportOutPath;//默认的html报告输出目录 136 | } 137 | return this.runInfo.getHtmlReportOutPath(); 138 | } 139 | 140 | private String getHtmlReportTitle(){ 141 | if (null == this.runInfo.getHtmlReportTitle() || this.runInfo.getHtmlReportTitle().length()<1) { 142 | log.info("设置Html报告标题失败:"+this.runInfo.getHtmlReportTitle()); 143 | log.info("使用默认Html报告标题:"+DispatchConf.HtmlReportTitle); 144 | return DispatchConf.HtmlReportTitle; 145 | } 146 | return this.runInfo.getHtmlReportTitle(); 147 | } 148 | 149 | private List getXmlFileList() { 150 | return xmlFileList; 151 | } 152 | 153 | private void addXmlFileList(List xmlFileList) { 154 | if (null==xmlFileList) { 155 | log.error("添加的Xml文件列表为null,添加失败"); 156 | return; 157 | } 158 | for (String xmlFile : xmlFileList) { 159 | addXmlFile(xmlFile); 160 | } 161 | } 162 | 163 | private boolean addXmlFile(String xmlPathName){ 164 | if (null==xmlPathName){ 165 | log.error("添加的xml文件为null,添加失败"); 166 | return false; 167 | } 168 | if (!FileUtil.getExtensionName(xmlPathName).equals("xml")) xmlPathName=xmlPathName+".xml"; 169 | 170 | if (FileUtil.isExist(xmlPathName)) { 171 | log.info("执行队列添加xml文件成功:"+xmlPathName); 172 | this.xmlFileList.add(xmlPathName); 173 | return true; 174 | }else{ 175 | log.error("添加的xml文件不存在:"+xmlPathName); 176 | return false; 177 | } 178 | } 179 | 180 | 181 | private boolean createHtmlReport() { 182 | if (ExportReportHtml.createHtmlReport(getTestNgOut()+"testng-results.xml", 183 | getHtmlReportOut(),getHtmlReportTitle())) { 184 | 185 | this.testReport .setHtmlReport(getHtmlReportOut()); 186 | return true; 187 | } 188 | return false; 189 | } 190 | 191 | /** 192 | * 从监听器中获取需要的报告信息 193 | * @param listener 194 | */ 195 | private void createTestReport() { 196 | log.info("从TestNG监听器中获取任务执行的用例信息"); 197 | ArrayList testCountList=new ArrayList();; 198 | TngCount tngCount=new TngCount(); 199 | tngCount.setName(getTaskName()); 200 | tngCount.setFailed(this.listener.getFailedTests().size()); 201 | tngCount.setPassed(this.listener.getPassedTests().size()); 202 | tngCount.setSkipped(this.listener.getSkippedTests().size()); 203 | this.testReport.setTngSuiteCount(tngCount); 204 | List testContextList=this.listener.getTestContexts(); 205 | for (int i = 0; i < testContextList.size(); i++) { 206 | tngCount=new TngCount(); 207 | tngCount.setName(testContextList.get(i).getName()); 208 | tngCount.setSuiteName(testContextList.get(i).getSuite().getName()); 209 | tngCount.setFailed(testContextList.get(i).getFailedTests().size()); 210 | tngCount.setPassed(testContextList.get(i).getPassedTests().size()); 211 | tngCount.setSkipped(testContextList.get(i).getSkippedTests().size()); 212 | 213 | testCountList.add(tngCount); 214 | } 215 | this.testReport .setTaskName(getTaskName()); 216 | this.testReport .setTngTestCountList(testCountList); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/run/TestngRunSingle.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.run; 2 | 3 | import com.github.qihootest.leo.dispatch.report.TestReport; 4 | import com.github.qihootest.leo.toolkit.util.LogUtil; 5 | 6 | /** 7 | * 说明:封装用例执行 单例模式 8 | * 9 | * @author lianghui (lianghui@360.cn) 2012-12-04 10 | * 11 | */ 12 | public class TestngRunSingle { 13 | private LogUtil log=LogUtil.getLogger(TestngRunSingle.class);//日志记录 14 | private static TestngRunSingle single; 15 | private static boolean Flag;//是否运行任务标识,为true时有任务在运行,false时无任务运行 16 | private TestRunInfo runInfo ;//任务名称 17 | private TestReport testReport;//执行完毕后,返回的测试报告信息 18 | 19 | //设置为单例模式 20 | private TestngRunSingle() 21 | { 22 | setFlag(false); 23 | init();//第一次创建时,初始化属性 24 | } 25 | 26 | /** 27 | * 运行前初始化相关信息 28 | */ 29 | private void init(){ 30 | log.info("TestNG执行实例创建"); 31 | runInfo=new TestRunInfo(); 32 | testReport=new TestReport(); 33 | } 34 | 35 | /** 36 | * 获取类的实例 37 | * @return TestngRunSingle 38 | */ 39 | public synchronized static TestngRunSingle getInstance() { 40 | if (single == null) { 41 | single = new TestngRunSingle(); 42 | } 43 | return single; 44 | } 45 | 46 | /** 47 | * 设置任务信息 48 | * @param runInfo 任务配置信息 49 | */ 50 | public void setRunInfo(TestRunInfo runInfo) { 51 | // 设置任务信息 52 | this.runInfo=runInfo; 53 | } 54 | 55 | /** 56 | * 获取当前任务运行标识 57 | * @return boolean 58 | */ 59 | public boolean getFlag() { 60 | return Flag; 61 | } 62 | 63 | /** 64 | * 说明:执行任务返回测试报告信息 65 | * @return TestReport 66 | */ 67 | public TestReport execTask() { 68 | setFlag(true); 69 | doTask(); 70 | setFlag(false); 71 | return this.testReport; 72 | } 73 | 74 | //内部方法 75 | private static void setFlag(boolean flag) { 76 | Flag = flag; 77 | } 78 | 79 | /** 80 | * 说明:执行测试过程 81 | * 82 | * @return boolean 83 | */ 84 | private boolean doTask() { 85 | log.info(this.runInfo.getTaskName()+" 开始执行"); 86 | TestngRun testngRun = new TestngRun(); 87 | testngRun.setRunInfo(runInfo); 88 | boolean result = testngRun.run(); 89 | testReport = testngRun.getTestReport(); 90 | testngRun = null; 91 | return result; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/CreateXmlFile.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import org.testng.xml.XmlClass; 8 | import org.testng.xml.XmlSuite; 9 | import org.testng.xml.XmlTest; 10 | 11 | import com.github.qihootest.leo.dispatch.DispatchConf; 12 | import com.github.qihootest.leo.toolkit.util.CommUtils; 13 | import com.github.qihootest.leo.toolkit.util.FileUtil; 14 | import com.github.qihootest.leo.toolkit.util.LogUtil; 15 | 16 | 17 | /** 18 | * 根据java文件输出Xml文件 19 | * @author lianghui (lianghui@360.cn) 20 | * 21 | */ 22 | public class CreateXmlFile { 23 | private LogUtil log=LogUtil.getLogger(CreateXmlFile.class);//日志记录 24 | 25 | private XmlSuite suite; 26 | private String xmlFileFolder; 27 | private String suiteName; 28 | 29 | /** 30 | * 构造函数 31 | */ 32 | public CreateXmlFile(){ 33 | suite=new XmlSuite(); 34 | setSuiteName("测试套件"+CommUtils.getRandomStr(5)); 35 | setXmlFileFolder(DispatchConf.SuitsXmlPath); 36 | } 37 | 38 | /** 39 | * 构造函数 40 | * @param threadCont 线程数 41 | * @param setParallel 设置多线程方式 42 | */ 43 | public CreateXmlFile(int threadCont,String setParallel){ 44 | suite=new XmlSuite(); 45 | setSuiteName("测试套件"+CommUtils.getRandomStr(5),threadCont,setParallel); 46 | setXmlFileFolder(DispatchConf.SuitsXmlPath); 47 | } 48 | 49 | public String getXmlFilePath(){ 50 | if (suite.getTests().size()<1) { 51 | log.error("未添加任何测试集,未生成xml文件"); 52 | return null; 53 | }else{ 54 | return createXmlFile(); 55 | } 56 | } 57 | 58 | /** 59 | * 添加java用例 60 | * @param cls 61 | */ 62 | public void addJavaCase(Class cls){ 63 | if (null==cls) return ; 64 | String caseName=cls.getSimpleName(); 65 | addJavaCase(caseName, cls); 66 | } 67 | /** 68 | * 添加java用例 69 | * @param caseName 用例名称 70 | * @param cls 类 71 | */ 72 | public void addJavaCase(String caseName,Class cls) { 73 | if (null==cls ) { 74 | log.error("添加的java类为null,添加失败"); 75 | return; 76 | } 77 | if (null==caseName || caseName.length()<1) { 78 | log.info("指定的测试集为空:"+caseName); 79 | String nameTmp="未命名测试集"+CommUtils.getRandomStr(5); 80 | log.info("使用默认测试集名称:"+nameTmp); 81 | addClassToXmlTest(cls.getName(), nameTmp); 82 | return; 83 | } 84 | addClassToXmlTest(cls.getName(), caseName); 85 | } 86 | 87 | /** 88 | * 设置测试套名称 89 | * @param suiteName 90 | */ 91 | public void setSuiteName(String suiteName) { 92 | if (null!=suiteName && suiteName.length()>0) { 93 | this.suiteName = suiteName; 94 | }else{ 95 | log.info("设置的测试套件名称为空"); 96 | log.info("使用默认测试套名称:"+this.suiteName); 97 | } 98 | suite.setName(this.suiteName); 99 | suite.setVerbose(1); 100 | } 101 | 102 | /** 103 | * 设置测试套名称 104 | * @param suiteName 105 | * @param threadCont 执行的线程数 106 | * @param setParallel 设置多线程的方式 107 | */ 108 | public void setSuiteName(String suiteName,int threadCont,String setParallel) { 109 | this.setSuiteName(suiteName); 110 | if(threadCont>0){ 111 | suite.setParallel(setParallel); //设置多线程的方式 methods ,tests,classes 112 | suite.setThreadCount(threadCont); //设置多线程的个数 113 | } 114 | } 115 | 116 | public void setXmlFileFolder(String xmlFileFolder) { 117 | this.xmlFileFolder = xmlFileFolder; 118 | } 119 | private void addClassToXmlTest(String pkgAndClsName,String testName) { 120 | XmlTest xmltest=new XmlTest(); 121 | XmlClass classe=new XmlClass(pkgAndClsName); 122 | xmltest.setName(testName); 123 | xmltest.setClasses(Arrays.asList(classe)); 124 | addTest(xmltest); 125 | } 126 | 127 | private void addTest(XmlTest test){ 128 | if (null==test){ 129 | log.error("测试集为null,添加失败"); 130 | return; 131 | } 132 | suite.addTest(test); 133 | } 134 | 135 | /** 136 | * 生成testNG调用的xml文件 137 | * @return 138 | */ 139 | private String createXmlFile(){ 140 | List arr=new ArrayList(); 141 | String xml=this.suite.toXml(); 142 | String xx[]=xml.split("\n"); 143 | 144 | for (int i = 0; i < xx.length; i++) { 145 | if (xx[i].indexOf("verbose")!=-1) { 146 | String temp=xx[i].trim(); 147 | xx[i]=temp.substring(0, temp.indexOf("verbose")+12)+" preserve-order=\"true\" " 148 | +temp.substring(temp.indexOf("verbose")+12, temp.length()); 149 | } 150 | arr.add(xx[i]); 151 | } 152 | String xmlName = getXmlFileFolder()+getSuiteName()+".xml"; 153 | if (FileUtil.writeString(arr, xmlName, "UTF-8")){ 154 | log.info("生成Xml文件成功:"+xmlName); 155 | return xmlName; 156 | }else { 157 | log.error("生成Xml文件失败:"+xmlName); 158 | return null; 159 | } 160 | } 161 | 162 | private String getSuiteName(){ 163 | return this.suiteName; 164 | } 165 | 166 | private String getXmlFileFolder() { 167 | return xmlFileFolder; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/DataFileCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | 4 | /** 5 | * 数据文件类型的测试用例 6 | * 7 | * @author lianghui (lianghui@360.cn) 8 | * 9 | */ 10 | public class DataFileCase extends SuperCase{ 11 | /** 12 | * 默认构造函数 13 | */ 14 | public DataFileCase() { 15 | super(); 16 | } 17 | //逻辑处理 输出xml配置文件 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/ICase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 测试集(一个或多个测试集、测试套) 7 | * @author lianghui (lianghui@360.cn) 8 | * 9 | */ 10 | public interface ICase { 11 | 12 | /** 13 | * 获取用例的xml文件路径信息列表 14 | * @return List 15 | */ 16 | public List getCaseList(); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/JavaFileCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | import com.github.qihootest.leo.toolkit.util.CommUtils; 7 | import com.github.qihootest.leo.toolkit.util.LogUtil; 8 | 9 | /** 10 | * .java文件类型的测试用例 11 | * @author lianghui (lianghui@360.cn) 12 | * 13 | */ 14 | public class JavaFileCase extends SuperCase{ 15 | private LogUtil log=LogUtil.getLogger(JavaFileCase.class);//日志记录 16 | private CreateXmlFile createXmlFile; 17 | /** 18 | * 构造函数 19 | */ 20 | public JavaFileCase(){ 21 | super(); 22 | createXmlFile = new CreateXmlFile(); 23 | } 24 | 25 | /** 26 | * 构造函数 27 | * @param threadCont 线程数 28 | */ 29 | public JavaFileCase(int threadCont,String setParallel){ 30 | super(); 31 | createXmlFile = new CreateXmlFile(threadCont,setParallel); 32 | } 33 | 34 | /** 35 | * 获取用例列表,返回的是xml文件路径信息 36 | * @return List 37 | */ 38 | public List getCaseList(){ 39 | String xmlFilePath = createXmlFile.getXmlFilePath(); 40 | if (null!=xmlFilePath){ 41 | return Arrays.asList(xmlFilePath); 42 | }else{ 43 | return null; 44 | } 45 | 46 | } 47 | /** 48 | * 添加用例 49 | * @param cls 50 | */ 51 | public void addCase(Class cls){ 52 | if (null==cls) { 53 | log.error("添加的java用例类为null"); 54 | return ; 55 | } 56 | String caseName=cls.getSimpleName(); 57 | addCase(caseName, cls); 58 | } 59 | /** 60 | * 添加用例 61 | * @param caseName 62 | * @param cls 63 | */ 64 | public void addCase(String caseName,Class cls) { 65 | if (null==cls ) { 66 | log.error("添加的java用例类为null"); 67 | return; 68 | } 69 | if (null==caseName || caseName.length()<1) { 70 | log.info("设置的用例名为空"); 71 | caseName="未命名测试集"+CommUtils.getRandomStr(5); 72 | log.info("使用默认名称:"+caseName); 73 | } 74 | createXmlFile.addJavaCase(caseName, cls); 75 | } 76 | 77 | /** 78 | * 设置测试套名称 未设置使用默认名称 "未命名测试用例"+5随机字符 79 | * @param suiteName 80 | */ 81 | public void setSuiteName(String suiteName) { 82 | createXmlFile.setSuiteName(suiteName); 83 | } 84 | 85 | /** 86 | * 设置生成的xml文件存放文件夹 未设置使用默认 qtaf/dispatch/suites/ 87 | * @param suiteName 88 | */ 89 | public void setXmlFileFolder(String xmlFileFolder) { 90 | createXmlFile.setXmlFileFolder(xmlFileFolder); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/SuperCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 测试用例基类 8 | * @author lianghui (lianghui@360.cn) 9 | * 10 | */ 11 | public abstract class SuperCase implements ICase { 12 | 13 | protected List xmlPathNameList; 14 | /** 15 | * 构造函数 16 | */ 17 | public SuperCase(){ 18 | xmlPathNameList=new ArrayList<>(); 19 | } 20 | /** 21 | * 返回用例列表 xml文件信息 22 | * @return List 23 | */ 24 | public List getCaseList() { 25 | return this.xmlPathNameList; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/dispatch/testcase/XmlFileCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch.testcase; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.github.qihootest.leo.toolkit.util.LogUtil; 7 | 8 | /** 9 | * XML文件类型的测试用例 10 | * @author lianghui (lianghui@360.cn) 11 | * 12 | */ 13 | public class XmlFileCase extends SuperCase{ 14 | 15 | private LogUtil log=LogUtil.getLogger(XmlFileCase.class);//日志记录 16 | /** 17 | *默认构造函数 18 | */ 19 | public XmlFileCase() { 20 | super(); 21 | xmlPathNameList=new ArrayList<>(); 22 | } 23 | /** 24 | * 构造函数 根据xml文件列表信息创建 25 | * @param xmlPathNameList 26 | */ 27 | public XmlFileCase(List xmlPathNameList) { 28 | super(); 29 | xmlPathNameList=new ArrayList<>(); 30 | this.xmlPathNameList=xmlPathNameList; 31 | } 32 | /** 33 | * 构造函数 根据单个xml文件信息创建 34 | * @param xmlPathName 35 | */ 36 | public XmlFileCase(String xmlPathName) { 37 | super(); 38 | xmlPathNameList=new ArrayList<>(); 39 | if (null==xmlPathName)return; 40 | this.xmlPathNameList.add(xmlPathName); 41 | } 42 | 43 | /** 44 | * 添加xml文件列表信息 45 | * @param xmlPathNameList 46 | */ 47 | public void addXmlCase(List xmlPathNameList) { 48 | this.xmlPathNameList.addAll(xmlPathNameList); 49 | } 50 | /** 51 | * 添加单个xml文件信息 52 | * @param xmlPathName 53 | */ 54 | public void addXmlCase(String xmlPathName) { 55 | if (null==xmlPathName){ 56 | log.error("添加的Xml文件为null,添加失败"); 57 | return; 58 | } 59 | this.xmlPathNameList.add(xmlPathName); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/IftConf.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.OutputStream; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | import java.util.Properties; 13 | 14 | import org.apache.commons.io.FileUtils; 15 | 16 | /** 17 | * 接口全局配置文件 18 | * @author @bwgang (bwgang@163.com)
19 | * 20 | */ 21 | public class IftConf{ 22 | /** 23 | * 自定义依赖参数 24 | */ 25 | public static Map DependPara = new HashMap(); 26 | /** 27 | * 项目根目录 28 | */ 29 | public static final String RootPath = getRootPath(); 30 | /** 31 | * 接口ift配置等文件默认保存目录 32 | */ 33 | public static String IftPath = RootPath+"leo/ift/"; 34 | /** 35 | * 默认编译输出目录 36 | */ 37 | public static String DistPath = getDistPath(); 38 | /** 39 | * 默认lib目录 40 | */ 41 | public static String LibPath = getLibPath(); 42 | /** 43 | * jar文件目录 maven 44 | */ 45 | public static String JarFile = ""; 46 | /** 47 | * 默认生成的java文件存放目录 48 | */ 49 | public static String JavaPath = IftPath+"javaCase/"; 50 | 51 | /** 52 | * 默认生成java文件时的包名 53 | */ 54 | public static String PackageName = "com.github.qihootest.leo.ift.testcase"; 55 | 56 | /** 57 | * 默认的模板文件 58 | */ 59 | public static String TemplatePath = IftPath +"template/Template.ftl"; 60 | 61 | /** 62 | * 默认测试报告输出路径 63 | */ 64 | public static String ReportPath=IftPath+"report/"; 65 | /** 66 | * 默认的配置文件 67 | */ 68 | public static String ConfFile = IftPath + "config/IftConf.properties"; 69 | 70 | //代理相关配置信息 71 | /** 72 | * 是否启用代理配置 73 | */ 74 | public static String ProxyEnable = getPropValue("ProxyEnable","N"); 75 | /** 76 | * 代理IP 77 | */ 78 | public static String ProxyIp = getPropValue("ProxyIp","127.0.0.1"); 79 | /** 80 | * 代理端口 81 | */ 82 | public static int PROXY_PORT = Integer.parseInt(getPropValue("ProxyPort","8888")); 83 | 84 | //https协议配置 85 | /** 86 | * 是否使用本地认证信息 87 | */ 88 | public static String SSL = getPropValue("SSL","N"); 89 | /** 90 | * 本地认证信息路径 91 | */ 92 | public static String KeyPath = getPropValue("keyPath",IftConf.RootPath); 93 | /** 94 | * 密匙库的密码 95 | */ 96 | public static String KeyPassword = getPropValue("keyPassword",""); 97 | 98 | //时间样式设置 99 | public static String DateFormat = getPropValue("dateFormat","yyyMMddHHmmss"); 100 | 101 | //结果比对参数 102 | /** 103 | * json默认解析方式 单层解析 104 | */ 105 | public static final int parseJson = 1; 106 | 107 | //测试用例Excel文件读取 相关配置信息 108 | /** 109 | * url所在行数 110 | */ 111 | public static final int urlRow = 0; 112 | /** 113 | * url所在列数 114 | */ 115 | public static final int urlCol = 1; 116 | /** 117 | * httpMethod所在行数 118 | */ 119 | public static final int methodRow = 1; 120 | /** 121 | * httpMethod所在列数 122 | */ 123 | public static final int methodCol = 1; 124 | /** 125 | * 全局cookie所在行数 126 | */ 127 | public static final int cookieRow = 2; 128 | /** 129 | * 全局cookie所在列数 130 | */ 131 | public static final int cookieCol = 1; 132 | /** 133 | * 参数签名计算参数个数所在行数 134 | */ 135 | public static final int argCountRow = 3; 136 | /** 137 | * 参数签名计算参数个数所在列数 138 | */ 139 | public static final int argCountCol = 1; 140 | /** 141 | * 标题所在行 142 | */ 143 | public static final int typeRow = 4; 144 | /** 145 | * 用例数据开始行数 146 | */ 147 | public static final int paramStartRow = 5; 148 | /** 149 | * 用例数据开始列表 150 | */ 151 | public static final int paramStartCol = 3; 152 | /** 153 | * caseId所在列数 154 | */ 155 | public static final int caseIdCol = 1; 156 | /** 157 | * 是否执行属性所在列数 158 | */ 159 | public static final int isRunCol = 1; 160 | /** 161 | * secondUrl所在列数 162 | */ 163 | public static final int secondUrlCol = 2; 164 | 165 | 166 | 167 | /** 168 | * 删除默认临时目录 169 | */ 170 | public static void delTmpPath() { 171 | try { 172 | // 清空java文件生成目录 173 | FileUtils.deleteDirectory(new File(JavaPath)); 174 | } catch (IOException e) { 175 | // e.printStackTrace(); 176 | } 177 | } 178 | 179 | 180 | 181 | /** 182 | * 如果配置文件不存在,写入 183 | * @return boolean 已存在或创建失败时返回false 创建成功返回true 184 | */ 185 | public static boolean writeConf() { 186 | //相应配置文件如果不存在,则创建 187 | boolean flag =false; 188 | if (!new File(ConfFile).exists()){ 189 | flag = copyFile(IftConf.class.getResourceAsStream("/IftConf.properties"),new File(ConfFile)); 190 | } 191 | if (!new File(TemplatePath).exists()){ 192 | flag = copyFile(IftConf.class.getResourceAsStream("/Template.ftl"),new File(TemplatePath)); 193 | } 194 | return flag; 195 | } 196 | 197 | /** 198 | * 设置依赖的jar文件路径信息 maven 199 | * @param args 200 | * @return boolean 设置成功返回true 201 | */ 202 | public static boolean updateJarFile(String[] args) { 203 | 204 | if (IftConf.JarFile.length()>0) { 205 | return true;//JarFile已设置 206 | } 207 | try { 208 | if (null!=args && args.length>0) {//设置JarFile,同时写入文件 209 | JarFile=args[0]; 210 | FileUtils.writeStringToFile(new File(IftConf.IftPath+"JarFile"), JarFile, "UTF-8"); 211 | }else{ 212 | if (new File(IftPath+"JarFile").exists()) {//已存在则读取 213 | FileUtils.readFileToString(new File(IftPath+"JarFile"), "UTF-8"); 214 | IftConf.JarFile=FileUtils.readFileToString(new File(IftPath+"JarFile"), "UTF-8"); 215 | }else{ 216 | System.out.print("在eclipse中,第一次需要以maven方式执行"); 217 | return false; 218 | } 219 | } 220 | } catch (IOException e) { 221 | // e.printStackTrace(); 222 | return false; 223 | } 224 | return true; 225 | } 226 | 227 | 228 | /** 229 | * 获取项目根目录,如果是在Tomcat中运行,则返回部署根目录 230 | * @return String 231 | */ 232 | private static String getRootPath() { 233 | String path=""; 234 | if (IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")!=-1) { 235 | path=IftConf.class.getClassLoader().getResource("").toString().substring(6, IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")); 236 | path=path+"/"; 237 | }else { 238 | String temp=System.getProperty("user.dir"); 239 | temp=temp.replace("\\","/"); 240 | path=temp+"/"; 241 | } 242 | return path; 243 | } 244 | 245 | /** 246 | * 获取编译输出目录,如果是在Tomcat中运行,则返回部署目录下的WEB-INF/classes/ 否则返回bin/ 247 | * @return String 248 | */ 249 | private static String getDistPath() { 250 | String path=""; 251 | if (IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")!=-1) { 252 | path=IftConf.class.getClassLoader().getResource("").toString().substring(6, IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")); 253 | path=path+"/WEB-INF/classes/"; 254 | }else { 255 | // path = GlobalSettings.class.getClassLoader().getResource("").toString(); 256 | String temp=System.getProperty("user.dir"); 257 | temp=temp.replace("\\","/"); 258 | path=temp+"/target/classes/"; 259 | } 260 | return path; 261 | } 262 | 263 | /** 264 | * 获取jar包存放的lib目录,如果是在Tomcat中运行,则返回部署目录下的WEB-INF/lib/ 否则返回lib/ 265 | * @return String 266 | */ 267 | private static String getLibPath() { 268 | String path=""; 269 | if (IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")!=-1) { 270 | path=IftConf.class.getClassLoader().getResource("").toString().substring(6, IftConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")); 271 | path=path+"/WEB-INF/lib/"; 272 | }else { 273 | // path = GlobalSettings.class.getClassLoader().getResource("").toString(); 274 | String temp=System.getProperty("user.dir"); 275 | temp=temp.replace("\\","/"); 276 | path=temp+"/lib/"; 277 | } 278 | return path; 279 | } 280 | 281 | private static String getPropValue(String key, String defaultValue) { 282 | return getProperties().getProperty(key, defaultValue); 283 | } 284 | 285 | private static Properties getProperties() { 286 | Properties prop = new Properties(); 287 | try { 288 | //配置文件不存在则创建 289 | IftConf.writeConf(); 290 | FileInputStream file = new FileInputStream(ConfFile); 291 | prop.load(new InputStreamReader(file,"UTF-8")); 292 | file.close(); 293 | } catch (Exception e) { 294 | // e.printStackTrace(); 295 | } 296 | return prop; 297 | } 298 | 299 | private static boolean copyFile(InputStream from, File to) { 300 | try { 301 | if (! to.getParentFile().exists()) { 302 | to.getParentFile().mkdirs(); 303 | } 304 | OutputStream os = new FileOutputStream(to); 305 | byte[] buffer = new byte[65536]; 306 | int count = from.read(buffer); 307 | while (count > 0) { 308 | os.write(buffer, 0, count); 309 | count = from.read(buffer); 310 | } 311 | os.close(); 312 | return true; 313 | } catch (IOException e) { 314 | // e.printStackTrace(); 315 | return false; 316 | } 317 | 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/IftExec.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.github.qihootest.leo.ift; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import com.github.qihootest.leo.dispatch.DispatchConf; 10 | import com.github.qihootest.leo.dispatch.ExecTask; 11 | import com.github.qihootest.leo.dispatch.report.TestReport; 12 | import com.github.qihootest.leo.dispatch.run.TestRunInfo; 13 | import com.github.qihootest.leo.dispatch.testcase.ICase; 14 | import com.github.qihootest.leo.ift.testcase.autocreate.IftDataFileCase; 15 | 16 | /** 17 | * 接口测试任务执行类 18 | * @author @bwgang (bwgang@163.com)
19 | * 20 | */ 21 | public class IftExec { 22 | 23 | private ExecTask exec; 24 | private TestRunInfo runInfo; 25 | private List caseList; 26 | private IftDataFileCase dataCase; 27 | 28 | /** 29 | * 构造函数 30 | */ 31 | public IftExec(){ 32 | 33 | //清空临时目录 34 | DispatchConf.delTmpPath(); 35 | IftConf.delTmpPath(); 36 | exec = new ExecTask(); 37 | runInfo = new TestRunInfo(); 38 | caseList = new ArrayList<>();//用例列表 39 | dataCase = new IftDataFileCase(); 40 | dataCase.setIftTaskName("接口测试"); 41 | } 42 | 43 | /** 44 | * 构造函数 45 | * @param threadCont 46 | */ 47 | public IftExec(int threadCont,String setParallel){ 48 | 49 | //清空临时目录 50 | DispatchConf.delTmpPath(); 51 | IftConf.delTmpPath(); 52 | exec = new ExecTask(); 53 | runInfo = new TestRunInfo(); 54 | caseList = new ArrayList<>();//用例列表 55 | dataCase = new IftDataFileCase(setParallel,threadCont); 56 | dataCase.setIftTaskName("接口测试"); 57 | } 58 | 59 | /** 60 | * 添加用例 61 | * @param casePath 用例路径 必填 62 | * @param sheetName Excel的sheet表名 可选 63 | * @param caseName 用例名称 必填 64 | * @param cls 执行用例的类 必填 65 | * @param method 类中的方法 必填 66 | */ 67 | public void addCase(String casePath, String sheetName, String caseName, 68 | Class cls,String method){ 69 | dataCase.addCase(casePath, sheetName, caseName, cls, method); 70 | } 71 | 72 | /** 73 | * 任务执行 74 | * @return TestReport 75 | */ 76 | public TestReport run(){ 77 | caseList.add(dataCase); 78 | //设置运行配置信息 79 | runInfo.setTaskName(dataCase.getTaskName());//任务名称 80 | runInfo.setCaseList(caseList);//用例 81 | runInfo.setHtmlReportOutPath(dataCase.getHtmlReportPath());//设置测试报告输出目录, 82 | 83 | //可选运行参数设置 84 | // runInfo.setTestng_OutPut(IftConf.IftPath+"testng-out/");//设置TestNG输出目录,--可选 85 | // runInfo.setHtmlReportOutPath(IftConf.IftPath+"report/");//设置测试报告输出目录,---可选 86 | // runInfo.setHtmlReportTitle("设置测试报告标题-可选");//设置测试报告标题 ---可选 87 | // TestngLog.setOutputTestNGLog(false);//不记录TestNG日志,--可选 88 | 89 | //执行 90 | exec.setRunInfo(runInfo); 91 | return exec.Exec(); 92 | } 93 | 94 | /** 95 | * 返回Excel报告的路径 96 | * @return String 97 | */ 98 | public String getExcelReportPath() { 99 | return dataCase.getExcelReportPath(); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/core/CompareResult.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.core; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedList; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | import java.util.TreeMap; 11 | 12 | import com.github.qihootest.leo.ift.IftConf; 13 | import com.github.qihootest.leo.toolkit.util.CommUtils; 14 | import com.github.qihootest.leo.toolkit.util.JsonUtil; 15 | import com.github.qihootest.leo.toolkit.util.StringUtil; 16 | import com.github.qihootest.leo.toolkit.util.XmlUtil; 17 | 18 | 19 | /** 20 | * 说明:比对期望结果与实际结果 21 | * 22 | * @author lianghui (lianghui@360.cn) 23 | * 24 | */ 25 | public class CompareResult { 26 | 27 | private String clearActres; 28 | private String clearExpres; 29 | 30 | /** 31 | * 默认构造函数 32 | */ 33 | public CompareResult() { 34 | clearActres = ""; 35 | clearExpres = ""; 36 | } 37 | 38 | /** 39 | * 说明:期望结果与实际结果的比对 40 | * @param expRes 预期结果 41 | * @param actRes 从请求响应中提取过滤后的实际结果 42 | * @param config 可选参数默认为1,只解析一层,2时全解析 43 | * @return boolean 相同时返回true,不同时返回false 44 | */ 45 | public boolean getCompareResult(String expRes, String actRes,int config){ 46 | //开始比对之前,清空已整理后的预期与实际结果字符串 47 | setClearActres(""); 48 | setClearExpres(""); 49 | //预期结果中匹配${} 50 | Pattern pattern = Pattern.compile("^\\$\\{(.*)\\}$"); 51 | Matcher matcher = pattern.matcher(expRes); 52 | Map exp = new TreeMap(); 53 | Map act = new TreeMap(); 54 | act = trimActres(actRes,config); //将实际结果解析成map 55 | if (StringUtil.IsNullOrEmpty(expRes)) { 56 | setClearExpres("预期结果为null或空字符串,不进行比对"); 57 | setClearActres("未设置预期值&实际结果为:"+actRes); 58 | return true;//预期结果为空或null时,不再进行比对处理,直接返回true 59 | }else if(matcher.matches()){ 60 | String para = matcher.group(1); 61 | if(para.contains("_")){ //当依赖参数中有多个值时进行处理(同一个id可能会有多个依赖参数,用_进行分割) 62 | String[] paraArray = para.split("_"); 63 | para = paraArray[0]; 64 | } 65 | if(act.get(para)!=null){ //实际结果中没有预期结果参数,则用例失败 66 | setClearExpres("预期结果为依赖参数,不进行验证"); 67 | setClearActres("预期结果为依赖参数&实际结果为:"+actRes); 68 | IftConf.DependPara.put(matcher.group(1), act.get(para)); //添加依赖参数(赋值) 69 | return true; 70 | }else{ //当未匹配到依赖参数时返回 false 71 | setClearExpres("预期结果为依赖参数:"+expRes); 72 | setClearActres("实际结果未匹配到参数:"+para); 73 | return false; 74 | } 75 | 76 | } 77 | exp = trimExpres(expRes); //将预期结果解析成map 78 | if (StringUtil.IsNullOrEmpty(actRes)) { 79 | setClearActres("实际结果为null或空字符串,未找到"); 80 | return false;//实际结果为空或null时,不再进行比对处理,直接返回false 81 | } 82 | return compareMap(exp, act); 83 | } 84 | 85 | /** 86 | * 说明:期望结果与实际结果的比对 json解析方式 使用默认 87 | * @param expRes 预期结果 88 | * @param actRes 从请求响应中提取过滤后的实际结果 89 | * @return boolean 相同时返回true,不同时返回false 90 | */ 91 | public boolean getCompareResult(String expRes, String actRes) { 92 | return getCompareResult(expRes,actRes,IftConf.parseJson); 93 | } 94 | 95 | /** 96 | * 说明:比较两个map 97 | * @param expMap 98 | * @param actMap 99 | * @return boolean 如果map1∩map2等于map1或者map2,则返回true,否则返回false 100 | */ 101 | private boolean compareMap(Map expMap,Map actMap) { 102 | List listFlag = new LinkedList(); 103 | String record = "";// 记录在实际结果中查找到的结果,记录格式为key=value&key=value..... 104 | 105 | // 遍历预期结果map表 106 | for (Entry entryExp : expMap.entrySet()) { 107 | String expKey = entryExp.getKey(); 108 | String expValue = entryExp.getValue(); 109 | 110 | boolean flag=false;//在实际结果中是否找到对应的key-value 111 | 112 | //遍历实际结果map表 113 | for (Entry entryAct : actMap.entrySet()) { 114 | String actKey = entryAct.getKey(); 115 | String actValue = entryAct.getValue(); 116 | if (actKey.equals(expKey)) {//在实际结果中找到对应的key-value 117 | // 记录每个键值的比对结果 118 | if (CompareStr(expValue, actValue)) { 119 | listFlag.add(1); 120 | } else { 121 | listFlag.add(0); 122 | } 123 | // 记录在实际结果中找到的记录 124 | record += actKey + "=" + actValue + "&"; 125 | flag=true; 126 | break;//比对完毕,结束实际结果map表遍历 127 | } 128 | }//实际结果map表遍历结束 129 | 130 | //在实际结果map表中未找到对应的key-value时的处理 131 | if (false==flag) { 132 | record +=expKey+"的值未找到"; 133 | listFlag.add(0); 134 | } 135 | 136 | }// 预期结果map表遍历结束 137 | 138 | // 更新整理后实际结果的值 139 | if (record.length() > 2) { 140 | if (record.substring(record.length() - 1, record.length()).equals("&")) { 141 | setClearActres(record.substring(0, record.length() - 1)); 142 | }else{ 143 | setClearActres(record+"未找到"); 144 | } 145 | } 146 | 147 | if (record.indexOf("未找到")>-1) { 148 | setClearActres(record+"&实际结果为:"+StringUtil.getStrFromMap(actMap)); 149 | } 150 | 151 | // 汇总比对结果 152 | int sum = 1; 153 | for (int i = 0; i < listFlag.size(); i++) { 154 | sum *= listFlag.get(i); 155 | } 156 | // 返回比对结果 157 | if (sum == 1) { 158 | return true; 159 | } else { 160 | return false; 161 | } 162 | } 163 | 164 | /** 165 | * 单个预期结果值与对应实际结果值的比对,支持预期结果值以#标识分割,多个预期结果的处理 166 | * @param expValue 167 | * @param actValue 168 | * @return boolean 169 | * @author lianghui 170 | */ 171 | private boolean CompareStr(String expValue, String actValue) { 172 | // 预期结果与实际结果任一为null,返回false 173 | if (null == actValue || null == expValue) return false; 174 | // 判断实际结果是否为数组格式 175 | if (actValue.startsWith("[") && actValue.endsWith("]")) { 176 | String[] actValueList = StringUtil.stringToArray(actValue); 177 | // 判断预期结果是否来数组格式(预期结果包含[]) 178 | if (expValue.startsWith("[") && expValue.endsWith("]")) { 179 | String[] expArray = StringUtil.stringToArray(expValue); 180 | if (actValueList.length == expArray.length) { // 判断实际结果与预期结果的数组长度是否相同,不相同则直接返回错误 181 | for (int i = 0; i < actValueList.length; i++) { 182 | if (!(actValueList[i].trim()) 183 | .equals(expArray[i].trim())) { // 判断实际结果与预期结果中的数据组是否相同 184 | return false; 185 | } 186 | } 187 | // 预期结果与实际结果的数组长度不相等,则直接返回false 188 | } else { 189 | return false; 190 | } 191 | // 预期结果为非数组,则判断预期结果是否包含在实际结果中 192 | } else { 193 | int len = actValueList.length; 194 | for (int i = 0; i < len; i++) { 195 | if ((actValueList[i].trim()).equals(expValue.trim())) { 196 | return true; 197 | } 198 | 199 | } 200 | } 201 | return true; 202 | } else { 203 | 204 | // 判断是否有多个预期结果值(预期结果中包含#,进入下面方法) 205 | if (expValue.contains("#")) { 206 | String[] allExpValue2 = expValue.split("#"); 207 | for (int i = 0; i < allExpValue2.length; i++) { 208 | if (actValue.equals(allExpValue2[i])) { 209 | return true; 210 | } 211 | } 212 | return false;// 返回结果 213 | } 214 | 215 | // 仅1个预期结果值,并对int关键词做处理 216 | if (expValue.contains("int")) { // 预期结果中有int值 217 | if (actValue.matches("[0-9]+") & !actValue.equals("0")) { // 匹配int类型实际结果,但实际结果不能为0 218 | return true; 219 | } else { 220 | return false; 221 | } 222 | } else if (!actValue.equalsIgnoreCase(expValue)) { // 预期结果中没有int值 223 | return false; 224 | } else { 225 | return true; 226 | } 227 | } 228 | 229 | } 230 | 231 | /** 232 | * 说明:对预期结果的字符串进行清理, 233 | * @param expres预期结果字符串 234 | * @return Map 返回整理后的预期结果 235 | */ 236 | private Map trimExpres(String expres) { 237 | Map trimExpres = new TreeMap(); 238 | trimExpres = CommUtils.parseQuery(expres, '&', '='); 239 | if (null == trimExpres) { 240 | trimExpres = new TreeMap(); 241 | setClearExpres("预期结果未找到,请检查:"+expres); 242 | return trimExpres; 243 | } 244 | String temp = ""; 245 | int i = 0; 246 | for (Entry entry : trimExpres.entrySet()) { 247 | String key = entry.getKey().toString(); 248 | String value = entry.getValue().toString(); 249 | if (i == 0) { 250 | temp += key + "=" + value; 251 | } else { 252 | temp += "&" + key + "=" + value; 253 | } 254 | i++; 255 | } 256 | setClearExpres(temp); 257 | return trimExpres; 258 | } 259 | 260 | /** 261 | * 说明:对请求返回的实际结果字符串进行清理, 262 | * @param responseRes 实际结果字符串 263 | * @return Map ,返回整理后的实际结果 264 | */ 265 | public Map trimActres(String responseRes,int config) { 266 | Map trimactres = new TreeMap(); 267 | Map map = new TreeMap(); 268 | XmlUtil xmlUtil = new XmlUtil(); 269 | if (XmlUtil.isXmlText(responseRes)) { 270 | map = xmlUtil.fomatXMLToMap(responseRes); 271 | if (map.size()<1) { 272 | map.put("解析xml格式错误", "---"+responseRes); 273 | } 274 | } else{ 275 | if(config == 1){//单层方式解析json串 276 | map = JsonUtil.getResult(responseRes); 277 | }else if(config == 2){//多层方式解析json串 278 | map = JsonUtil.getAllResult(responseRes); 279 | }else{//config不为1、2时 按单层方式解析 280 | map = JsonUtil.getResult(responseRes); 281 | } 282 | if(map == null){ 283 | trimactres.put("解析json格式错误", "---"+responseRes); 284 | return trimactres; 285 | } 286 | 287 | } 288 | for (Iterator> it = map.entrySet().iterator(); it.hasNext();) { //object类型转换成String类型 289 | @SuppressWarnings("rawtypes") 290 | Map.Entry entity = it.next(); 291 | trimactres.put(entity.getKey().toString(), entity.getValue().toString()); 292 | } 293 | return trimactres; 294 | } 295 | 296 | 297 | public String getClearActres() { 298 | return clearActres; 299 | } 300 | 301 | public void setClearActres(String clearActres) { 302 | this.clearActres = clearActres; 303 | } 304 | 305 | public String getClearExpres() { 306 | return clearExpres; 307 | } 308 | 309 | public void setClearExpres(String clearExpres) { 310 | this.clearExpres = clearExpres; 311 | } 312 | 313 | } 314 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/core/IFtResultInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.core; 2 | 3 | import com.github.qihootest.leo.toolkit.httpclient.ResponseInfo; 4 | 5 | 6 | /** 7 | * 接口测试执行结果信息 8 | * @author lianghui (lianghui@360.cn) 9 | */ 10 | public class IFtResultInfo { 11 | private ResponseInfo responseInfo;//http请求的返回信息 12 | private String expRes;//预期结果信息 13 | private String actRes;//整理后的实际结果信息 14 | private boolean compareRes;//预期与实际的比对结果 true或false 15 | public ResponseInfo getResponseInfo() { 16 | return responseInfo; 17 | } 18 | public void setResponseInfo(ResponseInfo responseInfo) { 19 | this.responseInfo = responseInfo; 20 | } 21 | public String getExpRes() { 22 | return expRes; 23 | } 24 | public void setExpRes(String expRes) { 25 | this.expRes = expRes; 26 | } 27 | public String getActRes() { 28 | return actRes; 29 | } 30 | public void setActRes(String actRes) { 31 | this.actRes = actRes; 32 | } 33 | public boolean getCompareRes() { 34 | return compareRes; 35 | } 36 | public void setCompareRes(boolean compareRes) { 37 | this.compareRes = compareRes; 38 | } 39 | 40 | 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/IftTestCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.TreeMap; 8 | 9 | /** 10 | * 说明:测试用例实体类 11 | * @author lianghui (lianghui@360.cn) 12 | * 13 | */ 14 | public class IftTestCase { 15 | private String url;//发起请求的url地址 16 | private String httpMethod;//请求的方法 17 | private int argCount; //参与签名计算的参数个数 18 | private String enCoding;//编码 19 | private String casesetName;//测试集名称 20 | private String templatePath;//使用的模板存储位置 21 | private String cookie;//此用例的cookie信息 22 | private String secretKey;//参与签名计算的密钥 23 | private String signKey;//标识签名值参数的key值 24 | private boolean signFlag;//标识是否计算签名,true--需要签名,false不需要签名 25 | private LinkedHashMap caseMap;//所有键值对信息 26 | private List paralist;//get请求的参数项列表 27 | private List formlist;//post请求的参数项列表 28 | private List signlist;//参与签名计算的参数项列表 29 | private List headerlist;//header的参数项列表 30 | private TreeMap headerMap;//发起请求时使用的header信息 31 | private Map results;//依据此用例发起请求后返回的结果串 32 | 33 | private String caseId;//用例的ID标识 34 | private String testPoint;//测试点 35 | 36 | /** 37 | * 默认构造函数 38 | */ 39 | public IftTestCase() { 40 | this.url = ""; 41 | this.httpMethod = ""; 42 | this.argCount = 0; 43 | this.enCoding = ""; 44 | this.casesetName = ""; 45 | this.templatePath = ""; 46 | this.cookie = ""; 47 | this.secretKey = ""; 48 | this.signFlag = false; 49 | this.caseMap = new LinkedHashMap(); 50 | this.paralist = new ArrayList(); 51 | this.formlist = new ArrayList(); 52 | this.signlist = new ArrayList(); 53 | this.headerlist = new ArrayList(); 54 | this.headerMap = new TreeMap(); 55 | this.results = new TreeMap(); 56 | } 57 | /** 58 | * @return the url 59 | */ 60 | public String getUrl() { 61 | return url; 62 | } 63 | /** 64 | * @param url the url to set 65 | */ 66 | public void setUrl(String url) { 67 | this.url = url; 68 | } 69 | /** 70 | * @return the httpMethod 71 | */ 72 | public String getHttpMethod() { 73 | return httpMethod; 74 | } 75 | /** 76 | * @param httpMethod the httpMethod to set 77 | */ 78 | public void setHttpMethod(String httpMethod) { 79 | this.httpMethod = httpMethod; 80 | } 81 | 82 | /** 83 | * @return the argCount 84 | */ 85 | public int getArgCount() { 86 | return argCount; 87 | } 88 | /** 89 | * @param argCount the argCount to set 90 | */ 91 | public void setArgCount(int argCount) { 92 | this.argCount = argCount; 93 | } 94 | /** 95 | * @return the enCoding 96 | */ 97 | public String getEnCoding() { 98 | return enCoding; 99 | } 100 | /** 101 | * @param enCoding the enCoding to set 102 | */ 103 | public void setEnCoding(String enCoding) { 104 | this.enCoding = enCoding; 105 | } 106 | /** 107 | * @return the casesetName 108 | */ 109 | public String getCasesetName() { 110 | return casesetName; 111 | } 112 | /** 113 | * @param casesetName the casesetName to set 114 | */ 115 | public void setCasesetName(String casesetName) { 116 | this.casesetName = casesetName; 117 | } 118 | /** 119 | * @return the templatePath 120 | */ 121 | public String getTemplatePath() { 122 | return templatePath; 123 | } 124 | /** 125 | * @param templatePath the templatePath to set 126 | */ 127 | public void setTemplatePath(String templatePath) { 128 | this.templatePath = templatePath; 129 | } 130 | /** 131 | * @return the cookie 132 | */ 133 | public String getCookie() { 134 | return cookie; 135 | } 136 | /** 137 | * @param cookie the cookie to set 138 | */ 139 | public void setCookie(String cookie) { 140 | this.cookie = cookie; 141 | } 142 | /** 143 | * @return the secretKey 144 | */ 145 | public String getSecretKey() { 146 | return secretKey; 147 | } 148 | /** 149 | * @param secretKey the secretKey to set 150 | */ 151 | public void setSecretKey(String secretKey) { 152 | this.secretKey = secretKey; 153 | } 154 | /** 155 | * @return the signKey 156 | */ 157 | public String getSignKey() { 158 | return signKey; 159 | } 160 | /** 161 | * @param signKey the signKey to set 162 | */ 163 | public void setSignKey(String signKey) { 164 | this.signKey = signKey; 165 | } 166 | /** 167 | * @return the signFlag 168 | */ 169 | public boolean isSignFlag() { 170 | return signFlag; 171 | } 172 | /** 173 | * @param signFlag the signFlag to set 174 | */ 175 | public void setSignFlag(boolean signFlag) { 176 | this.signFlag = signFlag; 177 | } 178 | 179 | /** 180 | * @return the caseMap 181 | */ 182 | public LinkedHashMap getCaseMap() { 183 | return caseMap; 184 | } 185 | /** 186 | * @param caseMap the caseMap to set 187 | */ 188 | public void setCaseMap(LinkedHashMap caseMap) { 189 | this.caseMap = caseMap; 190 | } 191 | /** 192 | * @return the paralist 193 | */ 194 | public List getParalist() { 195 | return paralist; 196 | } 197 | /** 198 | * @param paralist the paralist to set 199 | */ 200 | public void setParalist(List paralist) { 201 | this.paralist = paralist; 202 | } 203 | /** 204 | * @return the formlist 205 | */ 206 | public List getFormlist() { 207 | return formlist; 208 | } 209 | /** 210 | * @param formlist the formlist to set 211 | */ 212 | public void setFormlist(List formlist) { 213 | this.formlist = formlist; 214 | } 215 | /** 216 | * @return the signlist 217 | */ 218 | public List getSignlist() { 219 | return signlist; 220 | } 221 | /** 222 | * @param signlist the signlist to set 223 | */ 224 | public void setSignlist(List signlist) { 225 | this.signlist = signlist; 226 | } 227 | /** 228 | * @return the headerlist 229 | */ 230 | public List getHeaderlist() { 231 | return headerlist; 232 | } 233 | /** 234 | * @param headerlist the headerlist to set 235 | */ 236 | public void setHeaderlist(List headerlist) { 237 | this.headerlist = headerlist; 238 | } 239 | /** 240 | * @return the headerMap 241 | */ 242 | public TreeMap getHeaderMap() { 243 | return headerMap; 244 | } 245 | /** 246 | * @param headerMap the headerMap to set 247 | */ 248 | public void setHeaderMap(TreeMap headerMap) { 249 | this.headerMap = headerMap; 250 | } 251 | /** 252 | * @return the results 253 | */ 254 | public Map getResults() { 255 | return results; 256 | } 257 | /** 258 | * @param results the results to set 259 | */ 260 | public void setResults(Map results) { 261 | this.results = results; 262 | } 263 | public String getCaseId() { 264 | return caseId; 265 | } 266 | public void setCaseId(String caseId) { 267 | this.caseId = caseId; 268 | } 269 | public String getTestPoint() { 270 | return testPoint; 271 | } 272 | public void setTestPoint(String testPoint) { 273 | this.testPoint = testPoint; 274 | } 275 | 276 | } 277 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/autocreate/CreateJavaFile.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase.autocreate; 2 | 3 | import java.util.Map; 4 | import java.util.TreeMap; 5 | 6 | import com.github.qihootest.leo.ift.IftConf; 7 | import com.github.qihootest.leo.toolkit.util.FreeMakerUtil; 8 | import com.github.qihootest.leo.toolkit.util.LogUtil; 9 | 10 | 11 | /** 12 | * 封装用例集,对集合进行分组格式化等处理,当前是1个excel文件对应1个此类的实例 13 | * @author lianghui (lianghui@360.cn) 2012-11-12 14 | * 15 | */ 16 | public class CreateJavaFile { 17 | 18 | private static LogUtil log=LogUtil.getLogger(CreateJavaFile.class);//日志记录 19 | 20 | /** 21 | * 根据用例数据信息创建对应的.java源文件 22 | * @return boolean 创建成功返回true,失败返回false 23 | */ 24 | public boolean creatJavaSrcFile(JavaCaseInfo javaInfo) { 25 | String javaFilePathTmp = javaInfo.getJavaSavePath()+javaInfo.getJavaFileName()+".java"; 26 | FreeMakerUtil creatjava=new FreeMakerUtil(); 27 | if (creatjava.CreateJavaFile(IftConf.TemplatePath, getJavaFileData(javaInfo), javaFilePathTmp)) { 28 | log.info("创建"+javaInfo.getJavaFileName()+"对应的.java文件成功:"+javaFilePathTmp); 29 | return true; 30 | } 31 | log.error("创建"+javaInfo.getJavaFileName()+"对应的.java文件成功失败:"+javaFilePathTmp); 32 | return false; 33 | } 34 | 35 | 36 | //私有方法 37 | private Map getJavaFileData(JavaCaseInfo javaInfo){ 38 | Map data = new TreeMap(); 39 | data.put("javaInfo", javaInfo); 40 | Map clsInfo = new TreeMap<>(); 41 | String impotInfo = javaInfo.getCls().getPackage().toString(); 42 | impotInfo = impotInfo.substring(8)+"."+javaInfo.getCls().getSimpleName(); 43 | clsInfo.put("importInfo", impotInfo); 44 | clsInfo.put("className", javaInfo.getCls().getSimpleName()); 45 | clsInfo.put("method", javaInfo.getMethod()); 46 | data.put("clsInfo", clsInfo); 47 | return data; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/autocreate/IftDataFileCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase.autocreate; 2 | 3 | import java.util.List; 4 | 5 | import com.github.qihootest.leo.dispatch.testcase.CreateXmlFile; 6 | import com.github.qihootest.leo.dispatch.testcase.SuperCase; 7 | import com.github.qihootest.leo.ift.IftConf; 8 | import com.github.qihootest.leo.ift.testcase.format.FormatCase; 9 | import com.github.qihootest.leo.toolkit.util.CompilerUtil; 10 | import com.github.qihootest.leo.toolkit.util.FileUtil; 11 | import com.github.qihootest.leo.toolkit.util.LogUtil; 12 | import com.github.qihootest.leo.toolkit.util.StringUtil; 13 | 14 | 15 | /** 16 | * 数据文件类型的测试用例 17 | * @author lianghui (lianghui@360.cn) 18 | * 19 | */ 20 | public class IftDataFileCase extends SuperCase{ 21 | 22 | private LogUtil log =LogUtil.getLogger(IftDataFileCase.class);//日志记录 23 | //任务名称 24 | private String taskName;//测试任务名称 25 | //根据用例数据文件,创建java、xml文件相关配置信息 26 | private String allReportPath ;// html、excel测试报告存储的上级目录 27 | private String excelReportName;//excel格式测试报告的名称 28 | 29 | private CreateJavaFile createJavaFile;//生成java文件 30 | private CreateXmlFile createXmlFile;//生成xml文件 31 | 32 | /** 33 | * 构造函数 34 | */ 35 | public IftDataFileCase() { 36 | super(); 37 | createJavaFile = new CreateJavaFile(); 38 | createXmlFile = new CreateXmlFile(); 39 | setIftTaskName("未命名测试任务"); 40 | excelReportName="未命名接口测试"; 41 | } 42 | 43 | /** 44 | * 构造函数 45 | * @param threadCont 线程数 46 | * @param setParallel 设置多线程执行方式methods;tests;classes 47 | */ 48 | public IftDataFileCase(String setParallel,int threadCont) { 49 | super(); 50 | if(setParallel.equals("methods")||setParallel.equals("tests")||setParallel.equals("classes")){ 51 | createJavaFile = new CreateJavaFile(); 52 | createXmlFile = new CreateXmlFile(threadCont,setParallel); 53 | setIftTaskName("未命名测试任务"); 54 | excelReportName="未命名接口测试"; 55 | }else{ 56 | log.error("多线程不支持:"+setParallel+"方法"); 57 | } 58 | 59 | 60 | } 61 | 62 | public List getCaseList() { 63 | createXmlFile(); 64 | return this.xmlPathNameList; 65 | } 66 | /** 67 | * 添加用例 68 | * @param casePath 用例路径 必填 69 | * @param sheetName Excel的sheet表名 可选 70 | * @param caseName 用例名称 必填 71 | * @param cls 执行用例的类 必填 72 | * @param method 类中的方法 必填 73 | */ 74 | public void addCase(String casePath, String sheetName, String caseName, 75 | Class cls,String method) { 76 | if (StringUtil.IsNullOrEmpty(casePath) || StringUtil.IsNullOrEmpty(caseName)) { 77 | return; 78 | }//任一项空值或长度小于1时,不做处理 79 | JavaCaseInfo javaCaseInfo = new JavaCaseInfo(); 80 | //读取用例 81 | FormatCase formatcase=new FormatCase(); 82 | formatcase.FormatCaseFromObj(casePath,sheetName); 83 | //存储用例实体列表信息 84 | javaCaseInfo.setAllCase(formatcase.getTestCase()); 85 | //获取测试集名称作为输出的测试报告名称 86 | this.excelReportName="测试报告_"+formatcase.getCasesetName(); 87 | //存储javaCaseInfo其余信息 88 | javaCaseInfo.setPackageName(IftConf.PackageName); 89 | javaCaseInfo.setJavaFileName(caseName.replace(".", "_")); 90 | javaCaseInfo.setJavaSavePath(IftConf.JavaPath); 91 | javaCaseInfo.setCaseDataPathName(casePath); 92 | javaCaseInfo.setCaseDataSheetName(sheetName); 93 | javaCaseInfo.setExcelReportSheetName(sheetName); 94 | javaCaseInfo.setExcelReportName(this.excelReportName); 95 | javaCaseInfo.setExcelReportPath(getReportPath()); 96 | javaCaseInfo.setCls(cls); 97 | javaCaseInfo.setMethod(method); 98 | //创建java文件 失败则返回 99 | if (!createJavaFile.creatJavaSrcFile(javaCaseInfo)){ 100 | return; 101 | } 102 | //编译java文件为class 失败则返回 103 | if(!CompilerUtil.dynamicCompiler(javaCaseInfo.getJavaSavePath()+javaCaseInfo.getJavaFileName()+".java", 104 | IftConf.DistPath, IftConf.LibPath,IftConf.JarFile)){ 105 | return; 106 | } 107 | //添加到xmlSuite 108 | try { 109 | createXmlFile.addJavaCase(caseName.replace(".", "_"), 110 | Class.forName(javaCaseInfo.getPackageName()+"."+javaCaseInfo.getJavaFileName())); 111 | log.info("添加测试集:"+javaCaseInfo.getJavaFileName()+"成功"); 112 | } catch (ClassNotFoundException e) { 113 | log.error("添加测试集:"+javaCaseInfo.getJavaFileName()+"失败"); 114 | log.error(e.getMessage()); 115 | } 116 | 117 | } 118 | 119 | /** 120 | * 添加用例 121 | * @param casePath 用例路径 必填 122 | * @param caseName 用例名称 必填 123 | * @param cls 执行用例的类 必填 124 | * @param method 类中的方法 必填 125 | */ 126 | public void addCase(String casePath, String caseName,Class cls,String method) { 127 | addCase(casePath,"TestCase",caseName,cls,method); 128 | } 129 | 130 | /** 131 | * 设置任务名称 132 | * @param setTaskName 133 | */ 134 | public void setIftTaskName(String setTaskName) { 135 | this.taskName =setTaskName; 136 | this.createXmlFile.setSuiteName(this.taskName); 137 | setReportPath(IftConf.ReportPath+this.taskName+"/");// 测试报告存储路径 138 | this.excelReportName = this.taskName; 139 | 140 | } 141 | 142 | 143 | /** 144 | * 如果路径无效 则测试报告默认保存在 [qtaf/ift/report/任务名称 ]目录下 145 | * @param reportPath 146 | */ 147 | public void setReportPath(String reportPath){ 148 | if (FileUtil.createDictory(reportPath)) { 149 | this.allReportPath=reportPath; 150 | //清空指定的测试报告目录 151 | FileUtil.delFolder(getReportPath()); 152 | } 153 | } 154 | public String getReportPath(){ 155 | return this.allReportPath; 156 | } 157 | public String getExcelReportPath() { 158 | return getReportPath()+this.excelReportName+".xlsx"; 159 | } 160 | public String getHtmlReportPath() { 161 | return this.allReportPath+"html"; 162 | } 163 | 164 | public String getTaskName() { 165 | return taskName; 166 | } 167 | 168 | /** 169 | * 创建java、xml文件 更新xmlPathNameList列表 170 | * @return boolean 设置成功返回true 171 | */ 172 | private boolean createXmlFile() { 173 | //创建java、xml文件 174 | String xmlFilePath = createXmlFile.getXmlFilePath(); 175 | if (FileUtil.isExist(xmlFilePath)) { 176 | xmlPathNameList.add(xmlFilePath); 177 | log.info("添加xml文件成功:"+xmlFilePath); 178 | return true; 179 | }else{ 180 | log.error("添加xml文件失败:"+xmlFilePath); 181 | return false; 182 | } 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/autocreate/JavaCaseInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase.autocreate; 2 | 3 | import java.util.List; 4 | 5 | import com.github.qihootest.leo.ift.testcase.IftTestCase; 6 | 7 | /** 8 | * 生成java文件时需要的信息 9 | * @author lianghui (lianghui@360.cn) 10 | * 11 | */ 12 | public class JavaCaseInfo { 13 | 14 | private List allCase;//所有用例列表 15 | private String packageName;//包名 16 | private String javaFileName;//java文件名 17 | private String javaSavePath;//java文件保存目录 18 | private String caseDataPathName;//用例数据文件路径 19 | private String caseDataSheetName;//Excel用例数据sheet名称 20 | 21 | private Class cls;//执行用例的类名 22 | private String method;//执行用例的方法名 23 | 24 | private String excelReportSheetName;//excel测试报告sheet名称 25 | private String excelReportName;//excel测试报告文件名称 26 | private String excelReportPath;//excel测试报告存储目录 27 | public List getAllCase() { 28 | return allCase; 29 | } 30 | public void setAllCase(List allCase) { 31 | this.allCase = allCase; 32 | } 33 | public String getPackageName() { 34 | return packageName; 35 | } 36 | public void setPackageName(String packageName) { 37 | this.packageName = packageName; 38 | } 39 | public String getJavaFileName() { 40 | return javaFileName; 41 | } 42 | public void setJavaFileName(String javaFileName) { 43 | this.javaFileName = javaFileName; 44 | } 45 | public String getJavaSavePath() { 46 | return javaSavePath; 47 | } 48 | public void setJavaSavePath(String javaSavePath) { 49 | this.javaSavePath = javaSavePath; 50 | } 51 | public String getCaseDataPathName() { 52 | return caseDataPathName; 53 | } 54 | public void setCaseDataPathName(String caseDataPathName) { 55 | this.caseDataPathName = caseDataPathName; 56 | } 57 | public String getExcelReportSheetName() { 58 | return excelReportSheetName; 59 | } 60 | public void setExcelReportSheetName(String excelReportSheetName) { 61 | this.excelReportSheetName = excelReportSheetName; 62 | } 63 | public String getExcelReportName() { 64 | return excelReportName; 65 | } 66 | public void setExcelReportName(String excelReportName) { 67 | this.excelReportName = excelReportName; 68 | } 69 | public String getExcelReportPath() { 70 | return excelReportPath; 71 | } 72 | public void setExcelReportPath(String excelReportPath) { 73 | this.excelReportPath = excelReportPath; 74 | } 75 | public String getCaseDataSheetName() { 76 | return caseDataSheetName; 77 | } 78 | public void setCaseDataSheetName(String caseDataSheetName) { 79 | this.caseDataSheetName = caseDataSheetName; 80 | } 81 | public Class getCls() { 82 | return cls; 83 | } 84 | public void setCls(Class cls) { 85 | this.cls = cls; 86 | } 87 | public String getMethod() { 88 | return method; 89 | } 90 | public void setMethod(String method) { 91 | this.method = method; 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/format/FormatCase.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase.format; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | 7 | import com.github.qihootest.leo.ift.IftConf; 8 | import com.github.qihootest.leo.ift.testcase.IftTestCase; 9 | import com.github.qihootest.leo.toolkit.util.FileUtil; 10 | import com.github.qihootest.leo.toolkit.util.LogUtil; 11 | import com.github.qihootest.leo.toolkit.util.StringUtil; 12 | 13 | /** 14 | * 功能说明:格式化测试用例数据, 目前只支持读取excel格式数据,XML、数据库等后续扩展 15 | * @author lianghui (lianghui@360.cn) 16 | */ 17 | public class FormatCase { 18 | 19 | private static LogUtil log=LogUtil.getLogger(FormatCase.class);//日志记录 20 | 21 | private List> arrCase; 22 | private List testCase; 23 | private String url; 24 | private String httpMethod; 25 | private int argcount; 26 | private String cookie; 27 | private String casesetName; 28 | private String sheetName; 29 | 30 | /** 31 | * 构造函数 32 | */ 33 | public FormatCase() { 34 | this.arrCase = new ArrayList>(); 35 | this.testCase = new ArrayList(); 36 | this.url = ""; 37 | this.httpMethod = ""; 38 | this.argcount = 0; 39 | this.cookie = ""; 40 | this.casesetName = ""; 41 | this.sheetName = ""; 42 | } 43 | 44 | /** 45 | * 从数据文件中读取测试用例 46 | * @param casePath 47 | * @param sheetName 48 | */ 49 | public void FormatCaseFromObj(String casePath,String sheetName) { 50 | this.FormatCaseFromExcel(casePath,sheetName); 51 | this.casesetName = casePath.substring(casePath.lastIndexOf("/") + 1,casePath.length() - (FileUtil.getExtensionName(casePath).length()+1)); 52 | this.sheetName=sheetName; 53 | } 54 | 55 | /** 56 | * 57 | * @param pathName 58 | * @param sheetIndex 59 | */ 60 | private void getTestCaseFromExcel(String pathName,String sheetName) { 61 | // 记录读取到的用例数据信息 62 | ReadCaseFromExcel readCase = new ReadCaseFromExcel(pathName,sheetName); 63 | // 读取表表信息 64 | url = readCase.readUrl(); 65 | httpMethod = readCase.readHttpMethod(); 66 | argcount = readCase.readArgCount();// 参与sign计算的参数个数 67 | this.cookie = readCase.readCookie(); 68 | String[] argKey = readCase.readArgKey();// 获取参数key 69 | // 设置测试集名称,Excel中未存储,从判断传入的path为excel时设置 70 | // casesetName=readcase(); 71 | // 获取用例数据 72 | for (int j = IftConf.paramStartRow; j < readCase.getRowNum(); j++) { 73 | IftTestCase tempcase = new IftTestCase(); 74 | tempcase.setArgCount(getArgcount()); 75 | tempcase.setHttpMethod(getHttpMethod()); 76 | tempcase.setUrl(getUrl()); 77 | tempcase.setCookie(this.cookie); 78 | // 读取【j+1】行的数据 79 | String[] argValue = readCase.readArgValue(j); 80 | // System.out.print("行:"+j+" 参数个数"+argValue.length+argValue[1]+"\n"); 81 | if (!argValue[IftConf.isRunCol].equals("Y")) { 82 | continue; 83 | } else { 84 | // 把数据和标题一一对应存入LinkedHashMap有序键值对中 85 | LinkedHashMap mycase = new LinkedHashMap(); 86 | for (int i = 0; i < argKey.length; i++) { 87 | // 判断此条记录是否有cookie参数,如果有且不为空替换全局cookie 88 | if (null != argValue[i] && argKey[i].equals("cookie") && argValue[i].length() > 0) { 89 | String dependCookie = (String) (IftConf.DependPara).get("cookie"); //重新赋值value 90 | tempcase.setCookie(StringUtil.paramReplace(argValue[i], dependCookie)); //cookie参数依赖(将之前接口获取的cookie值进行替换) 91 | } 92 | mycase.put(argKey[i], argValue[i]); 93 | } 94 | arrCase.add(mycase); 95 | tempcase.setCaseMap(mycase); 96 | tempcase.setCaseId(mycase.get("CaseID")); 97 | tempcase.setTestPoint(mycase.get("TestPoint")); 98 | } 99 | this.testCase.add(tempcase); 100 | } 101 | } 102 | 103 | /** 104 | * 功能:格式化Excel格式的测试用例 105 | * 106 | * @param casefilepath 读取Sheet1表格 107 | */ 108 | public void FormatCaseFromExcel(String casefilepath) { 109 | // 记录读取到的用例数据信息 110 | getTestCaseFromExcel(casefilepath, "Sheet1"); 111 | 112 | } 113 | 114 | /** 115 | * 功能:格式化Excel格式的测试用例 116 | * 117 | * @param casefilepath 118 | * @param casesheetname 如果为空,默认读取Sheet1 119 | */ 120 | public void FormatCaseFromExcel(String casefilepath, String casesheetname) { 121 | if (null==casesheetname | casesheetname.length()<1) { 122 | casesheetname="Sheet1"; 123 | } 124 | getTestCaseFromExcel(casefilepath, casesheetname); 125 | } 126 | 127 | /** 128 | * 功能:格式化Xml格式的测试用例 129 | * 130 | * @param casefilepath 131 | */ 132 | public void FormatCaseFromXml(String casefilepath) { 133 | 134 | } 135 | 136 | /** 137 | * @return the arrCase 138 | */ 139 | public List> getArrCase() { 140 | return arrCase; 141 | } 142 | 143 | /** 144 | * @return the testCase 145 | */ 146 | public List getTestCase() { 147 | return testCase; 148 | } 149 | 150 | /** 151 | * @return the url 152 | */ 153 | public String getUrl() { 154 | return url; 155 | } 156 | 157 | /** 158 | * @return the httpMethod 159 | */ 160 | public String getHttpMethod() { 161 | return httpMethod; 162 | } 163 | 164 | /** 165 | * @return the argcount 166 | */ 167 | public int getArgcount() { 168 | return argcount; 169 | } 170 | 171 | /** 172 | * @return the cookie 173 | */ 174 | public String getCookie() { 175 | return cookie; 176 | } 177 | 178 | /** 179 | * @return the casesetName 180 | */ 181 | public String getCasesetName() { 182 | return casesetName; 183 | } 184 | 185 | public String getSheetName() { 186 | return sheetName; 187 | } 188 | 189 | 190 | } 191 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/testcase/format/ReadCaseFromExcel.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.testcase.format; 2 | import java.util.List; 3 | import com.github.qihootest.leo.ift.IftConf; 4 | import com.github.qihootest.leo.toolkit.util.ExcelUtil; 5 | 6 | /** 7 | * 功能说明:从excel表中读取用例数据文件 8 | * @author lianghui (lianghui@360.cn) 9 | */ 10 | public class ReadCaseFromExcel { 11 | private ExcelUtil excel; 12 | private int rowNum; 13 | private String url; 14 | private String httpMethod; 15 | private String cookie; 16 | private int argcount; 17 | private String[] argKey; 18 | private String[] argValue; 19 | 20 | /** 21 | * 构造函数 22 | * @param pathName 23 | * @param sheetName 24 | */ 25 | public ReadCaseFromExcel(String pathName,String sheetName){ 26 | excel=new ExcelUtil(pathName, sheetName); 27 | } 28 | /** 29 | * 构造函数 30 | * @param pathName 31 | */ 32 | public ReadCaseFromExcel(String pathName){ 33 | excel=new ExcelUtil(pathName, 0); 34 | } 35 | 36 | /** 37 | * 功能说明:从excel表格B1中读取url并返回 38 | * @return String 39 | */ 40 | public String readUrl(){ 41 | this.url=excel.getCellValue(IftConf.urlRow, IftConf.urlCol).trim(); 42 | return this.url; 43 | } 44 | 45 | /** 46 | * 功能说明:从excel表格B2中读取readHttpMethod并返回 47 | * @return String 48 | */ 49 | public String readHttpMethod(){ 50 | this.httpMethod = excel.getCellValue(IftConf.methodRow, IftConf.methodCol).trim(); 51 | return this.httpMethod; 52 | } 53 | 54 | /** 55 | * 功能说明:从excel表格B3中读取Cookie并返回 56 | * 57 | * @return String 58 | * 59 | */ 60 | public String readCookie(){ 61 | this.cookie = excel.getCellValue(IftConf.cookieRow, IftConf.cookieCol).trim(); 62 | return this.cookie; 63 | } 64 | 65 | /** 66 | * 功能说明:从excel表格B4中读取argcount并返回 67 | * 68 | * @return int 69 | * 70 | */ 71 | public int readArgCount(){ 72 | this.argcount = Integer.parseInt(excel.getCellValue(IftConf.argCountRow, IftConf.argCountCol).trim()); 73 | return this.argcount; 74 | } 75 | 76 | /** 77 | * 功能说明:从excel表格第5行中读取参数标题并返回 78 | * 79 | * @return String[] 80 | * 81 | */ 82 | public String[] readArgKey(){ 83 | this.argKey=new String[excel.getColNum()]; 84 | Listkeylist=excel.getRowList(IftConf.typeRow); 85 | for (int i = 0; i < keylist.size(); i++) { 86 | argKey[i]=keylist.get(i); 87 | } 88 | return this.argKey; 89 | } 90 | 91 | /** 92 | * 功能说明:从excel表格指定行开始读取所有值并返回 93 | * 94 | * @param argKeynum 95 | * @return String[] 96 | * 97 | */ 98 | public String[] readArgValue(int argKeynum){ 99 | this.argValue=new String[excel.getColNum()]; 100 | Listvaluelist=excel.getRowList(argKeynum); 101 | for (int i = 0; i < valuelist.size(); i++) { 102 | argValue[i]=valuelist.get(i); 103 | } 104 | return this.argValue; 105 | } 106 | 107 | /** 108 | * Excel的行数 109 | * @return int 110 | */ 111 | public int getRowNum() { 112 | this.rowNum=excel.getRowNum(); 113 | return this.rowNum; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/util/CommonSign.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.util; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map.Entry; 5 | import java.util.TreeMap; 6 | import com.github.qihootest.leo.toolkit.util.CommUtils; 7 | import com.github.qihootest.leo.toolkit.util.LogUtil; 8 | 9 | /** 10 | * 各种签名算法 11 | * @author @bwgang (bwgang@163.com)
12 | */ 13 | public class CommonSign { 14 | 15 | private static LogUtil log = LogUtil.getLogger(CommonSign.class);// 日志记录 16 | 17 | /** 18 | * 说明:签名算法1 key=value&key=value&.....key=valuesecret_key 最后连接私钥时不带&符号 19 | * 计算MD5时,中文按照UTF-8编码计算 20 | * @param signpara 参与签名计算的键值对 21 | * @param secret_key 签名计算所需的密钥 22 | * @return String 23 | */ 24 | public static String signMethodOne(TreeMap signpara, 25 | String secret_key) { 26 | String expBaseSign = ""; 27 | String expSign = ""; 28 | 29 | Iterator ite = signpara.entrySet().iterator(); 30 | while (ite.hasNext()) { 31 | Entry entry = (Entry) ite.next(); 32 | expBaseSign = expBaseSign + entry.getKey() + "=" 33 | + entry.getValue().toString() + "&"; 34 | } 35 | if (expBaseSign.length() < 1) { 36 | expSign = expBaseSign + secret_key; 37 | } else { 38 | expSign = expBaseSign.substring(0, expBaseSign.length() - 1) 39 | + secret_key; 40 | } 41 | return CommUtils.getMD5(expSign,"UTF-8"); 42 | } 43 | 44 | /** 45 | * 说明:签名算法2 key=value&key=value&.....key=valuesecret_key 最后连接私钥时不带&符号 46 | * 计算MD5时,中文按照GBK编码计算 47 | * @param signpara 参与签名计算的键值对 48 | * @param secret_key 签名计算所需的密钥 49 | * @return String 50 | */ 51 | public static String signMethodTwo(TreeMap signpara,String secret_key) { 52 | String expBaseSign = ""; 53 | String expSign = ""; 54 | 55 | Iterator ite = signpara.entrySet().iterator(); 56 | while (ite.hasNext()) { 57 | Entry entry = (Entry) ite.next(); 58 | expBaseSign = expBaseSign + entry.getKey() + "=" 59 | + entry.getValue().toString() + "&"; 60 | } 61 | if (expBaseSign.length() < 1) { 62 | expSign = expBaseSign + secret_key; 63 | } else { 64 | expSign = expBaseSign.substring(0, expBaseSign.length() - 1) 65 | + secret_key; 66 | } 67 | log.info("签名计算串:" + expSign); 68 | return CommUtils.getMD5Gbk(expSign); 69 | } 70 | 71 | /** 72 | * 说明:签名算法3 value为空时 不参与签名计算 key=value&key=value&.....key=valuesecret_key 73 | * 最后连接私钥时不带&符号 计算MD5时,中文按照UTF-8编码计算 74 | * 75 | * @param signpara 参与签名计算的键值对 76 | * @param secret_key 签名计算所需的密钥 77 | * @return String 78 | */ 79 | public static String signMethodThird(TreeMap signpara, 80 | String secret_key) { 81 | String expBaseSign = ""; 82 | String expSign = ""; 83 | 84 | Iterator ite = signpara.entrySet().iterator(); 85 | while (ite.hasNext()) { 86 | Entry entry = (Entry) ite.next(); 87 | if (entry.getValue().toString().length() > 0) { 88 | expBaseSign = expBaseSign + entry.getKey() + "=" + entry.getValue().toString() + "&"; 89 | } 90 | } 91 | if (expBaseSign.length() < 1) { 92 | expSign = expBaseSign + secret_key; 93 | } else { 94 | expSign = expBaseSign.substring(0, expBaseSign.length() - 1) + secret_key; 95 | } 96 | return CommUtils.getMD5(expSign,"UTF-8"); 97 | } 98 | 99 | /** 100 | * 说明:签名算法4 value为空时 不参与签名计算 key=value&key=value&.....key=valuesecret_key 101 | * 最后连接私钥时带&符号 计算MD5时,中文按照UTF-8编码计算 102 | * 103 | * @param signpara 参与签名计算的键值对 104 | * @param secret_key 签名计算所需的密钥 105 | * @return String 106 | */ 107 | public static String signMethodFour(TreeMap signpara, 108 | String secret_key) { 109 | String expBaseSign = ""; 110 | String expSign = ""; 111 | 112 | Iterator ite = signpara.entrySet().iterator(); 113 | while (ite.hasNext()) { 114 | Entry entry = (Entry) ite.next(); 115 | if (entry.getValue().toString().length() > 0) { 116 | String value=entry.getValue().toString(); 117 | // if (MyString.isChinese(value)) { 118 | // value=CommUtils.urlEncode(value, IEnCoding.UTF8); 119 | // } 120 | expBaseSign = expBaseSign + entry.getKey() + "=" +value + "&"; 121 | } 122 | } 123 | if (expBaseSign.length() < 1) { 124 | expSign = expBaseSign + secret_key; 125 | } else { 126 | expSign = expBaseSign.substring(0, expBaseSign.length() - 1) + secret_key; 127 | } 128 | // log.info("参与签名的串:"+expSign); 129 | // log.info("计算后的结果为:"+CommUtils.getMD5(expSign,IEnCoding.UTF8)); 130 | return CommUtils.getMD5(expSign,"UTF-8"); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/ift/util/ExportReportExcel.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | 8 | import org.apache.poi.hssf.util.HSSFColor; 9 | import org.apache.poi.ss.usermodel.CellStyle; 10 | import org.apache.poi.ss.usermodel.IndexedColors; 11 | import org.apache.poi.xssf.usermodel.XSSFCell; 12 | import org.apache.poi.xssf.usermodel.XSSFFont; 13 | import org.apache.poi.xssf.usermodel.XSSFRichTextString; 14 | import org.apache.poi.xssf.usermodel.XSSFRow; 15 | import org.apache.poi.xssf.usermodel.XSSFSheet; 16 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 17 | 18 | 19 | import com.github.qihootest.leo.toolkit.util.CommUtils; 20 | import com.github.qihootest.leo.toolkit.util.ExcelUtil; 21 | import com.github.qihootest.leo.toolkit.util.FileUtil; 22 | 23 | /** 24 | * 说明:输出Excel格式的测试报告 25 | * @author @bwgang (bwgang@163.com)
26 | */ 27 | public class ExportReportExcel { 28 | 29 | // private static LogUtil log = LogUtil.getLogger(ExportReportExcel.class); 30 | /** 31 | * 根据测试执行过程中的记录,生成Excel的测试报告 32 | * @param excelreportpath 33 | * @param filename 34 | * @param arrres 35 | * @return boolean 36 | */ 37 | public boolean CreatReportExcel(String excelreportpath,String filename,ArrayList> arrres) { 38 | boolean flag=false; 39 | flag=CreatReportExcel(excelreportpath,filename,null,arrres); 40 | return flag; 41 | } 42 | 43 | /** 44 | * 根据测试执行过程中的记录,生成Excel的测试报告 45 | * @param excelreportpath 46 | * @param filename 47 | * @param sheetname 48 | * @param arrres 49 | * @return boolean 50 | */ 51 | public boolean CreatReportExcel(String excelreportpath,String filename,String sheetname,List> arrres) { 52 | boolean flag=false; 53 | List title =null; 54 | List content=null; 55 | 56 | if (filename.indexOf("/")!=-1 || filename.indexOf("xls")!=-1 || filename.length()<1) { 57 | filename="未命名"; 58 | } 59 | 60 | title=getTitle(); 61 | content=getContentFromMap(arrres); 62 | writeExcel(title, content, sheetname,filename,excelreportpath); 63 | 64 | return flag; 65 | } 66 | 67 | //excel测试报告内容定义 68 | 69 | /** 70 | * 说明:指定输出报告的标题项,按顺序存储到List中 71 | * 72 | * @return List title 73 | */ 74 | private List getTitle() { 75 | List title=new LinkedList() ; 76 | 77 | title.add("CaseID"); 78 | title.add("TestPoint"); 79 | title.add("ExpRes"); 80 | title.add("ActRes"); 81 | title.add("ExcResult"); 82 | title.add("ResponseRes"); 83 | title.add("Httpurl"); 84 | 85 | return title; 86 | } 87 | 88 | /** 89 | * 说明:解析出内容,按顺序存储到List中,每行为一字符数组 90 | * @param arrres 91 | * @return List 92 | */ 93 | private List getContentFromMap(List> arrres) { 94 | List content=new LinkedList(); 95 | 96 | List title=getTitle(); 97 | 98 | 99 | for (int i = 0; i < arrres.size(); i++) { 100 | String[] str = new String[title.size()]; 101 | for (int j = 0; j < title.size(); j++) { 102 | str[j]=arrres.get(i).get(title.get(j)); 103 | } 104 | content.add(str); 105 | } 106 | 107 | return content; 108 | } 109 | 110 | //Excel报告格式定义 111 | private void writeExcel(List title,List datas,String sheetName,String excelName,String excelreportpath){ 112 | // log.error("title:"); 113 | // for (int i = 0; i < title.size(); i++) { 114 | // log.error(title.get(i)); 115 | // } 116 | // log.error("datas:"); 117 | // for (int i = 0; i < datas.size(); i++) { 118 | // log.error("data--"+i); 119 | // for (String str : datas.get(i)) { 120 | // log.error(str); 121 | // } 122 | // 123 | // } 124 | // log.error("sheetname--"+sheetName); 125 | // log.error("excelName--"+excelName); 126 | // log.error("excelreportpath--"+excelreportpath); 127 | ExcelUtil excel = new ExcelUtil(); 128 | String pathName=excelreportpath+"/"+excelName+".xlsx"; 129 | 130 | if (!FileUtil.isExist(pathName)) {//不存在时,新建空白工作簿 131 | excel.createBlankExcel2007(pathName); 132 | } 133 | 134 | //读取Excel文件 135 | excel.setPathName(pathName); 136 | XSSFWorkbook wb=(XSSFWorkbook) excel.getWb(); 137 | updateWbFromContent(wb,title,datas,sheetName);//测试结果写入工作簿 138 | excel.writeExcel2007(wb, pathName);//写入文件 139 | } 140 | 141 | private void updateWbFromContent(XSSFWorkbook wb,List title, List datas, 142 | String sheetName) { 143 | 144 | XSSFSheet sheet; 145 | if (null==sheetName | sheetName.length()<1) {//未指定sheet名称时,自动命名创建 146 | sheet=wb.createSheet(); 147 | }else{ 148 | if (null!=wb.getSheet(sheetName)) sheetName=sheetName+CommUtils.getRandomStr(5);//已存在同名sheet,添加随机字符串 149 | sheet=wb.createSheet(sheetName);//使用指定的sheetName 150 | } 151 | 152 | //设置列宽 153 | sheet.setColumnWidth(0, 15*255); 154 | sheet.setColumnWidth(1, 25*255); 155 | sheet.setColumnWidth(2, 40*255); 156 | sheet.setColumnWidth(3, 40*255); 157 | sheet.setColumnWidth(4, 10*255); 158 | sheet.setColumnWidth(5, 50*255); 159 | sheet.setColumnWidth(6, 15*255); 160 | sheet.setColumnWidth(7, 20*255); 161 | sheet.setColumnWidth(8, 10*255); 162 | //创建第一行 163 | XSSFRow row=sheet.createRow(0); 164 | //表头样式 165 | XSSFFont fonttitle=wb.createFont(); 166 | fonttitle.setItalic(true); 167 | fonttitle.setFontName("微软雅黑"); 168 | fonttitle.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);//粗体 169 | 170 | CellStyle styletitle = wb.createCellStyle(); 171 | styletitle.setFillForegroundColor(IndexedColors.BRIGHT_GREEN.getIndex()); 172 | styletitle.setFillPattern(CellStyle.SOLID_FOREGROUND); 173 | styletitle.setFont(fonttitle); 174 | styletitle.setBorderLeft(CellStyle.BORDER_THIN); 175 | styletitle.setBorderRight(CellStyle.BORDER_THIN); 176 | styletitle.setBorderTop(CellStyle.BORDER_THIN); 177 | styletitle.setBorderBottom(CellStyle.BORDER_THIN); 178 | 179 | //正文样式 180 | // 181 | XSSFFont fontRed=wb.createFont(); 182 | fontRed.setColor(HSSFColor.GREEN.index); 183 | fontRed.setColor(IndexedColors.RED.getIndex()); 184 | fontRed.setFontName("微软雅黑"); 185 | fontRed.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);//粗体 186 | fontRed.setFontHeightInPoints((short) 11); 187 | CellStyle styleRed = wb.createCellStyle(); 188 | styleRed.setFont(fontRed); 189 | styleRed.setBorderLeft(CellStyle.BORDER_THIN); 190 | styleRed.setBorderRight(CellStyle.BORDER_THIN); 191 | styleRed.setBorderTop(CellStyle.BORDER_THIN); 192 | styleRed.setBorderBottom(CellStyle.BORDER_THIN); 193 | 194 | XSSFFont fontGreen=wb.createFont(); 195 | fontGreen.setColor(IndexedColors.GREEN.getIndex()); 196 | fontGreen.setFontName("微软雅黑"); 197 | fontGreen.setBoldweight(XSSFFont.BOLDWEIGHT_BOLD);//粗体 198 | fontGreen.setFontHeightInPoints((short) 11); 199 | CellStyle styleGreen = wb.createCellStyle(); 200 | styleGreen.setFont(fontGreen); 201 | styleGreen.setBorderLeft(CellStyle.BORDER_THIN); 202 | styleGreen.setBorderRight(CellStyle.BORDER_THIN); 203 | styleGreen.setBorderTop(CellStyle.BORDER_THIN); 204 | styleGreen.setBorderBottom(CellStyle.BORDER_THIN); 205 | 206 | XSSFFont fontBlack=wb.createFont(); 207 | fontBlack.setColor(IndexedColors.BLACK.getIndex()); 208 | fontBlack.setFontName("Arial"); 209 | fontBlack.setFontHeightInPoints((short) 9); 210 | CellStyle styleBlack = wb.createCellStyle(); 211 | styleBlack.setFont(fontBlack); 212 | styleBlack.setBorderLeft(CellStyle.BORDER_THIN); 213 | styleBlack.setBorderRight(CellStyle.BORDER_THIN); 214 | styleBlack.setBorderTop(CellStyle.BORDER_THIN); 215 | styleBlack.setBorderBottom(CellStyle.BORDER_THIN); 216 | //写入标题 217 | for (int i = 0; i < title.size(); i++) { 218 | XSSFCell cell=row.createCell(i, XSSFCell.CELL_TYPE_STRING); 219 | cell.setCellValue(title.get(i)); 220 | cell.setCellStyle(styletitle); 221 | } 222 | 223 | // 写入内容行 224 | for (int i = 0; i < datas.size(); i++) { 225 | String[] rowvalue = datas.get(i); 226 | XSSFRow nextrow = sheet.createRow(sheet.getLastRowNum() + 1);// 创建一行 227 | for (int j = 0; j < rowvalue.length; j++) { 228 | XSSFCell cell = nextrow 229 | .createCell(j, XSSFCell.CELL_TYPE_STRING); 230 | cell.setCellValue(new XSSFRichTextString(rowvalue[j])); 231 | if (rowvalue[j].equals("Fail")) { 232 | cell.setCellStyle(styleRed); 233 | } else if (rowvalue[j].equals("Pass")) { 234 | cell.setCellStyle(styleGreen); 235 | } else { 236 | cell.setCellStyle(styleBlack); 237 | } 238 | 239 | } 240 | } 241 | 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/QtafException.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit; 2 | 3 | /** 4 | * 自定义异常信息 5 | * @author @bwgang (bwgang@163.com)
6 | * 7 | */ 8 | public class QtafException extends RuntimeException { 9 | 10 | private static final long serialVersionUID = 1L; 11 | 12 | public QtafException() { 13 | } 14 | 15 | public QtafException(String message) { 16 | super(message); 17 | } 18 | 19 | public QtafException(String message, Throwable cause) { 20 | super(message, cause); 21 | } 22 | 23 | public QtafException(Throwable cause) { 24 | super(cause); 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/TkConf.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | 9 | 10 | /** 11 | * 配置文件 12 | * @author @bwgang (bwgang@163.com)
13 | */ 14 | public class TkConf { 15 | 16 | /** 17 | * 根目录 18 | */ 19 | public static String RootPath = getRootPath(); 20 | /** 21 | * log4j配置文件目录 22 | */ 23 | public static String Log4jConf = RootPath+"leo/toolkit/log4j.properties"; 24 | 25 | /** 26 | * 如果配置文件不存在,写入 27 | * @return boolean 已存在或写入失败返回false 重新写入成功返回true 28 | */ 29 | public static boolean writeConf(){ 30 | if (!new File(Log4jConf).exists()) { 31 | return copyFile(TkConf.class.getResourceAsStream("/log4j.properties"),new File(Log4jConf)); 32 | } 33 | return false; 34 | } 35 | 36 | /** 37 | * 获取项目根目录,如果是在Tomcat中运行,则返回部署根目录 38 | * @return String 39 | */ 40 | private static String getRootPath() { 41 | String path=""; 42 | if (TkConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")!=-1) { 43 | path=TkConf.class.getClassLoader().getResource("").toString().substring(6, TkConf.class.getClassLoader().getResource("").toString().indexOf("WEB-INF")); 44 | path=path+"/"; 45 | }else { 46 | String temp=System.getProperty("user.dir"); 47 | temp=temp.replace("\\","/"); 48 | path=temp+"/"; 49 | } 50 | return path; 51 | } 52 | 53 | private static boolean copyFile(InputStream from, File to) { 54 | try { 55 | if (! to.getParentFile().exists()) { 56 | to.getParentFile().mkdirs(); 57 | } 58 | OutputStream os = new FileOutputStream(to); 59 | byte[] buffer = new byte[65536]; 60 | int count = from.read(buffer); 61 | while (count > 0) { 62 | os.write(buffer, 0, count); 63 | count = from.read(buffer); 64 | } 65 | os.close(); 66 | return true; 67 | } catch (IOException e) { 68 | // e.printStackTrace(); 69 | return false; 70 | } 71 | } 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/dbunit/DbUnitUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.dbunit; 2 | 3 | 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.sql.Connection; 7 | import java.sql.SQLException; 8 | 9 | import org.dbunit.DatabaseUnitException; 10 | import org.dbunit.database.DatabaseConfig; 11 | import org.dbunit.database.DatabaseConnection; 12 | import org.dbunit.database.IDatabaseConnection; 13 | import org.dbunit.database.QueryDataSet; 14 | import org.dbunit.dataset.IDataSet; 15 | import org.dbunit.dataset.ITable; 16 | import org.dbunit.dataset.xml.FlatXmlDataSet; 17 | import org.dbunit.ext.mysql.MySqlDataTypeFactory; 18 | import org.dbunit.ext.mysql.MySqlMetadataHandler; 19 | 20 | import com.github.qihootest.leo.toolkit.dbunit.data.excel.XlsDataSet; 21 | import com.github.qihootest.leo.toolkit.mysql.ConnMysql; 22 | import com.github.qihootest.leo.toolkit.util.LogUtil; 23 | 24 | /** 25 | * 从数据库中导出到excel、xml文件、创建dbunit的DatabaseConnection、IDataSet 26 | * @author @bwgang (bwgang@163.com)
2013-02-07 27 | * 28 | */ 29 | public class DbUnitUtil { 30 | 31 | private static final LogUtil log = LogUtil.getLogger(DbUnitUtil.class); 32 | 33 | //针对Mysql数据库专用的 34 | 35 | /** 36 | * 从数据库中读取数据写入到文件中,支持excel和xml格式,以文件后缀名区分 37 | * @param destFilePath 写入文件的路径 38 | * @param mysql 连接MySql数据库的实例 39 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 40 | */ 41 | public static void writeToFileFromMysql(String destFilePath,ConnMysql mysql,String querySqlsSplitBySemicolon){ 42 | writeToFileFromDataBase(destFilePath,mysql.getConnection(),querySqlsSplitBySemicolon); 43 | } 44 | 45 | /** 46 | * 根据connection和查询sql语句,返回ITable 47 | * @param mysql mysql数据库连接实例 48 | * @param resultName 查询结果集对应的名称 49 | * @param querySql 单个sql查询语句 50 | * @return ITable 51 | */ 52 | public static ITable getTableFromMysql(ConnMysql mysql,String resultName,String querySql){ 53 | return getTableFromDataBase(mysql.getConnection(), resultName, querySql); 54 | } 55 | 56 | /** 57 | * 根据connection和查询sql语句,返回IDataSet 58 | * @param mysql mysql数据库连接实例 59 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 60 | * @return IDataSet 61 | */ 62 | public static IDataSet getDataSetFromMysql(ConnMysql mysql,String querySqlsSplitBySemicolon){ 63 | return getDataSetFromDataBase(mysql.getConnection(), querySqlsSplitBySemicolon); 64 | } 65 | 66 | /** 67 | * 从Mysql实例转换为DatabaseConnection 68 | * @param mysql 69 | * @return DatabaseConnection 70 | */ 71 | public static DatabaseConnection getDatabaseConnectionFromMysql(ConnMysql mysql) { 72 | return getDatabaseConnection(mysql.getConnection()); 73 | } 74 | 75 | 76 | //根据jdbc的connection连接,参照上述Mysql的,其它数据库类型Oracle、MSSql等可复用 77 | 78 | /** 79 | * 从数据库中读取数据写入到文件中,支持excel和xml格式,以文件后缀名区分 80 | * @param databaseConnection 使用的IDatabaseConnection数据连接 81 | * @param destFilePath 写入文件的路径 82 | */ 83 | public static void writeToFileFromDataBase(IDatabaseConnection databaseConnection,String destFilePath){ 84 | IDataSet dataSet=null; 85 | 86 | try { 87 | dataSet=databaseConnection.createDataSet(); 88 | } catch (Exception e) { 89 | log.error("未获取到测试集"); 90 | log.error(e.getMessage()); 91 | return; 92 | } 93 | writeToFileFromDataSet(dataSet,destFilePath); 94 | } 95 | 96 | /** 97 | * 从数据库中读取数据写入到文件中,支持excel和xml格式,以文件后缀名区分 98 | * @param destFilePath 写入文件的路径 99 | * @param databaseConnection 使用的IDatabaseConnection数据连接 100 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 101 | */ 102 | public static void writeToFileFromDataBase(String destFilePath,IDatabaseConnection databaseConnection,String querySqlsSplitBySemicolon){ 103 | writeToFileFromDataSet(getDataSetFromDataBase(databaseConnection, querySqlsSplitBySemicolon),destFilePath); 104 | } 105 | 106 | /** 107 | * 从数据库中读取数据写入到文件中,支持excel和xml格式,以文件后缀名区分 108 | * @param destFilePath 写入文件的路径 109 | * @param connection 使用的数据连接 110 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 111 | */ 112 | public static void writeToFileFromDataBase(String destFilePath,Connection connection,String querySqlsSplitBySemicolon){ 113 | writeToFileFromDataSet(getDataSetFromDataBase(connection, querySqlsSplitBySemicolon),destFilePath); 114 | } 115 | 116 | /** 117 | * 把数据集写入到文件中 118 | * @param dataSet 119 | * @param destFilePath 120 | */ 121 | public static void writeToFileFromDataSet(IDataSet dataSet,String destFilePath) { 122 | File destFile = new File(destFilePath); 123 | try { 124 | String destFileName = destFile.getName(); 125 | //转换为excel格式 126 | if(destFileName.endsWith(".xls")){ 127 | XlsDataSet.write(dataSet, new FileOutputStream(destFile)); 128 | }else if(destFileName.endsWith(".xml")){ 129 | FlatXmlDataSet.write(dataSet, new FileOutputStream(destFile)); 130 | }else{ 131 | log.error("文件格式不是xls或者xml,不支持"); 132 | return; 133 | } 134 | log.info("写入数据到文件 : "+destFile.getAbsolutePath()); 135 | } catch (Exception e) { 136 | log.error("写入数据到文件失败"); 137 | log.error(e.getMessage()); 138 | } 139 | } 140 | 141 | /** 142 | * 根据connection和查询sql语句,返回IDataSet 143 | * @param connection 使用的数据连接 144 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 145 | * @return IDataSet 146 | */ 147 | public static IDataSet getDataSetFromDataBase(Connection connection,String querySqlsSplitBySemicolon){ 148 | return getDataSetFromDataBase(getDatabaseConnection(connection), querySqlsSplitBySemicolon); 149 | } 150 | 151 | /** 152 | * 根据databaseConnection和多个查询sql语句,返回IDataSet 153 | * @param databaseConnection 使用的IDatabaseConnection类型数据连接 154 | * @param querySqlsSplitBySemicolon 查询的sql语句,支持多个,使用;分开 155 | * @return queryDataSet 156 | */ 157 | public static IDataSet getDataSetFromDataBase(IDatabaseConnection databaseConnection,String querySqlsSplitBySemicolon){ 158 | //分割多个sql语句 159 | String[] querySqls = querySqlsSplitBySemicolon.split(";"); 160 | QueryDataSet queryDataSet=null; 161 | try { 162 | queryDataSet = new QueryDataSet(databaseConnection); 163 | //处理多个语句情况 164 | for (int i = 0; i < querySqls.length; i++) { 165 | queryDataSet.addTable(getTableNameFromQuerySql(querySqls[i]), querySqls[i]); 166 | } 167 | } catch (Exception e) { 168 | log.error("查询数据失败!"); 169 | log.error(e.getMessage()); 170 | } 171 | return queryDataSet; 172 | } 173 | 174 | /** 175 | * 根据connection和查询sql语句,返回ITable 176 | * @param connection 177 | * @param resultName 指定查询结果集对应的表名 178 | * @param querySql 单个sql查询语句 179 | * @return ITable 180 | */ 181 | public static ITable getTableFromDataBase(Connection connection,String resultName,String querySql){ 182 | //分割多个sql语句 183 | ITable table=null; 184 | try { 185 | table=getDatabaseConnection(connection).createQueryTable(resultName, querySql); 186 | } catch (Exception e) { 187 | log.error("查询数据失败!"); 188 | log.error(e.getMessage()); 189 | } 190 | return table; 191 | } 192 | 193 | /** 194 | * 从connection转换为DatabaseConnection 195 | * @param connection 196 | * @return DatabaseConnection 197 | */ 198 | public static DatabaseConnection getDatabaseConnection(Connection connection) { 199 | DatabaseConnection databaseConnection = null; 200 | try { 201 | databaseConnection= new DatabaseConnection(connection); 202 | DatabaseConfig config = databaseConnection.getConfig(); 203 | //数据库为mysql 204 | if ("MySQL".equalsIgnoreCase(connection.getMetaData() 205 | .getDatabaseProductName())) { 206 | config.setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, 207 | new MySqlMetadataHandler()); 208 | config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, 209 | new MySqlDataTypeFactory()); 210 | } //else if ("Oracle".equalsIgnoreCase(connection.getMetaData() 211 | // .getDatabaseProductName())) { 212 | // config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, 213 | // new Oracle10DataTypeFactory()); 214 | // } 215 | } catch (DatabaseUnitException | SQLException e) { 216 | log.error("创建dbunit的数据库连接失败"); 217 | log.error(e.getMessage()); 218 | return null; 219 | } 220 | 221 | return databaseConnection; 222 | } 223 | 224 | 225 | 226 | //私有方法 227 | 228 | /** 229 | * 从sql语句中查找到表名,第一个from之后的表名 230 | * @param querySql 231 | * @return String 232 | */ 233 | 234 | private static String getTableNameFromQuerySql(String querySql){ 235 | String tableName = null; 236 | String[] array = querySql.split(" "); 237 | for (int i = 0; i < array.length; i++) { 238 | if("From".equalsIgnoreCase(array[i].trim())){ 239 | tableName = array[i+1].trim(); 240 | break; 241 | } 242 | } 243 | return tableName; 244 | 245 | } 246 | 247 | 248 | } 249 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/dbunit/data/excel/XlsDataSet.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.dbunit.data.excel; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.io.OutputStream; 8 | 9 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 10 | import org.dbunit.dataset.AbstractDataSet; 11 | import org.dbunit.dataset.DataSetException; 12 | import org.dbunit.dataset.DefaultTableIterator; 13 | import org.dbunit.dataset.IDataSet; 14 | import org.dbunit.dataset.ITable; 15 | import org.dbunit.dataset.ITableIterator; 16 | import org.dbunit.dataset.OrderedTableNameMap; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | /** 21 | * 重写dbunit的XlsDataSet 22 | * 23 | */ 24 | public class XlsDataSet extends AbstractDataSet { 25 | 26 | /** 27 | * Logger for this class 28 | */ 29 | private static final Logger logger = LoggerFactory.getLogger(XlsDataSet.class); 30 | 31 | private final OrderedTableNameMap _tables; 32 | 33 | /** 34 | * 从Excel文件中创建XlsDataSet 35 | */ 36 | public XlsDataSet(String file) throws IOException, DataSetException { 37 | this(new FileInputStream(file)); 38 | } 39 | 40 | /** 41 | * 从Excel文件中创建XlsDataSet 42 | */ 43 | public XlsDataSet(File file) throws IOException, DataSetException { 44 | this(new FileInputStream(file)); 45 | } 46 | 47 | 48 | /** 49 | * Creates a new XlsDataSet object that loads the specified Excel document. 50 | */ 51 | public XlsDataSet(InputStream in) throws IOException, DataSetException { 52 | _tables = super.createTableNameMap(); 53 | 54 | HSSFWorkbook workbook = new HSSFWorkbook(in); 55 | int sheetCount = workbook.getNumberOfSheets(); 56 | for (int i = 0; i < sheetCount; i++) { 57 | ITable table = new XlsTable(workbook, workbook.getSheetName(i), 58 | workbook.getSheetAt(i)); 59 | _tables.add(table.getTableMetaData().getTableName(), table); 60 | } 61 | } 62 | 63 | //暂不使用部分 64 | /** 65 | * 从Excel的工作簿中创建XlsDataSet. 66 | */ 67 | @Deprecated 68 | public XlsDataSet(HSSFWorkbook workbook) throws IOException, DataSetException { 69 | _tables = super.createTableNameMap(); 70 | 71 | int sheetCount = workbook.getNumberOfSheets(); 72 | for (int i = 0; i < sheetCount; i++) { 73 | ITable table = new XlsTable(workbook, workbook.getSheetName(i), 74 | workbook.getSheetAt(i)); 75 | _tables.add(table.getTableMetaData().getTableName(), table); 76 | } 77 | } 78 | 79 | /** 80 | * 把数据集写入到Excel文档 81 | */ 82 | public static void write(IDataSet dataSet, OutputStream out) 83 | throws IOException, DataSetException { 84 | logger.debug("write(dataSet={}, out={}) - start", dataSet, out); 85 | 86 | new XlsDataSetWriter().write(dataSet, out); 87 | } 88 | 89 | @SuppressWarnings("unchecked") 90 | @Override 91 | protected ITableIterator createIterator(boolean reversed) 92 | throws DataSetException { 93 | if (logger.isDebugEnabled()) 94 | logger.debug("createIterator(reversed={}) - start", String.valueOf(reversed)); 95 | 96 | ITable[] tables = (ITable[]) _tables.orderedValues().toArray(new ITable[0]); 97 | return new DefaultTableIterator(tables, reversed); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/dbunit/data/excel/XlsDataSetWriter.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.dbunit.data.excel; 2 | 3 | import java.io.IOException; 4 | import java.io.OutputStream; 5 | import java.math.BigDecimal; 6 | import java.util.Date; 7 | 8 | import org.apache.poi.hssf.usermodel.HSSFCell; 9 | import org.apache.poi.hssf.usermodel.HSSFCellStyle; 10 | import org.apache.poi.hssf.usermodel.HSSFDataFormat; 11 | import org.apache.poi.hssf.usermodel.HSSFRichTextString; 12 | import org.apache.poi.hssf.usermodel.HSSFRow; 13 | import org.apache.poi.hssf.usermodel.HSSFSheet; 14 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 15 | import org.dbunit.dataset.Column; 16 | import org.dbunit.dataset.DataSetException; 17 | import org.dbunit.dataset.IDataSet; 18 | import org.dbunit.dataset.ITable; 19 | import org.dbunit.dataset.ITableIterator; 20 | import org.dbunit.dataset.ITableMetaData; 21 | import org.dbunit.dataset.datatype.DataType; 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | /** 26 | * 说明:因为dbunit写xls文件使用的poi版本较早3.2版本,使用poi3.9时会写入xls文件失败 27 | * 拷贝其写excel的类到此,未做修改,写excel正常 28 | * 29 | * Writes an {@link IDataSet} to an XLS file or OutputStream. 30 | * 31 | * @author gommma (gommma AT users.sourceforge.net) 32 | * @author Last changed by: $Author: gommma $ 33 | * @version $Revision: 915 $ $Date: 2008-12-07 14:17:25 +0100 (Sun, 07 Dec 2008) $ 34 | * @since 2.4.0 35 | */ 36 | public class XlsDataSetWriter 37 | { 38 | public static final String ZEROS = "0000000000000000000000000000000000000000000000000000"; 39 | 40 | /** 41 | * A special format pattern used to create a custom {@link HSSFDataFormat} which 42 | * marks {@link Date} values that are stored via POI to an XLS file. 43 | * Note that it might produce problems if a normal numeric value uses this format 44 | * pattern incidentally. 45 | */ 46 | public static final String DATE_FORMAT_AS_NUMBER_DBUNIT = "####################"; 47 | /** 48 | * Logger for this class 49 | */ 50 | private static final Logger logger = LoggerFactory.getLogger(XlsDataSetWriter.class); 51 | 52 | private HSSFCellStyle dateCellStyle; 53 | 54 | /** 55 | * Write the specified dataset to the specified Excel document. 56 | */ 57 | public void write(IDataSet dataSet, OutputStream out) 58 | throws IOException, DataSetException 59 | { 60 | logger.debug("write(dataSet={}, out={}) - start", dataSet, out); 61 | 62 | HSSFWorkbook workbook = new HSSFWorkbook(); 63 | 64 | this.dateCellStyle = createDateCellStyle(workbook); 65 | 66 | int index = 0; 67 | ITableIterator iterator = dataSet.iterator(); 68 | while(iterator.next()) 69 | { 70 | // create the table i.e. sheet 71 | ITable table = iterator.getTable(); 72 | ITableMetaData metaData = table.getTableMetaData(); 73 | HSSFSheet sheet = workbook.createSheet(metaData.getTableName()); 74 | 75 | // write table metadata i.e. first row in sheet 76 | workbook.setSheetName(index, metaData.getTableName()); 77 | 78 | HSSFRow headerRow = sheet.createRow(0); 79 | Column[] columns = metaData.getColumns(); 80 | for (int j = 0; j < columns.length; j++) 81 | { 82 | Column column = columns[j]; 83 | HSSFCell cell = headerRow.createCell(j); 84 | cell.setCellValue(new HSSFRichTextString(column.getColumnName())); 85 | } 86 | 87 | // write table data 88 | for (int j = 0; j < table.getRowCount(); j++) 89 | { 90 | HSSFRow row = sheet.createRow(j + 1); 91 | for (int k = 0; k < columns.length; k++) 92 | { 93 | Column column = columns[k]; 94 | Object value = table.getValue(j, column.getColumnName()); 95 | if (value != null) 96 | { 97 | HSSFCell cell = row.createCell(k); 98 | if(value instanceof Date){ 99 | setDateCell(cell, (Date)value, workbook); 100 | } 101 | else if(value instanceof BigDecimal){ 102 | setNumericCell(cell, (BigDecimal)value, workbook); 103 | } 104 | else if(value instanceof Long){ 105 | setDateCell(cell, new Date( ((Long)value).longValue()), workbook); 106 | } 107 | else { 108 | cell.setCellValue(new HSSFRichTextString(DataType.asString(value))); 109 | } 110 | } 111 | } 112 | } 113 | 114 | index++; 115 | } 116 | 117 | // write xls document 118 | workbook.write(out); 119 | out.flush(); 120 | } 121 | 122 | protected static HSSFCellStyle createDateCellStyle(HSSFWorkbook workbook) { 123 | HSSFDataFormat format = workbook.createDataFormat(); 124 | short dateFormatCode = format.getFormat(DATE_FORMAT_AS_NUMBER_DBUNIT); 125 | HSSFCellStyle dateCellStyle = workbook.createCellStyle(); 126 | dateCellStyle.setDataFormat(dateFormatCode); 127 | return dateCellStyle; 128 | } 129 | 130 | protected void setDateCell(HSSFCell cell, Date value, HSSFWorkbook workbook) 131 | { 132 | // double excelDateValue = HSSFDateUtil.getExcelDate(value); 133 | // cell.setCellValue(excelDateValue); 134 | // cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC); 135 | 136 | long timeMillis = value.getTime(); 137 | cell.setCellValue( (double)timeMillis ); 138 | cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC); 139 | cell.setCellStyle(this.dateCellStyle); 140 | 141 | // System.out.println(HSSFDataFormat.getBuiltinFormats()); 142 | // TODO Find out correct cell styles for date objects 143 | // HSSFCellStyle cellStyleDate = workbook.createCellStyle(); 144 | // cellStyleDate.setDataFormat(HSSFDataFormat.getBuiltinFormat("m/d/yy h:mm")); 145 | // 146 | // HSSFCellStyle cellStyleDateTimeWithSeconds = workbook.createCellStyle(); 147 | // cellStyleDateTimeWithSeconds.setDataFormat(HSSFDataFormat.getBuiltinFormat("h:mm:ss")); 148 | // 149 | // HSSFDataFormat dataFormat = workbook.createDataFormat(); 150 | // HSSFCellStyle cellStyle = workbook.createCellStyle(); 151 | // cellStyle.setDataFormat(dataFormat.getFormat("dd/mm/yyyy hh:mm:ss")); 152 | // 153 | // SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); 154 | // SimpleDateFormat formatter2 = new SimpleDateFormat("dd/MM/yyyy"); 155 | // SimpleDateFormat formatter3 = new SimpleDateFormat("HH:mm:ss.SSS"); 156 | // 157 | // 158 | // Date dateValue = (Date)value; 159 | // Calendar cal = null; 160 | // 161 | // // If it is a date value that does not have seconds 162 | // if(dateValue.getTime() % 60000 == 0){ 163 | //// cellStyle = cellStyleDate; 164 | // cal=Calendar.getInstance(); 165 | // cal.setTimeInMillis(dateValue.getTime()); 166 | // 167 | // cell.setCellValue(cal); 168 | // cell.setCellStyle(cellStyle); 169 | //// cell.setCellValue(cal); 170 | // } 171 | // else { 172 | //// HSSFDataFormatter formatter = new HSSFDataFormatter(); 173 | // 174 | // // If we have seconds assume that it is only h:mm:ss without date 175 | // // TODO Clean implementation where user can control date formats would be nice 176 | //// double dateDouble = dateValue.getTime() % (24*60*60*1000); 177 | // cal = get1900Cal(dateValue); 178 | // 179 | // String formatted = formatter3.format(dateValue); 180 | // //TODO Format ... 181 | //// cellStyle = cellStyleDateTimeWithSeconds; 182 | // System.out.println("date formatted:"+formatted); 183 | //// HSSFRichTextString s = new HSSFRichTextString(formatted); 184 | //// cell.setCellValue(s); 185 | // cell.setCellType(HSSFCell.CELL_TYPE_NUMERIC); 186 | // cell.setCellValue((double)dateValue.getTime()); 187 | // cell.setCellStyle(cellStyleDateTimeWithSeconds); 188 | // } 189 | 190 | } 191 | 192 | protected void setNumericCell(HSSFCell cell, BigDecimal value, HSSFWorkbook workbook) 193 | { 194 | if(logger.isDebugEnabled()) 195 | logger.debug("setNumericCell(cell={}, value={}, workbook={}) - start", 196 | new Object[] {cell, value, workbook} ); 197 | 198 | cell.setCellValue( ((BigDecimal)value).doubleValue() ); 199 | 200 | HSSFDataFormat df = workbook.createDataFormat(); 201 | int scale = ((BigDecimal)value).scale(); 202 | short format; 203 | if(scale <= 0){ 204 | format = df.getFormat("####"); 205 | } 206 | else { 207 | String zeros = createZeros(((BigDecimal)value).scale()); 208 | format = df.getFormat("####." + zeros); 209 | } 210 | if(logger.isDebugEnabled()) 211 | logger.debug("Using format '{}' for value '{}'.", String.valueOf(format), value); 212 | 213 | HSSFCellStyle cellStyleNumber = workbook.createCellStyle(); 214 | cellStyleNumber.setDataFormat(format); 215 | cell.setCellStyle(cellStyleNumber); 216 | } 217 | 218 | 219 | // public static Date get1900(Date date) { 220 | // Calendar cal = Calendar.getInstance(); 221 | // cal.setTimeInMillis(date.getTime() % (24*60*60*1000)); 222 | // cal.set(1900, 0, 1); // 1.1.1900 223 | // return cal.getTime(); 224 | // } 225 | // 226 | // public static Calendar get1900Cal(Date date) { 227 | // Calendar cal = Calendar.getInstance(); 228 | // cal.clear(); 229 | //// long hoursInMillis = date.getTime() % (24*60*60*1000); 230 | //// long smallerThanDays = date.getTime() % (24*60*60*1000); 231 | //// cal.setTimeInMillis(date.getTime() % (24*60*60*1000)); 232 | // cal.set(Calendar.SECOND, (int) (date.getTime() % (24*60*60*1000)) / (1000) ); 233 | // cal.set(Calendar.MINUTE, (int) (date.getTime() % (24*60*60*1000)) / (1000*60) ); 234 | // cal.set(Calendar.HOUR, (int) (date.getTime() % (24*60*60*1000)) / (1000*60*60) ); 235 | //// cal.set(1900, 0, 1); // 1.1.1900 236 | // System.out.println(cal.isSet(Calendar.DATE)); 237 | // return cal; 238 | // } 239 | 240 | private static String createZeros(int count) { 241 | return ZEROS.substring(0, count); 242 | } 243 | 244 | } 245 | 246 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/dbunit/data/excel/XlsTableWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 Alibaba Group Holding Limited. 3 | * All rights reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | * 17 | */ 18 | package com.github.qihootest.leo.toolkit.dbunit.data.excel; 19 | 20 | 21 | import org.apache.commons.lang.StringUtils; 22 | import org.dbunit.dataset.AbstractTable; 23 | import org.dbunit.dataset.DataSetException; 24 | import org.dbunit.dataset.DefaultTableMetaData; 25 | import org.dbunit.dataset.ITable; 26 | import org.dbunit.dataset.ITableMetaData; 27 | 28 | import com.github.qihootest.leo.toolkit.QtafException; 29 | 30 | /** 31 | * 表名称后的数据源为获取数据表名称 32 | * 33 | */ 34 | public class XlsTableWrapper extends AbstractTable { 35 | private ITable delegate; 36 | private String tableName; 37 | 38 | public XlsTableWrapper(String tableName, ITable table) { 39 | this.delegate = table; 40 | this.tableName = tableName; 41 | } 42 | public int getRowCount() { 43 | return delegate.getRowCount(); 44 | } 45 | 46 | public ITableMetaData getTableMetaData() { 47 | ITableMetaData meta = delegate.getTableMetaData(); 48 | try { 49 | return new DefaultTableMetaData(tableName, meta.getColumns(), meta.getPrimaryKeys()); 50 | } catch (DataSetException e) { 51 | throw new QtafException("Don't get the meta info from " + meta, e); 52 | } 53 | } 54 | 55 | public Object getValue(int row, String column) throws DataSetException { 56 | Object delta = delegate.getValue(row, column); 57 | if (delta instanceof String) { 58 | if (StringUtils.isEmpty((String) delta)) { 59 | return null; 60 | } 61 | } 62 | return delta; 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/httpclient/ResponseInfo.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.httpclient; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * http请求发送信息及返回信息 7 | * @author @bwgang (bwgang@163.com)
8 | * 9 | */ 10 | public class ResponseInfo { 11 | 12 | private String httpUrl;//发起get或post请求的url信息,post的body信息转换为参数对字符串标识 13 | private String resBodyInfo;//http请求返回的body信息 14 | private Map resHeaderInfo;//http请求返回的Header键值对 15 | private String cookies; //http请求返回的cookie信息 16 | private String errMsgInfo;//记录错误信息 17 | public String getHttpUrl() { 18 | return httpUrl; 19 | } 20 | public void setHttpUrl(String httpUrl) { 21 | this.httpUrl = httpUrl; 22 | } 23 | public String getResBodyInfo() { 24 | return resBodyInfo; 25 | } 26 | public void setResBodyInfo(String resBodyInfo) { 27 | this.resBodyInfo = resBodyInfo; 28 | } 29 | public Map getResHeaderInfo() { 30 | return resHeaderInfo; 31 | } 32 | public void setResHeaderInfo(Map resHeaderInfo) { 33 | this.resHeaderInfo = resHeaderInfo; 34 | } 35 | public String getCookies() { 36 | return cookies; 37 | } 38 | public void setCookies(String cookies) { 39 | this.cookies = cookies; 40 | } 41 | public String getErrMsgInfo() { 42 | return errMsgInfo; 43 | } 44 | public void setErrMsgInfo(String errMsgInfo) { 45 | this.errMsgInfo = errMsgInfo; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/mysql/ConnMysql.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.mysql; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | import com.github.qihootest.leo.toolkit.util.LogUtil; 9 | 10 | import com.mysql.jdbc.Statement; 11 | 12 | /** 13 | * 说明:连接数据库配置信息 14 | * 15 | * @author lianghui (lianghui@360.cn) 2013-01-10 16 | * 17 | */ 18 | public class ConnMysql { 19 | 20 | private static Connection con = null; // 创建用于连接数据库的Connection对象 21 | private static LogUtil log = LogUtil.getLogger(ConnMysql.class);// 日志记录 22 | 23 | /** IP地址 */ 24 | public String ip = "127.0.0.1"; 25 | /** 端口号 */ 26 | public String port = "3306"; 27 | /** 数据库名 */ 28 | public String dataName = ""; 29 | /** 用户名 */ 30 | public String userName = "root"; 31 | /** 密码 */ 32 | public String passWord = ""; 33 | 34 | /** 35 | * 默认构造方法 36 | */ 37 | public ConnMysql() { 38 | 39 | } 40 | 41 | /** 42 | * 构造方法 43 | * 44 | * @param ip 45 | * @param port 46 | * @param dataName 47 | * @param userName 48 | * @param passWord 49 | */ 50 | public ConnMysql(String ip, String port, String dataName, String userName, 51 | String passWord) { 52 | this.ip = ip; 53 | this.port = port; 54 | this.dataName = dataName; 55 | this.userName = userName; 56 | this.passWord = passWord; 57 | } 58 | 59 | /** 60 | * 说明:数据库连接信息,并创建数据库连接 编码为UTF-8 61 | * 62 | * @return Connection 63 | */ 64 | public Connection getConnection() { 65 | try { 66 | // 如果连接未释放,先断开连接 67 | if (con != null) { 68 | // con.close(); 69 | // con=null; 70 | // log.info("手动关闭数据库连接成功"); 71 | return con;// 未关闭时,不再重新连接,直接返回 72 | } 73 | Class.forName("com.mysql.jdbc.Driver");// 加载Mysql数据驱动 74 | con = DriverManager 75 | .getConnection( 76 | "jdbc:mysql://" 77 | + ip 78 | + ":" 79 | + port 80 | + "/" 81 | + dataName 82 | + "?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=round", 83 | userName, passWord);// 创建数据连接 84 | } catch (Exception e) { 85 | log.error("数据库连接失败"); 86 | log.error(e.getMessage()); 87 | } 88 | return con; // 返回所建立的数据库连接 89 | 90 | } 91 | 92 | /** 93 | * 说明:关闭数据库连接 94 | */ 95 | public void closedConn() { 96 | 97 | try { 98 | if (con != null) 99 | con.close(); 100 | con = null; 101 | log.info("关闭数据库连接成功【" + this.ip + "_" + this.port + "_" 102 | + this.dataName + "】"); 103 | } catch (SQLException e) { 104 | log.error("关闭数据库连接失败【" + this.ip + "_" + this.port + "_" 105 | + this.dataName + "】"); 106 | log.error(e.getMessage()); 107 | } 108 | } 109 | 110 | /** 111 | * 说明:用于执行插入、更新、删除的sql语句,当受影响的行数为0和执行失败时返回false 112 | * 113 | * @param sql 114 | * @return boolean 成功返回true,失败返回false 115 | */ 116 | public boolean excSql(String sql) { 117 | if (con == null) 118 | getConnection(); // 连接到数据库 119 | 120 | try { 121 | Statement st = (Statement) con.createStatement(); // 创建用于执行静态sql语句的Statement对象 122 | int counts = st.executeUpdate(sql); // 执行操作的sql语句 123 | if (0 == counts) { 124 | log.info("执行成功,,共0条数据受到影响,没有完成操作!:SQL语句-->【" + sql + "】"); 125 | return false; 126 | } 127 | log.info("执行成功,共" + counts + "条数据受到影响:" + "SQL语句-->【" + sql + "】"); 128 | return true; 129 | } catch (SQLException e) { 130 | log.error("执行失败:SQL语句-->【" + sql + "】"); 131 | log.error(e.getMessage()); 132 | return false; 133 | } 134 | 135 | } 136 | 137 | /** 138 | * 说明:用户select的查询语句,返回查询结果集 139 | * 140 | * @param sql 141 | * @return ResultSet 查询结果集 142 | */ 143 | public ResultSet querySql(String sql) { 144 | 145 | ResultSet rs = null; 146 | if (con == null) 147 | getConnection(); // 连接到数据库 148 | try { 149 | Statement st = null; // 创建用于执行静态sql语句的Statement对象,st属局部变量 150 | st = (Statement) con 151 | .createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, 152 | ResultSet.CONCUR_READ_ONLY); 153 | rs = st.executeQuery(sql); // 执行sql查询语句,返回查询数据的结果集 154 | log.info("执行成功:SQL查询语句-->【" + sql + "】"); 155 | } catch (SQLException e) { 156 | log.error("执行失败:SQL查询语句-->【" + sql + "】"); 157 | log.error(e.getMessage()); 158 | rs = null; 159 | } 160 | return rs; 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/mysql/MysqlUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.mysql; 2 | 3 | import java.sql.Connection; 4 | import java.sql.ResultSet; 5 | import java.sql.ResultSetMetaData; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.TreeMap; 11 | 12 | import com.github.qihootest.leo.toolkit.util.LogUtil; 13 | import com.github.qihootest.leo.toolkit.util.StringUtil; 14 | 15 | /** 16 | * 数据库操作类,需先使用connMysql或reConnMysql方法先连接到数据库后,再执行其他操作 17 | * @author @bwgang (bwgang@163.com)
18 | * 19 | */ 20 | public class MysqlUtil { 21 | 22 | private static Connection con = null; // 创建用于连接数据库的Connection对象 23 | private static LogUtil log = LogUtil.getLogger(MysqlUtil.class);// 日志记录 24 | private ConnMysql mysql;// 数据库连接 25 | 26 | /** 27 | * 连接mysql,如果已连接,则不再根据传入的参数创建连接 28 | * 29 | * @param ip 30 | * @param port 31 | * @param dataName 32 | * @param userName 33 | * @param passWord 34 | */ 35 | public void connMysql(String ip, String port, String dataName, 36 | String userName, String passWord) { 37 | if (con == null) { 38 | if (null == mysql) {// 39 | mysql = new ConnMysql(); 40 | mysql.ip = ip; 41 | mysql.port = port; 42 | mysql.dataName = dataName; 43 | mysql.userName = userName; 44 | mysql.passWord = passWord; 45 | } 46 | con = mysql.getConnection(); 47 | } 48 | } 49 | 50 | /** 51 | * 根据连接信息,重新连接mysql,如果已有连接,则先断开 52 | * 53 | * @param ip 54 | * @param port 55 | * @param dataName 56 | * @param userName 57 | * @param passWord 58 | */ 59 | public void reConnMysql(String ip, String port, String dataName, 60 | String userName, String passWord) { 61 | MysqlUtil mu = new MysqlUtil(); 62 | closedConn(); 63 | mu.connMysql(ip, port, dataName, userName, passWord); 64 | } 65 | 66 | /** 67 | * 说明:关闭数据库连接 68 | */ 69 | public void closedConn() { 70 | if (con != null) { 71 | mysql.closedConn(); 72 | con = null; 73 | } 74 | } 75 | 76 | /** 77 | * 说明:用于执行插入、更新、删除的sql语句,当受影响的行数为0和执行失败时返回false 78 | * 79 | * @param sql 80 | * @return boolean 成功返回true,失败返回false 81 | */ 82 | public boolean excSql(String sql) { 83 | if (null == con) { 84 | // log.info("尚未连接数据库"); 85 | return false;// 数据库未连接 86 | } 87 | return mysql.excSql(sql); 88 | } 89 | 90 | /** 91 | * 按指定的sql,查询表中所有数据,返回表中所有列 92 | * 93 | * @param sql 94 | * @return List> 95 | */ 96 | public List> queryBySql(String sql) { 97 | return getMapFromResult(querySql(sql)); 98 | } 99 | 100 | /** 101 | * 按指定的表名,查询表中所有数据,返回表中所有列 102 | * 103 | * @param tablename 104 | * @return List> 105 | */ 106 | public List> queryFromTable(String tablename) { 107 | String sql = "select * from " + tablename; 108 | return getMapFromResult(querySql(sql)); 109 | } 110 | 111 | /** 112 | * 按指定的表名,查询表中所有数据,返回表中所有列 113 | * 114 | * @param tablename 115 | * @return List> 116 | */ 117 | public List> queryFromTable(String tablename, 118 | List keyList) { 119 | return getMapByKeyList(queryFromTable(tablename), keyList); 120 | } 121 | 122 | /** 123 | * 按指定的查询条件和表名,查询表中所有数据,返回表中所有列 124 | * 125 | * @param tablename 126 | * @param wherestr 127 | * @return List> 128 | */ 129 | public List> queryFromTableByIf( 130 | String tablename, String wherestr) { 131 | String sql = "select * from " + tablename + " where " + wherestr; 132 | return getMapFromResult(querySql(sql)); 133 | } 134 | 135 | /** 136 | * 按指定的查询条件和表名.查询表中记录,返回第一条记录的指定列的值 137 | * 138 | * @param tablename 139 | * @param wherestr 140 | * @param keyname 141 | * @return String 142 | */ 143 | public String queryFromTableByIf(String tablename, String wherestr, 144 | String keyname) { 145 | Map map = new TreeMap(); 146 | try { 147 | map = queryFromTableByIf(tablename, wherestr).get(0); 148 | return map.get(keyname).toString(); 149 | } catch (Exception e) { 150 | log.error("查询异常"); 151 | log.error(e.getMessage()); 152 | return ""; 153 | } 154 | } 155 | 156 | /** 157 | * 按指定的sql.查询表中记录,返回第一条记录的指定列的值 158 | * 159 | * @param sql 160 | * @return String 161 | */ 162 | public String queryTableBysqlMax(String sql) { 163 | String max = ""; 164 | try { 165 | ResultSet res = querySql(sql); 166 | res.next(); 167 | max = res.getString(1); 168 | } catch (SQLException e) { 169 | log.error("查询最大值失败!"); 170 | log.error(e.getMessage()); 171 | } 172 | return max; 173 | } 174 | 175 | /** 176 | * 按指定的查询条件和表名,查询表中所有数据,返回指定的列 177 | * 178 | * @param tableName 179 | * @param whereStr 180 | * @param keyList 181 | * @return List> 182 | */ 183 | public List> getMapFromSql(String tableName, 184 | String whereStr, List keyList) { 185 | return getMapByKeyList(queryFromTableByIf(tableName, whereStr), keyList); 186 | } 187 | 188 | /** 189 | * 按指定的查询条件和表名,查询表中所有数据,返回Map中key对应的列 190 | * 191 | * @param tablename 192 | * @param wherestr 193 | * @param expMap 194 | * @return List> 195 | */ 196 | public List> getMapFromSql(String tablename, 197 | String wherestr, Map expMap) { 198 | List keyList = StringUtil.getKeyListFromMap(expMap); 199 | return getMapFromSql(tablename, wherestr, keyList); 200 | } 201 | 202 | // 私有方法 203 | 204 | private ResultSet querySql(String sql) { 205 | if (null == con) { 206 | // log.info("尚未连接数据库"); 207 | return null;// 数据库未连接 208 | } 209 | return mysql.querySql(sql); 210 | } 211 | 212 | /** 213 | * 说明:判断查询结果集内的记录个数,如果小于1条则返回true 214 | * 215 | * @param res 216 | * 查询结果集 217 | * @return boolean 结果集异常或等于0条返回true,否则返回false 218 | */ 219 | private static boolean ResultIsNull(ResultSet res) { 220 | if (null == res) { 221 | // log.info("数据库连接异常"); 222 | return true; 223 | } 224 | 225 | try { 226 | res.last(); 227 | if (res.getRow() == 0) { 228 | log.info("查询结果集为0条"); 229 | return true; 230 | } else { 231 | res.beforeFirst(); 232 | return false; 233 | } 234 | } catch (SQLException e) { 235 | 236 | log.error("计算查询结果集个数失败!"); 237 | log.error(e.getMessage()); 238 | return true; 239 | } 240 | 241 | } 242 | 243 | /** 244 | * 查询结果集转换为Map列表 245 | * 246 | * @param rs 247 | * @return List> 248 | */ 249 | private static List> getMapFromResult(ResultSet rs) { 250 | 251 | List> mapList = new ArrayList<>(); 252 | Map map; 253 | ResultSetMetaData rsmd; 254 | if (null == rs) { 255 | // log.info("数据库连接异常"); 256 | return mapList; 257 | } 258 | 259 | 260 | try { 261 | if (MysqlUtil.ResultIsNull(rs)) { 262 | log.error(" 查询结果集为空"); 263 | return mapList; 264 | } 265 | rsmd = rs.getMetaData(); 266 | while (rs.next()) { 267 | map = new TreeMap(); 268 | 269 | for (int i = 1; i <= rsmd.getColumnCount(); i++) { 270 | String key = ""; 271 | String value = ""; 272 | key = rsmd.getColumnName(i).toString(); 273 | try { 274 | value = rs.getObject(i).toString(); 275 | } catch (Exception e) { 276 | // log.error(" 查询结果中解析字段 "+key+"值异常"); 277 | // log.error(e.getMessage()); 278 | } 279 | map.put(key, value); 280 | } 281 | mapList.add(map); 282 | } 283 | } catch (SQLException e) { 284 | log.error("查询异常"); 285 | log.error(e.getMessage()); 286 | } 287 | return mapList; 288 | } 289 | 290 | /** 291 | * 根据指定的key列表,从map中取出新的map 292 | * 293 | * @param mapTmpList 294 | * @param keyList 295 | * @return List> 296 | */ 297 | private static List> getMapByKeyList( 298 | List> mapTmpList, List keyList) { 299 | 300 | List> mapList = new ArrayList>(); 301 | Map mapTmp; 302 | 303 | if (null == keyList || keyList.size() < 1) { 304 | log.error("要获取的列信息为空,请检查"); 305 | return mapList; 306 | } 307 | if (null == mapTmpList || mapTmpList.size() < 1) { 308 | return mapList; 309 | } 310 | 311 | for (int i = 0; i < mapTmpList.size(); i++) {// 处理多条查询结果 312 | mapTmp = new TreeMap<>(); 313 | for (int j = 0; j < keyList.size(); j++) {// 获取指定列信息 314 | String key = keyList.get(j); 315 | String value = StringUtil.getValueFromMapByKey( 316 | mapTmpList.get(i), key); 317 | mapTmp.put(key, value); 318 | } 319 | mapList.add(mapTmp); 320 | } 321 | 322 | return mapList; 323 | 324 | } 325 | } 326 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/mysql/dao/DaoUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.mysql.dao; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.TreeMap; 10 | import java.util.Map.Entry; 11 | 12 | import com.github.qihootest.leo.toolkit.mysql.MysqlUtil; 13 | import com.github.qihootest.leo.toolkit.util.LogUtil; 14 | 15 | /** 16 | * 说明:数据库通用操作类, 17 | * 当前只支持数据类型为String 18 | * 所有实现ITable接口的实体类都可使用此类的方法完成增删改查 19 | * @author lianghui (lianghui@360.cn) 2013-01-10 20 | * 21 | */ 22 | public class DaoUtil { 23 | 24 | private static LogUtil log=LogUtil.getLogger(DaoUtil.class);//日志记录 25 | MysqlUtil mysqlUtil ; 26 | 27 | /** 28 | * 构造方法 29 | */ 30 | public DaoUtil(){ 31 | mysqlUtil = new MysqlUtil(); 32 | } 33 | 34 | /** 35 | * 说明:根据传入的实体类,返回对应数据库表所有记录List 36 | * @param table 实体类对象 37 | * @return List实体类对应数据库表的所有记录List 38 | */ 39 | public List getAllInfo(ITable table){ 40 | String tablename=getNameOfClass(table); 41 | List keyList=getCoList(table); 42 | List>resMapList=mysqlUtil.queryFromTable(tablename, keyList); 43 | return getTableFromMap(resMapList,table); 44 | } 45 | 46 | /** 47 | * 说明:根据传入的实体类,按指定的查询条件返回对应数据库表记录List 48 | * @param where 49 | * @param table 50 | * @return List 51 | */ 52 | public List getInfoByKey(String where,ITable table) { 53 | String tablename=getNameOfClass(table); 54 | List keyList=getCoList(table); 55 | List>resMapList=mysqlUtil.getMapFromSql(tablename, where,keyList); 56 | return getTableFromMap(resMapList,table); 57 | } 58 | 59 | /** 60 | * 说明:根据传入的实体类,按自定义sql语句返回对应数据库表记录List 61 | * @param sql 62 | * @param table 63 | * @return List 64 | */ 65 | public List getInfoBySql(String sql,ITable table) { 66 | List>resMapList=mysqlUtil.queryBySql(sql); 67 | return getTableFromMap(resMapList,table); 68 | } 69 | 70 | /** 71 | * 说明:根据传入的实体类,按指定列名返回此列的最大值 72 | * @param key 73 | * @param table 74 | * @return String 75 | */ 76 | public String getMaxInfoByKey(String key,ITable table) { 77 | String tablename=getNameOfClass(table); 78 | String max=""; 79 | String sql="SELECT MAX("+key+") from "+tablename; 80 | max=mysqlUtil.queryTableBysqlMax(sql); 81 | if (null==max || max.length()<1) { 82 | max="0"; 83 | } 84 | return max; 85 | } 86 | /** 87 | * 说明:根据传入的实体类,按指定的条件更新一条记录 88 | * @param key 89 | * @param value 90 | * @param table 91 | * @return boolean 92 | */ 93 | public boolean updateInfo(String key,String value,ITable table) { 94 | boolean flag=false; 95 | String sql=getUpdateSql(key, value, table); 96 | flag=mysqlUtil.excSql(sql); 97 | return flag; 98 | } 99 | 100 | /** 101 | * 说明:根据传入的实体类,插入到数据库对应的表中一条数据 102 | * @param table 103 | * @return boolean 插入成功返回true,失败返回false 104 | */ 105 | public boolean insterInfo(ITable table) { 106 | boolean flag=false; 107 | String sql=getInsertSql(table); 108 | flag=mysqlUtil.excSql(sql); 109 | return flag; 110 | } 111 | 112 | /** 113 | * 说明:根据传入的实体类,按指定的条件删除对应数据库表中一条记录 114 | * @param key 115 | * @param value 116 | * @param table 117 | * @return boolean 删除成功返回true,失败返回false 118 | */ 119 | public boolean deleteInfoByKey(String key,String value,ITable table) { 120 | boolean flag=false; 121 | String sql="DELETE from "+getNameOfClass(table)+" where " 122 | +key+"='"+value+"'"; 123 | 124 | flag=mysqlUtil.excSql(sql); 125 | return flag; 126 | } 127 | 128 | 129 | /** 130 | * 说明:根据实体类对象,获取实体类对应table的所有列名 131 | * @param table 实体类对象 132 | * @return List table的所有列名的List 133 | */ 134 | public static List getCoList(ITable table) { 135 | List colList=new ArrayList(); 136 | Field[] field=table.getClass().getDeclaredFields(); 137 | for (int i = 0; i < field.length; i++) { 138 | Field f= field[i]; 139 | f.setAccessible(true); 140 | try { 141 | colList.add(f.getName()); 142 | } catch (IllegalArgumentException e1) { 143 | colList=null; 144 | log.error("获取实体类"+table.getClass().getSimpleName()+"的第"+(i+1)+"个字段失败"); 145 | log.error(e1.getMessage()); 146 | } 147 | } 148 | return colList; 149 | } 150 | 151 | /** 152 | * 说明:根据key-value键值对,对实体类赋值 153 | * @param key 154 | * @param value 155 | * @param table 实体类对象 156 | * @return boolean 赋值成功返回true,失败返回false 157 | */ 158 | public static boolean set(String key,String value,ITable table) { 159 | boolean flag=false; 160 | List coList= getCoList(table); 161 | for (int i = 0; i [] parameterTypes = new Class[1]; 165 | Field field = table.getClass().getDeclaredField(key); 166 | parameterTypes[0] = field.getType(); 167 | Method m = (Method) table.getClass().getMethod(getMethodByName("set", key),parameterTypes); 168 | m.invoke(table, value); 169 | flag=true; 170 | break; 171 | } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchFieldException e) { 172 | flag=false; 173 | log.error("对实体类"+table.getClass().getSimpleName()+"的字段"+key+"赋值失败"); 174 | log.error(e.getMessage()); 175 | break; 176 | 177 | } 178 | } 179 | } 180 | return flag; 181 | } 182 | 183 | /** 184 | * 说明:根据key值,从实体类中获取对应的value值 185 | * @param key 186 | * @param table 实体类对象 187 | * @return String 实体类中key对应的value值 188 | */ 189 | public static String get(String key,ITable table) { 190 | String res=""; 191 | List coList= getCoList(table); 192 | for (int i = 0; i colList=getCoList(table); 231 | 232 | for (int i = 0; i < colList.size(); i++) { 233 | try { 234 | Method m = (Method) table.getClass().getMethod(getMethodByName("get", colList.get(i))); 235 | String temp=m.invoke(table).toString(); 236 | sql+=colList.get(i)+" = '"+temp+"',"; 237 | m=null; 238 | } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 239 | log.error("拼接表"+table.getClass().getSimpleName()+"的列"+colList.get(i)+"的update语句异常"); 240 | log.error(e.getMessage()); 241 | } 242 | 243 | } 244 | sql=sql.substring(0, sql.length()-1); 245 | sql+=" where "+key+" = "+value; 246 | return sql; 247 | } 248 | 249 | /** 250 | * 说明:根据传入的实体类,拼接用户数据库插入的sql语句 251 | * @param cls 实体类对象 252 | * @return String 拼接后的sql语句 253 | */ 254 | private static String getInsertSql(ITable table) { 255 | String sql="insert into "+getNameOfClass(table); 256 | List keyList=getCoList(table); 257 | String key=""; 258 | String value=""; 259 | 260 | for (int i = 0; i < keyList.size(); i++) { 261 | try { 262 | Method m = (Method) table.getClass().getMethod(getMethodByName("get", keyList.get(i))); 263 | String temp=m.invoke(table).toString(); 264 | key+=keyList.get(i)+","; 265 | value+="'"+temp+"',"; 266 | } catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { 267 | log.error("拼接表"+table.getClass().getSimpleName()+"的列"+keyList.get(i)+"的Insert语句异常"); 268 | log.error(e.getMessage()); 269 | } 270 | } 271 | key=key.substring(0, key.length()-1); 272 | value=value.substring(0, value.length()-1); 273 | sql+=" ("+key+") values("+value+")"; 274 | return sql; 275 | } 276 | 277 | private static List getTableFromMap(List> resMapList,ITable table) { 278 | ListtableList=new ArrayList<>(); 279 | if (null==resMapList || resMapList.size()<1) { 280 | return tableList; 281 | } 282 | 283 | for (int i = 0; i < resMapList.size(); i++) { 284 | ITable tableTmp=getNewInstanceByClassdeep(table); 285 | Map mapTmp=new TreeMap(); 286 | //把查询结果赋值给实体类 287 | mapTmp=resMapList.get(i); 288 | for (Entry entry : mapTmp.entrySet()) { 289 | String key = entry.getKey().toString(); 290 | String value = entry.getValue().toString(); 291 | set(key, value, tableTmp); 292 | } 293 | //赋值给实体类完毕 294 | tableList.add(tableTmp); 295 | } 296 | return tableList; 297 | } 298 | 299 | 300 | 301 | /** 302 | * 说明:内部使用,根据传入的set或get、实体类属性名称拼接对应的set或get方法名 303 | * @param method 304 | * @param fildeName 305 | * @return String 对应的set或get方法名 306 | */ 307 | private static String getMethodByName(String method,String fildeName) { 308 | return method+getFirstCapitalized(fildeName); 309 | } 310 | 311 | /** 312 | * 说明:内部使用,把传入的字符串首字母大写并返回 313 | * @param fildeName 314 | * @return String 首字母大写之后的字符串 315 | */ 316 | private static String getFirstCapitalized(String fildeName) { 317 | byte[] items = fildeName.getBytes(); 318 | items[0] = (byte) ((char) items[0] - 'a' + 'A'); 319 | return new String(items); 320 | } 321 | 322 | /** 323 | * 说明:内部使用,根据传入的类,返回new之后的此类的实例化对象 324 | * @param cls 类对象 325 | * @return ITable 实例化之后的类对象 326 | */ 327 | private static ITable getNewInstanceByClassdeep(ITable table) { 328 | ITable table2; 329 | 330 | try { 331 | Class clazz = Class.forName(table.getClass().getName()); 332 | table2=(ITable) clazz.newInstance(); 333 | return table2; 334 | } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { 335 | log.error(e.getMessage()); 336 | return null; 337 | } 338 | 339 | } 340 | 341 | 342 | 343 | } 344 | 345 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/mysql/dao/ITable.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.mysql.dao; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 说明:数据库表实体类的基类 7 | * 当前有3个公共方法 8 | * @author lianghui (lianghui@360.cn) 2013-01-10 9 | * 10 | */ 11 | public interface ITable { 12 | public List getColList(); 13 | public void set(String key,String value); 14 | public String get(String key); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/mysql/dao/Table.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.mysql.dao; 2 | 3 | import java.util.List; 4 | 5 | 6 | 7 | 8 | 9 | public abstract class Table implements ITable{ 10 | 11 | 12 | public List getColList() { 13 | return DaoUtil.getCoList(this); 14 | } 15 | public void set(String key,String value) { 16 | DaoUtil.set(key, value, this); 17 | } 18 | public String get(String key) { 19 | return DaoUtil.get(key, this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/CompilerUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | import javax.tools.Diagnostic; 10 | import javax.tools.DiagnosticCollector; 11 | import javax.tools.JavaCompiler; 12 | import javax.tools.JavaCompiler.CompilationTask; 13 | import javax.tools.JavaFileObject; 14 | import javax.tools.StandardJavaFileManager; 15 | import javax.tools.ToolProvider; 16 | 17 | 18 | /** 19 | * 编译java文件为class 20 | * @author lianghui (lianghui@360.cn) 2013-01-10 21 | * 22 | */ 23 | public class CompilerUtil { 24 | 25 | //日志记录 26 | private static LogUtil log=LogUtil.getLogger(CompilerUtil.class); 27 | 28 | /** 29 | * 编译java文件为class 30 | * @param javaFilePath java文件或包含java文件的目录 31 | * @param distPath 项目class文件存放目录 32 | * @param libPath jar包存放目录 33 | * @param jarFile jar包存放目录(maven) 34 | * @return boolean 编译成功返回true 35 | */ 36 | public static boolean dynamicCompiler(String javaFilePath,String distPath,String libPath,String jarFile) { 37 | DiagnosticCollector diagnostics = new DiagnosticCollector(); 38 | boolean compilerResult = compiler("UTF-8",getClassPath(libPath,distPath,jarFile),javaFilePath, distPath, diagnostics); 39 | if (compilerResult) { 40 | log.info("动态编译成功:"+javaFilePath+" 输出目录为:"+distPath); 41 | }else{ 42 | log.error("动态编译失败:"+javaFilePath); 43 | for (@SuppressWarnings("rawtypes") Diagnostic diagnostic : diagnostics.getDiagnostics()) { 44 | log.error(diagnostic.getMessage(null)); 45 | } 46 | } 47 | return compilerResult; 48 | } 49 | 50 | /** 51 | * 编译java文件 52 | * @param encoding 编译编码 53 | * @param jars 需要加载的jar目录或文件 54 | * @param filePath 文件或者目录(若为目录,编译目录下所有java文件) 55 | * @param sourceDir 项目源码目录 56 | * @param distDir 编译后class类文件存放目录 57 | * @param diagnostics 存放编译过程中的错误信息 58 | * @return boolean 59 | */ 60 | private static boolean compiler(String encoding,String jars,String filePath, String distDir, DiagnosticCollector diagnostics){ 61 | // 获取编译器实例 62 | JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 63 | // 获取标准文件管理器实例 64 | StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); 65 | //编译文件 66 | if (StringUtil.IsNullOrEmpty(filePath)) { 67 | log.info("待编译的文件或目录不存在"); 68 | return false; 69 | } 70 | //输出目录 71 | if (!FileUtil.createDictory(distDir)) { 72 | log.error("输出目录创建失败"); 73 | return false; 74 | } 75 | // 得到filePath目录下的所有java源文件 76 | File sourceFile = new File(filePath); 77 | List sourceFileList = new ArrayList(); 78 | sourceFileList = getSourceFiles(sourceFile); 79 | // 没有java文件,直接返回 80 | if (sourceFileList.size() == 0) { 81 | log.error(filePath + "目录下查找不到任何java文件"); 82 | return false; 83 | } 84 | // 获取要编译的编译单元 85 | Iterable compilationUnits = fileManager.getJavaFileObjectsFromFiles(sourceFileList); 86 | //编译选项,在编译java文件时,编译程序会自动的去寻找java文件引用的其他的java源文件或者class。 -classpath选项就是定义class文件的查找目录。 87 | Iterable options = Arrays.asList("-encoding",encoding,"-classpath",jars,"-d", distDir); 88 | CompilationTask compilationTask = compiler.getTask(null, fileManager, diagnostics, options, null, compilationUnits); 89 | 90 | // 运行编译任务 91 | boolean res= compilationTask.call(); 92 | try { 93 | fileManager.close(); 94 | } catch (IOException e) { 95 | log.error("关闭文件管理器失败"); 96 | log.error(e.getMessage()); 97 | } 98 | return res; 99 | } 100 | 101 | /** 102 | * 查找该目录下的所有的java文件 103 | * @param sourceFile 104 | * @return List 105 | */ 106 | private static List getSourceFiles(File sourceFile){ 107 | List sourceFileList = new ArrayList(); 108 | if (sourceFile.exists() && sourceFileList != null) {//文件或者目录必须存在 109 | if (sourceFile.isDirectory()) {// 若file对象为目录 110 | // 得到该目录下以.java结尾的所有文件 111 | List sourceFileListTmp=FileUtil.getFilesFromFolder(sourceFile.getPath(),"java"); 112 | for (String filePath : sourceFileListTmp) { 113 | sourceFileList.add(new File(filePath)); 114 | } 115 | } else {// 若file对象为文件 116 | sourceFileList.add(sourceFile); 117 | } 118 | }else{ 119 | log.error("目录或文件不存在: "+sourceFile); 120 | } 121 | return sourceFileList; 122 | } 123 | 124 | /** 125 | * 查找该目录下的所有的jar文件 126 | * @param libPath 127 | * @return String 128 | */ 129 | private static String getJarFiles(String libPath,String jarFile) { 130 | // 得到该目录下以.jar结尾的所有文件 131 | String jarsPath=""; 132 | List jarFilePath = FileUtil.getFilesFromFolder(libPath,"jar"); 133 | for (String filePath : jarFilePath) { 134 | jarsPath=jarsPath+filePath+";"; 135 | } 136 | jarsPath=jarsPath+jarFile; 137 | return jarsPath; 138 | } 139 | 140 | private static String getClassPath(String libPath,String classPath,String jarFile){ 141 | if (FileUtil.isExist(classPath)) { 142 | return getJarFiles(libPath,jarFile)+classPath; 143 | }else{ 144 | log.error("classPath不存在:"+classPath); 145 | return getJarFiles(libPath,jarFile); 146 | } 147 | } 148 | } 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/ExcelUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.io.IOException; 4 | import java.math.BigDecimal; 5 | import java.text.SimpleDateFormat; 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | import org.apache.poi.hssf.usermodel.HSSFWorkbook; 10 | import org.apache.poi.ss.usermodel.Cell; 11 | import org.apache.poi.ss.usermodel.DateUtil; 12 | import org.apache.poi.ss.usermodel.Row; 13 | import org.apache.poi.ss.usermodel.Sheet; 14 | import org.apache.poi.ss.usermodel.Workbook; 15 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; 16 | 17 | 18 | //2007以下版本xsl 19 | //2007及以上版本xslx 20 | 21 | /** 22 | * Excel文件的读写 23 | * @author lianghui (lianghui@360.cn) 24 | * 25 | * 2007以下版本xsl 26 | * 2007及以上版本xslx 27 | */ 28 | public class ExcelUtil { 29 | private static LogUtil log=LogUtil.getLogger(ExcelUtil.class);//记录日志 30 | 31 | private Workbook wb;//工作簿 32 | private Sheet sheet;//sheet表 33 | private String pathName; 34 | 35 | /** 36 | * 默认构造函数 37 | */ 38 | public ExcelUtil(){ 39 | 40 | } 41 | /** 42 | * 构造函数 43 | * @param pathName 44 | */ 45 | public ExcelUtil(String pathName){ 46 | this.pathName=pathName; 47 | setWb(); 48 | } 49 | /** 50 | * 构造函数 51 | * @param pathName 52 | * @param sheetName 53 | */ 54 | public ExcelUtil(String pathName,String sheetName){ 55 | this.pathName=pathName; 56 | setWb(); 57 | setSheet(sheetName); 58 | } 59 | /** 60 | * 构造函数 61 | * @param pathName 62 | * @param sheetIndex 63 | */ 64 | public ExcelUtil(String pathName,int sheetIndex){ 65 | this.pathName=pathName; 66 | setWb(); 67 | setSheet(sheetIndex); 68 | } 69 | 70 | /** 71 | * 写Excel文件 72 | * @param wb 73 | * @param pathName 74 | */ 75 | public void writeExcel2007(XSSFWorkbook wb,String pathName) { 76 | try { 77 | wb.write(FileUtil.getFileOutStream(pathName)); 78 | } catch (IOException e) { 79 | log.error("写入Excel文件失败:"+pathName); 80 | log.error(e.getMessage()); 81 | } 82 | } 83 | 84 | /** 85 | * 获取工作簿 86 | * @return Workbook 87 | */ 88 | public Workbook getWb() { 89 | return this.wb; 90 | } 91 | /** 92 | * 设置Excel文件路径 93 | * @param pathName 94 | */ 95 | public void setPathName(String pathName) { 96 | this.pathName=pathName; 97 | setWb(); 98 | // setSheet(); 99 | } 100 | 101 | /** 102 | * 设置sheet 103 | * @param sheet 104 | */ 105 | public void setSheet(Sheet sheet) { 106 | this.sheet = sheet; 107 | //删除掉空白行 108 | delBankRow(); 109 | } 110 | /** 111 | * 设置sheet 112 | * @param sheetName 113 | */ 114 | public void setSheet(String sheetName) { 115 | if (null==wb) return; 116 | setSheet(getWb().getSheet(sheetName)); 117 | if (null==getSheet()) {//按名称未获取到sheet 118 | // log.info("Excel:"+this.pathName+"中,要获取的名称为"+sheetName+"的sheet页不存在," + 119 | // "默认获取第一个sheet页"); 120 | setSheet(getWb().getSheetAt(0)); 121 | if (null==getSheet())log.error("Excel:"+this.pathName+"中,不存在任何Sheet"); 122 | } 123 | } 124 | /** 125 | * 设置sheet 126 | * @param sheetIndex 127 | */ 128 | public void setSheet(int sheetIndex) { 129 | if (null==wb) return; 130 | try { 131 | setSheet(getWb().getSheetAt(sheetIndex)); 132 | } catch (Exception e) { 133 | log.error("Excel:"+this.pathName+"中,要获取的第"+sheetIndex+"个sheet不存在," 134 | +"默认获取第一个Sheet1"); 135 | setSheet(getWb().getSheetAt(0)); 136 | if (null==getSheet())log.error("Excel:"+this.pathName+"中,不存在任何Sheet"); 137 | } 138 | 139 | } 140 | /** 141 | * 获取单元格内容,坐标从(0,0)开始,横为行,竖为列 142 | * @param rowIndex 143 | * @param colIndex 144 | * @return String 145 | */ 146 | public String getCellValue(int rowIndex,int colIndex) { 147 | if ( colIndex<0) { 148 | log.error("读取Excel的列数不能为负数"); 149 | return null; 150 | } 151 | Row row=getRow(rowIndex); 152 | if (null==row) return null; 153 | return getStrFromCell(row.getCell(colIndex)); 154 | } 155 | /** 156 | * 获取一行的内容 157 | * @param rowIndex 158 | * @return List 159 | */ 160 | public List getRowList(int rowIndex) { 161 | List reslist=new ArrayList<>(); 162 | Row row=getRow(rowIndex); 163 | if (null!=row) { 164 | for (int i = 0; i < getColNum(); i++) { 165 | reslist.add(getCellValue(rowIndex, i)); 166 | } 167 | } 168 | 169 | return reslist; 170 | } 171 | /** 172 | * 获取总行数 173 | * @return int 174 | */ 175 | public int getRowNum() { 176 | if (null==getSheet())return 0; 177 | return getSheet().getLastRowNum()+1; 178 | } 179 | /** 180 | * 获取总列数 181 | * @return int 182 | */ 183 | public int getColNum() { 184 | int max=0; 185 | if (null==getSheet())return 0; 186 | if (getSheet().getPhysicalNumberOfRows()<1)return 0; 187 | for (int i = 0; i < getRowNum(); i++) { 188 | int tmp=getRow(i).getPhysicalNumberOfCells(); 189 | // log.error(i+"=="+tmp); 190 | if (tmp>=max)max=tmp; 191 | } 192 | return max; 193 | } 194 | 195 | private Row getRow(int rowIndex) { 196 | if ( rowIndex<0) { 197 | log.error("读取Excel的行数不能为负数"); 198 | return null; 199 | } 200 | if (null==getSheet()) return null; 201 | Row row=getSheet().getRow(rowIndex); 202 | if (null==row) { 203 | if (rowIndex-1 && exname.indexOf("xlsx")<0) { 270 | this.wb=new HSSFWorkbook(FileUtil.readToFileInputStream(this.pathName)); 271 | }else if (exname.indexOf("xlsx")>-1) { 272 | this.wb=new XSSFWorkbook(FileUtil.readToFileInputStream(this.pathName)); 273 | }else{ 274 | log.info("无法读取,Excel文件异常:"+this.pathName); 275 | } 276 | } catch ( NullPointerException | IOException e) { 277 | log.error("读取Excel文件出错:"+this.pathName); 278 | log.error(e.getMessage()); 279 | e.printStackTrace(); 280 | } 281 | } 282 | private void delBankRow() { 283 | for (int i = 0; i <= getRowNum(); i++) { 284 | Row r; 285 | try { 286 | r = sheet.getRow(i); 287 | } catch (Exception e) { 288 | r = null; 289 | // sheet.removeRowBreak(i); 290 | continue; 291 | } 292 | 293 | if (r == null && i == sheet.getLastRowNum()) { 294 | // 如果是空行,且到了最后一行,直接将那一行删掉 295 | sheet.removeRow(r); 296 | } else if (r == null && i < sheet.getLastRowNum()) { 297 | // 如果还没到最后一行,则数据往上移一行 298 | sheet.shiftRows(i + 1, sheet.getLastRowNum(), -1); 299 | } 300 | 301 | } 302 | } 303 | 304 | } 305 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/FreeMakerUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | 4 | import java.io.File; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.io.OutputStreamWriter; 8 | import java.io.Writer; 9 | import java.util.Map; 10 | 11 | import freemarker.template.Configuration; 12 | import freemarker.template.DefaultObjectWrapper; 13 | import freemarker.template.Template; 14 | import freemarker.template.TemplateException; 15 | 16 | /** 17 | * 根据模板+数据 输出文件 18 | * @author lianghui (lianghui@360.cn) 19 | */ 20 | public class FreeMakerUtil { 21 | //日志记录 22 | private static LogUtil log=LogUtil.getLogger(FreeMakerUtil.class); 23 | 24 | /** 25 | * 根据模板+数据 输出文件 26 | * @param templateFilePath 模板的绝对路径 27 | * @param data 数据 28 | * @param javaFilePath 输出的文件位置 29 | * @return boolean 30 | */ 31 | public boolean CreateJavaFile(String templateFilePath,Map data,String javaFilePath) { 32 | 33 | if (!FileUtil.isExist(templateFilePath)) { 34 | log.info("模板文件不存在:"+templateFilePath); 35 | return false; 36 | } 37 | if (null == data) { 38 | log.info("模板数据不能为null"); 39 | return false; 40 | } 41 | // Map clsMap= (Map) data.get("clsInfo"); 42 | // for (Entry entry : clsMap.entrySet()) { 43 | // String key = entry.getKey().toString(); 44 | // String value = entry.getValue().toString(); 45 | // log.info(key+"=="+value); 46 | // } 47 | // log.info("FreeMaker--39--"+data.size()); 48 | // PrintModelObject.P(data.get("clsInfo")); 49 | if (!FileUtil.createFile(javaFilePath)) { 50 | return false; 51 | } 52 | try { 53 | String tmpPath=FileUtil.getParentPath(templateFilePath); 54 | String tmpName=FileUtil.getFileName(templateFilePath); 55 | 56 | Configuration cfg =new Configuration(); 57 | cfg.setDirectoryForTemplateLoading(new File(tmpPath)); 58 | cfg.setObjectWrapper(new DefaultObjectWrapper()); 59 | 60 | //读取模板 61 | Template template= cfg.getTemplate(tmpName); 62 | 63 | //输出到文件 64 | Writer out = new OutputStreamWriter(new FileOutputStream(javaFilePath),"UTF-8"); 65 | template.process(data, out);//根据模板和数据输出java文件 66 | 67 | return true; 68 | 69 | } catch (IOException | TemplateException e) { 70 | //生成.java文件失败 71 | log.error(e.getMessage()); 72 | return false; 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/JsonUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | import java.util.TreeMap; 7 | 8 | import net.sf.json.JSONArray; 9 | import net.sf.json.JSONException; 10 | import net.sf.json.JSONObject; 11 | 12 | /** 13 | * 说明:解析Json字符串,解析后为map存储的键值对 14 | * @author lianghui (lianghui@360.cn) 15 | * 16 | */ 17 | public class JsonUtil { 18 | private Map oneResult = new TreeMap(); 19 | 20 | 21 | /** 22 | * 单层解析json字符串 23 | * @param str 24 | * @return Map 异常返回null 25 | */ 26 | @SuppressWarnings("unchecked") 27 | public static Map getResult(String str) { 28 | JsonUtil jsonUtil = new JsonUtil(); 29 | try { 30 | jsonUtil.oneResult = JSONObject.fromObject(str); 31 | } catch (JSONException e) { 32 | jsonUtil.oneResult = null; 33 | } 34 | return jsonUtil.oneResult; 35 | } 36 | 37 | /** 38 | * 多层解析 json字符串 39 | * @param str 40 | * @return Map 异常返回null 41 | */ 42 | public static Map getAllResult(String str) { 43 | JsonUtil jsonUtil = new JsonUtil(); 44 | try { 45 | JSONObject tempJSON = JSONObject.fromObject(str); 46 | jsonToMap(tempJSON, jsonUtil.oneResult); 47 | } catch (Exception e) { 48 | jsonUtil.oneResult = null; 49 | } 50 | return jsonUtil.oneResult; 51 | } 52 | 53 | @SuppressWarnings("unchecked") 54 | private static void jsonToMap(JSONObject tempJSON,Map resultMap) { 55 | for (Iterator it = tempJSON.keys(); it.hasNext();) { 56 | String key = it.next(); 57 | String realKey = key; 58 | Object valueObj = tempJSON.get(key); 59 | if (valueObj instanceof JSONObject) { 60 | JSONObject jo = (JSONObject) valueObj; 61 | jsonToMap(jo,resultMap); 62 | } else if (valueObj instanceof JSONArray) { 63 | JSONArray ja = (JSONArray) valueObj; 64 | for (int i = 0; i < ja.size(); i++) { 65 | JSONObject jo = ja.getJSONObject(i); 66 | jsonToMap(jo,resultMap); 67 | } 68 | } else { // 简单类型 69 | if (resultMap.containsKey(realKey)) { // 判断是否存在相同的key,如果存在相同的key,map将用泛型存储 70 | ArrayList valueList = new ArrayList(); 71 | if (resultMap.get(realKey) instanceof ArrayList) { // 判断value是否已经为ArrayList,等二次发现有相同的key 72 | valueList = (ArrayList) resultMap.get(realKey); 73 | valueList.add(valueObj.toString().trim()); 74 | resultMap.put(realKey, valueList); 75 | } else { // 第一次处理相同的key,new一个ArrayList 76 | valueList.add(resultMap.get(realKey)); 77 | valueList.add(valueObj.toString().trim()); 78 | resultMap.put(realKey, valueList); 79 | } 80 | 81 | } else { 82 | resultMap.put(realKey, valueObj.toString().trim()); 83 | } 84 | 85 | } 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | 4 | import org.apache.log4j.Logger; 5 | import org.apache.log4j.PropertyConfigurator; 6 | 7 | import com.github.qihootest.leo.toolkit.TkConf; 8 | 9 | /** 10 | * 自定义日志 11 | * @author lianghui (lianghui@360.cn) 12 | */ 13 | public class LogUtil { 14 | private Logger log ; 15 | private LogUtil(String name) { 16 | configLogProperties(); 17 | log = Logger.getLogger(name); 18 | } 19 | private LogUtil(Class clazz){ 20 | configLogProperties(); 21 | log = Logger.getLogger(clazz); 22 | } 23 | 24 | /** 25 | * 26 | * @param name 27 | * @return LogUtil 28 | */ 29 | public static LogUtil getLogger(String name){ 30 | return new LogUtil(name); 31 | } 32 | /** 33 | * 34 | * @param clazz 35 | * @return LogUtil 36 | */ 37 | public static LogUtil getLogger(Class clazz){ 38 | return new LogUtil(clazz); 39 | } 40 | 41 | /** 42 | * error级别日志 43 | * @param message 44 | */ 45 | public void error(Object message){ 46 | log.error(message); 47 | } 48 | /** 49 | * info 级别日志 50 | * @param message 51 | */ 52 | public void info(Object message){ 53 | log.info(message); 54 | } 55 | /** 56 | * debug级别日志 57 | * @param message 58 | */ 59 | public void debug(Object message){ 60 | log.debug(message); 61 | } 62 | /** 63 | * warn级别日志 64 | * @param message 65 | */ 66 | public void warn(Object message){ 67 | log.error(message); 68 | } 69 | 70 | /** 71 | * 读取日志配置文件 72 | */ 73 | private void configLogProperties(){ 74 | try { 75 | TkConf.writeConf(); 76 | PropertyConfigurator.configure(TkConf.Log4jConf); 77 | } catch (Exception e) { 78 | // e.printStackTrace(); 79 | } 80 | } 81 | 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/PropUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.io.IOException; 4 | import java.util.ArrayList; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | import java.util.Properties; 10 | import java.util.TreeMap; 11 | 12 | 13 | /** 14 | * Properties配置文件相关处理 15 | * @author lianghui (lianghui@360.cn) 16 | * 17 | */ 18 | public class PropUtil { 19 | private static LogUtil log= LogUtil.getLogger(PropUtil.class); 20 | 21 | /** 22 | * 获取指定位置的property文件中property文件信息 23 | * @param fullFilePath property文件的全路径信息 24 | * @return Properties 属性文件的信息 25 | * */ 26 | public static Properties getPropertyInfo(String fullFilePath){ 27 | Properties properties=new Properties(); 28 | try { 29 | properties.load(FileUtil.readToFileInputStream(fullFilePath)); 30 | } catch (IOException e) { 31 | properties=null; 32 | log.error(e.getMessage()); 33 | } 34 | return properties; 35 | } 36 | 37 | /**获得properties文件里面指定属性名字的属性值,如果不存在该属性或者该属性的值为"",抛出异常 38 | * @param properties 给定的properties文件 39 | * @param propertiesName 属性名字 40 | * @return String 属性值 41 | * */ 42 | public static String getValue(Properties properties,String propertiesName){ 43 | String value=properties.getProperty(propertiesName); 44 | if(value==null||"".equalsIgnoreCase(value)){ 45 | log.error("获取的属性值不存在或者为空串!"); 46 | }return value; 47 | } 48 | /**获得properties文件里面指定属性名字的属性值,如果不存在该属性或者该属性的值为"",返回默认值 49 | * @param properties 给定的properties文件 50 | * @param propertiesName 属性名字 51 | * @param defaultValue 在属性值不存在或者为""的时候的返回的默认值 52 | * @return String 属性值 53 | * */ 54 | public static String getValue(Properties properties,String propertiesName,String defaultValue){ 55 | String value=properties.getProperty(propertiesName); 56 | if(value==null||"".equalsIgnoreCase(value)){ 57 | return defaultValue; 58 | }return value; 59 | } 60 | /**通常在一个properties文件里面一个属性会有很多值,他们之间用','隔开,那么这个方法的作用就是获得所有的值
61 | * 属性值为""的不加入返回的列表,如果属性值不存在或者所有的值都为"",抛出异常 62 | * @param properties 给定的properties文件 63 | * @param propertiesName 属性名字 64 | * @return List 属性值列表*/ 65 | public static List getValueList(Properties properties,String propertiesName){ 66 | ArrayListvaluesList; 67 | String values=getValue(properties, propertiesName); 68 | valuesList=new ArrayList(values.length()); 69 | String[]propertieValues=values.split(","); 70 | for(String value:propertieValues){ 71 | if(value.trim().equalsIgnoreCase("")) 72 | continue; 73 | valuesList.add(value.trim()); 74 | } 75 | if(valuesList.isEmpty()){ 76 | log.error("获取的属性列表所有的属性都为空串!"); 77 | }return valuesList; 78 | } 79 | 80 | /** 81 | * 从配置文件中读取所有信息到map表中 82 | * @param properties 83 | * @return Map 84 | */ 85 | public static Map getAllInfoToMap(Properties properties) { 86 | Map map=new TreeMap(); 87 | try { 88 | Iterator> it=properties.entrySet().iterator(); 89 | while(it.hasNext()){ 90 | Map.Entry entry=(Map.Entry)it.next(); 91 | String key = entry.getKey().toString(); 92 | String value = entry.getValue().toString(); 93 | map.put(key, value); 94 | } 95 | } catch (Exception e) { 96 | log.error(e.getMessage()); 97 | } 98 | return map; 99 | } 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/SftpExecUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Properties; 6 | 7 | 8 | import com.jcraft.jsch.Channel; 9 | import com.jcraft.jsch.ChannelExec; 10 | import com.jcraft.jsch.JSch; 11 | import com.jcraft.jsch.JSchException; 12 | import com.jcraft.jsch.Session; 13 | 14 | /** 15 | * 连接到CentOS服务器,执行命令 16 | * @author lianghui (lianghui@360.cn) 17 | */ 18 | public class SftpExecUtil { 19 | 20 | private static Session session = null; 21 | private static Channel channel = null; 22 | private LogUtil log=LogUtil.getLogger(SftpExecUtil.class);//日志记录 23 | 24 | /** 25 | * 主机host 26 | */ 27 | public String SshHost = ""; 28 | /** 29 | * 端口 30 | */ 31 | public String SshPort = ""; 32 | /** 33 | * 用户名 34 | */ 35 | public String SshUserName = ""; 36 | /** 37 | * 密码 38 | */ 39 | public String SshPassword = ""; 40 | 41 | private Session getSession() { 42 | if (null!=session) { 43 | return session; 44 | } 45 | String ftpHost = SshHost; 46 | String port = SshPort; 47 | String ftpUserName = SshUserName; 48 | String ftpPassword = SshPassword; 49 | 50 | int ftpPort = 21; 51 | if (port != null && !port.equals("")) { 52 | ftpPort = Integer.valueOf(port); 53 | } 54 | 55 | JSch jsch = new JSch(); // 创建JSch对象 56 | 57 | try { 58 | // 根据用户名,主机ip,端口获取一个Session对象 59 | session = jsch.getSession(ftpUserName, ftpHost, ftpPort); 60 | if (ftpPassword != null) { 61 | session.setPassword(ftpPassword); // 设置密码 62 | } 63 | Properties config = new Properties(); 64 | config.put("StrictHostKeyChecking", "no"); 65 | session.setConfig(config); // 为Session对象设置properties 66 | session.setTimeout(300000); // 设置timeout时间为5分钟 67 | session.connect(); // 通过Session建立链接 68 | // log.info("连接 "+ftpHost+":"+ftpPort+"的SFTP通道创建成功"); 69 | return session; 70 | 71 | } catch (JSchException e) { 72 | log.error("连接 "+ftpHost+":"+ftpPort+"的SFTP通道创建失败"); 73 | log.error(e.getMessage()); 74 | return null; 75 | } 76 | } 77 | private Channel getChannel() { 78 | if (null!=channel){ 79 | closeChannelOnly(); 80 | } 81 | session=getSession(); 82 | try { 83 | channel = session.openChannel("exec"); // 打开exec通道 84 | return channel; 85 | } catch (JSchException e) { 86 | log.error("连接 SFTP通道创建失败"); 87 | log.error(e.getMessage()); 88 | return null; 89 | } 90 | } 91 | 92 | /** 93 | * 关闭连接 94 | */ 95 | public void closeChannelOnly() { 96 | if (channel != null) { 97 | channel.disconnect(); 98 | channel=null; 99 | } 100 | } 101 | /** 102 | * 关闭连接 103 | */ 104 | public void closeChannel() { 105 | if (channel != null) { 106 | channel.disconnect(); 107 | channel=null; 108 | } 109 | if (session != null) { 110 | session.disconnect(); 111 | session=null; 112 | } 113 | } 114 | 115 | /** 116 | * 返回执行命令的内容 117 | * @param command 118 | * @return String 119 | */ 120 | public String execStr(String command) { 121 | Channel channel=getChannel(); 122 | String res=""; 123 | try { 124 | ((ChannelExec)channel).setCommand(command); 125 | InputStream in=channel.getInputStream(); 126 | channel.setInputStream(null); 127 | ((ChannelExec)channel).setErrStream(System.err); 128 | channel.connect(); 129 | res=FileUtil.readInputStreamToString(in, "UTF-8"); 130 | in=null; 131 | // log.info("命令:"+command+"执行完毕\n"); 132 | // log.info("命令执行结果为:\n"+res); 133 | } catch (IOException e) { 134 | log.error("命令:"+command+"执行异常"); 135 | log.error(e.getMessage()); 136 | } catch (JSchException e) { 137 | log.error("命令:"+command+"执行异常"); 138 | log.error(e.getMessage()); 139 | } 140 | return res; 141 | } 142 | 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/SftpFileUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | import java.io.InputStream; 4 | import java.util.Properties; 5 | 6 | 7 | import com.jcraft.jsch.Channel; 8 | import com.jcraft.jsch.ChannelSftp; 9 | import com.jcraft.jsch.JSch; 10 | import com.jcraft.jsch.JSchException; 11 | import com.jcraft.jsch.Session; 12 | import com.jcraft.jsch.SftpException; 13 | 14 | /** 15 | * 针对CentOS服务器的文件进行下载,重命名等操作 16 | * @author lianghui (lianghui@360.cn) 17 | */ 18 | public class SftpFileUtil { 19 | 20 | private static Session session = null; 21 | private static Channel channel = null; 22 | private LogUtil log=LogUtil.getLogger(SftpFileUtil.class);//日志记录 23 | /** 24 | * 主机host 25 | */ 26 | public String FTPHOST; 27 | /** 28 | * 端口 29 | */ 30 | public String PORT; 31 | /** 32 | * 用户名 33 | */ 34 | public String FTPUSERNAME; 35 | /** 36 | * 密码 37 | */ 38 | public String FTPPASSWORD; 39 | 40 | private ChannelSftp getChannel() { 41 | 42 | if (null!=channel) { 43 | closeChannelOnly(); 44 | } 45 | try { 46 | channel = getSession().openChannel("sftp"); // 打开SFTP通道 47 | channel.connect(); // 建立SFTP通道的连接 48 | // log.info("连接SFTP通道创建成功"); 49 | return (ChannelSftp) channel; 50 | 51 | } catch (JSchException e) { 52 | log.error("连接SFTP通道创建失败"); 53 | log.error(e.getMessage()); 54 | return null; 55 | } 56 | } 57 | 58 | private Session getSession() { 59 | 60 | if (null!=session) { 61 | return session; 62 | } 63 | 64 | 65 | int ftpPort = 21; 66 | if (PORT != null && !PORT.equals("")) { 67 | ftpPort = Integer.valueOf(PORT); 68 | } 69 | 70 | JSch jsch = new JSch(); // 创建JSch对象 71 | 72 | try { 73 | // 根据用户名,主机ip,端口获取一个Session对象 74 | session = jsch.getSession(FTPUSERNAME, FTPHOST, ftpPort); 75 | 76 | if (FTPPASSWORD != null) { 77 | session.setPassword(FTPPASSWORD); // 设置密码 78 | } 79 | Properties config = new Properties(); 80 | config.put("StrictHostKeyChecking", "no"); 81 | session.setConfig(config); // 为Session对象设置properties 82 | session.setTimeout(300000); // 设置timeout时间为5分钟 83 | session.connect(); // 通过Session建立链接 84 | return session; 85 | 86 | } catch (JSchException e) { 87 | log.error("连接 "+FTPHOST+":"+ftpPort+"的SFTP通道创建失败"); 88 | log.error(e.getMessage()); 89 | return null; 90 | } 91 | } 92 | 93 | /** 94 | * 关闭连接 95 | */ 96 | public void closeChannelOnly() { 97 | if (channel != null) { 98 | channel.disconnect(); 99 | channel=null; 100 | } 101 | } 102 | /** 103 | * 关闭连接 104 | */ 105 | public void closeChannel() { 106 | if (channel != null) { 107 | channel.disconnect(); 108 | channel = null; 109 | } 110 | if (session != null) { 111 | session.disconnect(); 112 | session = null; 113 | } 114 | } 115 | 116 | /** 117 | * 删除服务器上的文件 118 | * @param filepath 119 | * @return boolean 120 | */ 121 | public boolean delFile(String filepath) { 122 | boolean flag=false; 123 | ChannelSftp channel=getChannel(); 124 | try { 125 | channel.rm(filepath); 126 | log.info("删除文件"+filepath+"成功"); 127 | flag=true; 128 | } catch (SftpException e) { 129 | log.error("删除文件"+filepath+"失败"); 130 | log.error(e.getMessage()); 131 | }finally { 132 | //channel.quit(); 133 | 134 | } 135 | 136 | return flag; 137 | } 138 | 139 | /** 140 | * 删除指定目录,此目录必须为空的目录 141 | * @param directory 142 | * @return boolean 143 | */ 144 | public boolean delDir(String directory) { 145 | boolean flag=false; 146 | ChannelSftp channel=getChannel(); 147 | try { 148 | channel.rmdir(directory); 149 | log.info("删除目录:"+directory+"成功"); 150 | flag=true; 151 | } catch (SftpException e) { 152 | log.error("删除目录:"+directory+"失败"); 153 | log.error(e.getMessage()); 154 | }finally { 155 | //channel.quit(); 156 | } 157 | 158 | return flag; 159 | } 160 | 161 | /** 162 | * 文件重命名 163 | * @param oldpath 164 | * @param newpath 165 | * @return boolean 166 | */ 167 | public boolean rename(String oldpath,String newpath) { 168 | boolean flag=false; 169 | ChannelSftp channel=getChannel(); 170 | try { 171 | channel.rename(oldpath, newpath); 172 | log.info("重命名文件"+oldpath+"成功"); 173 | log.info("更新后的文件名为:"+newpath); 174 | flag=true; 175 | } catch (SftpException e) { 176 | log.error("重命名文件"+oldpath+"失败"); 177 | log.error(e.getMessage()); 178 | }finally { 179 | //channel.quit(); 180 | 181 | } 182 | 183 | return flag; 184 | } 185 | 186 | /** 187 | * 下载指定的文档内容,保存到指定位置,返回文件内容 188 | * @param filepath 189 | * @param savepath 190 | * @return String 191 | */ 192 | public String getFile(String filepath,String savepath) { 193 | String strtmp=null; 194 | InputStream input; 195 | ChannelSftp channel=getChannel(); 196 | try { 197 | input=channel.get(filepath); 198 | strtmp=FileUtil.readInputStreamToString(input, "UTF-8"); 199 | if (null!=savepath && savepath.length()>0) { 200 | FileUtil.writeString(strtmp, savepath, "UTF-8"); 201 | } 202 | // log.info("从文件"+filepath+"获取信息成功"); 203 | } catch (SftpException e) { 204 | log.error("从文件"+filepath+"获取信息失败"); 205 | log.error(e.getMessage()); 206 | }finally { 207 | // channel.quit(); 208 | } 209 | 210 | return strtmp; 211 | 212 | } 213 | 214 | /** 215 | * 下载指定的文档内容,保返回文件内容 216 | * @param filepath 217 | * @return String 218 | */ 219 | public String getFile(String filepath) { 220 | return getFile(filepath, null); 221 | } 222 | 223 | } 224 | -------------------------------------------------------------------------------- /src/main/java/com/github/qihootest/leo/toolkit/util/XmlUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit.util; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.TreeMap; 9 | import org.dom4j.Attribute; 10 | import org.dom4j.Document; 11 | import org.dom4j.DocumentException; 12 | import org.dom4j.DocumentHelper; 13 | import org.dom4j.Element; 14 | 15 | 16 | 17 | /** 18 | * XML文件解析处理 19 | * @author lianghui (lianghui@360.cn) 20 | */ 21 | public class XmlUtil { 22 | private TreeMap resultMap; 23 | private LogUtil log = LogUtil.getLogger(XmlUtil.class);// 日志记录 24 | 25 | public XmlUtil(){ 26 | resultMap = new TreeMap(); 27 | } 28 | /** 29 | * xml文本串解析为Map表 30 | * @param strXML 31 | * @return Map 32 | */ 33 | public Map fomatXMLToMap(String strXML) { 34 | try { 35 | Document doc = DocumentHelper.parseText(strXML); 36 | Element root = doc.getRootElement(); 37 | AttriToMap(root); //标签属性解析 38 | traverse(root); //标签属性解析,遍历 39 | Dom2Map(doc); //结构解析 40 | } catch (DocumentException e) { 41 | log.error(e.getMessage()); 42 | } 43 | return resultMap; 44 | } 45 | 46 | /** 47 | * 判断字符串是否为xml格式 48 | * @param str 49 | * @return boolean xml可解析则返回true 50 | */ 51 | public static boolean isXmlText(String str) { 52 | try { 53 | @SuppressWarnings("unused") 54 | Document doc = DocumentHelper.parseText(str); 55 | doc=null; 56 | return true; 57 | } catch (DocumentException e) { 58 | } 59 | return false; 60 | } 61 | /** 62 | * 标签属性解析 63 | * 64 | * @param e 65 | */ 66 | @SuppressWarnings("unchecked") 67 | private void AttriToMap(Element e) { 68 | List tempList = e.attributes(); 69 | for (int i = 0; i < tempList.size(); i++) { 70 | // 属性的取得 71 | Attribute item = tempList.get(i); 72 | putMap(resultMap, item.getName(), item.getValue()); 73 | // resultMap.put(item.getName(), item.getValue()); 74 | } 75 | 76 | } 77 | 78 | /** 79 | * 标签属性解析,遍历 80 | * 81 | * @param e 82 | */ 83 | @SuppressWarnings("unchecked") 84 | private void traverse(Element e) { 85 | List list = e.elements(); 86 | for (int i = 0; i < list.size(); i++) { 87 | Element iter = list.get(i); 88 | AttriToMap(iter); 89 | traverse(iter); 90 | } 91 | } 92 | 93 | @SuppressWarnings("unchecked") 94 | private void Dom2Map(Document doc) { 95 | if (doc == null) 96 | return; 97 | Element root = doc.getRootElement(); 98 | for (Iterator iterator = root.elementIterator(); iterator.hasNext();) { 99 | Element e = iterator.next(); 100 | List list = e.elements(); 101 | if (list.size() > 0) { 102 | Dom2Map(e); 103 | } else 104 | putMap(resultMap, e.getName(), e.getText()); 105 | // resultMap.put(e.getName(), e.getText()); 106 | } 107 | } 108 | 109 | @SuppressWarnings("unchecked") 110 | private void Dom2Map(Element e) { 111 | List list = e.elements(); 112 | if (list.size() > 0) { 113 | for (int i = 0; i < list.size(); i++) { 114 | Element iter = list.get(i); 115 | if (iter.elements().size() > 0) { 116 | Dom2Map(iter); 117 | } else { 118 | putMap(resultMap, iter.getName(), iter.getText()); 119 | // resultMap.put(iter.getName(), iter.getText()); 120 | } 121 | } 122 | } else { 123 | putMap(resultMap, e.getName(), e.getText()); 124 | // resultMap.put(e.getName(), e.getText()); 125 | } 126 | } 127 | 128 | /** 129 | * map增加key-value逻辑,如果已存在,则不覆盖,以arraylist存储 130 | * @param map 131 | * @param key 132 | * @param value 133 | */ 134 | 135 | private void putMap(TreeMapmap,String key,String value){ 136 | if(map.containsKey(key)){ //判断原始map中是否已存在重复key 137 | Object valueOld = map.get(key); 138 | if (map.get(key) instanceof ArrayList) { // 判断value是否已经为ArrayList,等二次发现有相同的key 139 | ((ArrayList) valueOld).add(value.trim()); 140 | map.put(key, valueOld); 141 | } else { // 第一次处理相同的key,new一个ArrayList 142 | ArrayList valueList = new ArrayList(); 143 | valueList.add(valueOld); 144 | valueList.add(value.trim()); 145 | map.put(key, valueList); 146 | } 147 | }else{ 148 | map.put(key, value); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/main/resources/IftConf.properties: -------------------------------------------------------------------------------- 1 | #接口测试--全局配置文件 2 | 3 | #http代理配置信息 4 | #是否启用代理 5 | ProxyEnable = N 6 | #代理IP 7 | ProxyIp = 127.0.0.1 8 | #代理端口 9 | ProxyPort = 8888 10 | #日期格式 11 | dateFormat = yyyMMddHHmmss 12 | -------------------------------------------------------------------------------- /src/main/resources/Template.ftl: -------------------------------------------------------------------------------- 1 | package ${javaInfo.packageName}; 2 | 3 | import java.util.ArrayList; 4 | import java.util.LinkedHashMap; 5 | import java.util.List; 6 | import org.testng.annotations.AfterTest; 7 | import org.testng.annotations.BeforeTest; 8 | import org.testng.annotations.Test; 9 | import com.github.qihootest.leo.ift.util.ExportReportExcel; 10 | import com.github.qihootest.leo.ift.testcase.IftTestCase; 11 | import com.github.qihootest.leo.ift.testcase.format.FormatCase; 12 | import com.github.qihootest.leo.ift.core.IFtResultInfo; 13 | import com.github.qihootest.leo.dispatch.log.TestngLog; 14 | 15 | import ${clsInfo.importInfo}; 16 | 17 | /** 18 | * 自动生成的测试用例 19 | * @author lianghui (lianghui@360.cn) 20 | * 21 | */ 22 | public class ${javaInfo.javaFileName} { 23 | 24 | private ${clsInfo.className} cau;//执行用例的类 25 | private String caseFilePath;//用例文件路径 26 | private String caseSheetName;//用例的Sheet名 27 | private String excelReportFilePath; //Excel测试报告输出目录 28 | private String excelReportName;//EXcel报告文件名 29 | private String excelReportSheetName;//Excel报告sheet名 30 | private List testCaseList ;//所有用例列表 31 | 32 | //记录预期值与实际值比对情况 33 | private List> compareResultList; 34 | 35 | //记录类名称 36 | private String classSimpleName; 37 | 38 | @BeforeTest 39 | public void beforeTest() { 40 | 41 | cau=new ${clsInfo.className}(); 42 | testCaseList=new ArrayList() ; 43 | caseFilePath="${javaInfo.caseDataPathName}"; 44 | caseSheetName="${javaInfo.caseDataSheetName}"; 45 | excelReportFilePath="${javaInfo.excelReportPath}"; 46 | excelReportName="${javaInfo.excelReportName}"; 47 | excelReportSheetName="${javaInfo.excelReportSheetName}"; 48 | compareResultList=new ArrayList>(); 49 | 50 | FormatCase formatcase=new FormatCase(); 51 | formatcase.FormatCaseFromObj(caseFilePath,caseSheetName); 52 | testCaseList=formatcase.getTestCase(); 53 | 54 | classSimpleName="${javaInfo.javaFileName}"; 55 | } 56 | //根据待执行用例列表,生成对应的测试用例java源码 57 | <#list javaInfo.allCase as testCase> 58 | @Test(description="${testCase.testPoint}()") 59 | public void ${testCase.caseId}(){ 60 | 61 | IftTestCase testCase=new IftTestCase(); 62 | testCase=testCaseList.get(${testCase_index}); 63 | LinkedHashMap result=new LinkedHashMap();//记录Excel测试报告 64 | IFtResultInfo iftResInfo=new IFtResultInfo(); 65 | String httpurl="";//记录请求发送的Url 66 | String expres="";//期望的结果 67 | String response="";//请求响应的返回字符串 68 | String actres="";//过滤后实际的结果 69 | boolean res=false;//记录比对结果 70 | 71 | 72 | //用例开始 73 | 74 | TestngLog.CaseStart("测试集:"+classSimpleName+"--的用例:"+testCase.getCaseMap().get("CaseID")+"--"+testCase.getCaseMap().get("TestPoint")); 75 | 76 | //发起http请求, 77 | iftResInfo=cau.${clsInfo.method}(testCase); 78 | 79 | //获取返回结果信息和发起的http信息 80 | response=iftResInfo.getResponseInfo().getResBodyInfo(); 81 | httpurl=iftResInfo.getResponseInfo().getHttpUrl(); 82 | 83 | //获取比对结果信息 84 | res=iftResInfo.getCompareRes(); 85 | actres=iftResInfo.getActRes(); 86 | expres=iftResInfo.getExpRes(); 87 | 88 | //记录执行结果到ArrayList,写Excel报告要用到 89 | result.put("CaseID", testCase.getCaseMap().get("CaseID")); 90 | result.put("TestPoint", testCase.getCaseMap().get("TestPoint")); 91 | result.put("ExpRes", expres); 92 | result.put("ActRes", actres); 93 | result.put("ResponseRes", response); 94 | result.put("Httpurl", httpurl); 95 | 96 | //比对结果 97 | if (res==true) { 98 | result.put("ExcResult", "Pass"); 99 | } 100 | else { 101 | result.put("ExcResult", "Fail"); 102 | } 103 | compareResultList.add(result); 104 | 105 | //写入TestNG日志 106 | TestngLog.Log("此用例预期结果为:"+expres); 107 | TestngLog.Log("此用例实际结果为:"+actres); 108 | TestngLog.Log("此用例请求返回的完整字符串为:"+response); 109 | TestngLog.Log("此用例发送的请求URL为:"+httpurl); 110 | TestngLog.Log("执行结果为:"+res); 111 | 112 | //用例结束 113 | TestngLog.CaseEnd("测试集:"+classSimpleName+"--的用例:"+testCase.getCaseMap().get("CaseID")+"--"+testCase.getCaseMap().get("TestPoint")); 114 | 115 | //比较结果记入TestNG断言中 116 | org.testng.Assert.assertTrue(res, "实际结果:"+actres+" -预期结果:"+expres); 117 | //org.testng.Assert.assertEquals(actres, expres,res); 118 | } 119 | 120 | 121 | @AfterTest 122 | public void afterTest() { 123 | //cau.closeConn(); 124 | //执行结果写入excel 125 | ExportReportExcel exportexcel = new ExportReportExcel(); 126 | exportexcel.CreatReportExcel(excelReportFilePath,excelReportName,excelReportSheetName,compareResultList); 127 | //记录到TestNG日志 128 | TestngLog.Log("所有用例执行完毕"); 129 | TestngLog.Log("共验证检查点数为:"+compareResultList.size()); 130 | TestngLog.Log("生成Excel测试报告:"+excelReportFilePath+excelReportName+".xlsx"+" 的sheet表--"+excelReportSheetName); 131 | //此测试套执行完毕记入TestNG日志 132 | TestngLog.Log("********************测试套:【"+classSimpleName+"】执行完毕**************************"); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | ###日志输出编码UTF-8### 2 | log4j.appender.logfile.encoding=UTF-8 3 | ### 保存的日志级别 ### 4 | log4j.rootLogger = INFO,INFO,ERROR,STDOUT 5 | #关闭控制台输出日志信息 恢复时可把此标识加到上面STDOUT 6 | 7 | ### 输出ERROR级别日志到控制台 ### 8 | log4j.appender.STDOUT = org.apache.log4j.ConsoleAppender 9 | log4j.appender.STDOUT.Target = System.out 10 | log4j.appender.STDOUT.layout = org.apache.log4j.PatternLayout 11 | log4j.appender.STDOUT.Threshold = ERROR 12 | log4j.appender.STDOUT.layout.ConversionPattern = [%5p] %c{1} - %m%n 13 | 14 | ### INFO日志保存 ### 15 | log4j.appender.INFO = org.apache.log4j.DailyRollingFileAppender 16 | #必须是具体的文件而不是文件夹 17 | log4j.appender.INFO.File = Leo//logs//info.log 18 | log4j.appender.INFO.Append = true 19 | log4j.appender.INFO.Threshold = INFO 20 | log4j.appender.INFO.layout = org.apache.log4j.PatternLayout 21 | log4j.appender.INFO.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [%5p] %c{1} - %m%n 22 | 23 | ### ERROR日志保存 ### 24 | log4j.appender.ERROR = org.apache.log4j.DailyRollingFileAppender 25 | #必须是具体的文件而不是文件夹 26 | log4j.appender.ERROR.File = Leo//logs//error.log 27 | log4j.appender.ERROR.Append = true 28 | log4j.appender.ERROR.Threshold = ERROR 29 | log4j.appender.ERROR.layout = org.apache.log4j.PatternLayout 30 | log4j.appender.ERROR.layout.ConversionPattern =%-d{yyyy-MM-dd HH:mm:ss} [%5p] %c{1} - %m%n -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/dispatch/TestDispatchConf.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.github.qihootest.leo.dispatch; 5 | 6 | /** 7 | * @author lianghui (lianghui@360.cn) 8 | * 9 | */ 10 | public class TestDispatchConf { 11 | 12 | /** 13 | * @param args 14 | */ 15 | public static void main(String[] args) { 16 | 17 | DispatchConf.writeConf(); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/dispatch/TestExecTask.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.github.qihootest.leo.dispatch.log.TestngLog; 7 | import com.github.qihootest.leo.dispatch.report.TestReport; 8 | import com.github.qihootest.leo.dispatch.run.TestRunInfo; 9 | import com.github.qihootest.leo.dispatch.testcase.ICase; 10 | import com.github.qihootest.leo.dispatch.testcase.JavaFileCase; 11 | 12 | 13 | public class TestExecTask { 14 | 15 | public void test2() { 16 | ExecTask exec = new ExecTask(); 17 | TestRunInfo runInfo = new TestRunInfo(); 18 | List caseList = new ArrayList<>();//用例列表 19 | 20 | runInfo.setTaskName("框架测试99999"); 21 | 22 | //java格式用例 23 | JavaFileCase jCase = new JavaFileCase(); 24 | jCase.addCase(TestngLog.class); 25 | caseList.add(jCase); 26 | 27 | runInfo.setCaseList(caseList); 28 | runInfo.setHtmlReportTitle("测试报告的标题"); 29 | exec.setRunInfo(runInfo); 30 | TestReport report=exec.Exec(); 31 | System.out.print("任务执行结果:"+report.getResMsg()+"\n"); 32 | if (report.getResNo()>-1) { 33 | System.out.print("任务名称:"+report.getTaskName()+"\n"); 34 | System.out.print("任务执行时间:"+report.getSumTime()+"毫秒\n"); 35 | System.out.print("Html报告:"+report.getHtmlReport()+"index.html\n"); 36 | System.out.print(report.getTngTestCountList().get(0).getSuiteName()); 37 | } 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/dispatch/TestTestngLog.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.dispatch; 2 | 3 | 4 | 5 | import com.github.qihootest.leo.dispatch.log.TestngLog; 6 | 7 | public class TestTestngLog { 8 | 9 | // @Test 10 | public void test(){ 11 | TestngLog.CaseStart("Tba框架--dispatch执行测试"); 12 | TestngLog.Log("执行测试"); 13 | TestngLog.CaseEnd("Tba框架--dispatch执行测试"); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/ift/core/CompareResultTest.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.ift.core; 2 | 3 | import org.testng.annotations.BeforeTest; 4 | import org.testng.annotations.DataProvider; 5 | import org.testng.annotations.Test; 6 | 7 | public class CompareResultTest { 8 | CompareResult compResult; 9 | 10 | @BeforeTest 11 | public void beforeTest() { 12 | compResult = new CompareResult(); 13 | } 14 | 15 | @DataProvider(name = "exp01") 16 | public Object[][] createData01(){ 17 | Object[][] retObjArr={{"views=18",true,"测试点:key=value预期结果与实际结果相等"},{"total_cost=10.01",false,"测试点:key=value预期结果与实际结果不相等"}}; 18 | return retObjArr; 19 | } 20 | 21 | @Test(description="普通的数据比较key=value",dataProvider = "exp01") 22 | public void CompareStrTest01(String expValue,boolean expResult,String mssage){ 23 | String actValue = "{\"errno\":0,\"data\":{\"clicks\":\"8\",\"views\":\"18\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"2\"}}"; 24 | boolean actres = compResult.getCompareResult(expValue, actValue,2); 25 | org.testng.Assert.assertTrue(expResult==actres, mssage); 26 | } 27 | 28 | @DataProvider(name = "exp02") 29 | public Object[][] createData02(){ 30 | Object[][] retObjArr={{"errno=0&clicks=8&total_cost=10.00",true,"测试点:多个键值对,且实际结果与预期结果相等"},{"errno=0&clicks=9&total_cost=10.00",false,"测试点:多个键值对,实际结果与预期结果不相同"}}; 31 | return retObjArr; 32 | } 33 | 34 | @Test(description="支持多个键值对的比对",dataProvider="exp02") 35 | public void CompareStrTest02(String expValue,boolean expResult,String msg){ 36 | String actValue = "{\"errno\":0,\"data\":{\"clicks\":\"8\",\"views\":\"18\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"2\"}}"; 37 | boolean actres = compResult.getCompareResult(expValue, actValue,2); 38 | org.testng.Assert.assertTrue(expResult==actres, msg); 39 | } 40 | 41 | @DataProvider(name="exp03") 42 | public Object[][] createData03(){ 43 | Object[][] retObjArr={{"errno=1#2#0",true,"测试点:预期结果与实际结果相等"},{"ckicks=7#9",false,"测试点:预期结果与实际结果不同"}}; 44 | return retObjArr; 45 | } 46 | 47 | @Test(description="支持一个key可能对应多个值",dataProvider="exp03") 48 | public void CompareStrTest03(String expValue,boolean expResult,String message){ 49 | String actValue = "{\"errno\":0,\"data\":{\"clicks\":\"8\",\"views\":\"18\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"2\"}}"; 50 | boolean actres = compResult.getCompareResult(expValue, actValue,2); 51 | org.testng.Assert.assertTrue(expResult==actres, message); 52 | } 53 | 54 | @DataProvider(name="exp04") 55 | public Object[][] createData04(){ 56 | // Object[][] retObjArr={{"item=3049732936^3049732168^3049738568^3083317320^3989263944",true},{"item=3049732936^3049732168",true}}; 57 | Object[][] retObjArr={{"item=[3049732936,3049732168,3049738568,3083317320,3989263944]",true,"测试点:对实际结果中全部值进行匹配,预期结果与实际结果相等"}, 58 | {"item=[3049732936,3049732168]",false,"测试点:预期结果中的值不全,预期结果与实际结果不符"},{"item=3049732168",true,"测试点:预期结果中只单个包含,预期结果与实际结果相同"}}; 59 | return retObjArr; 60 | } 61 | 62 | @Test(description="xml文件存在一个key对应多个值",dataProvider="exp04") 63 | public void CompareStrTest04(String expValue,boolean expResult,String msg){ 64 | String actValue = " " 65 | + "3049732936 3049732168 3049738568 3083317320 3989263944 " 66 | + " "; 67 | boolean actres = compResult.getCompareResult(expValue,actValue,2); 68 | org.testng.Assert.assertTrue(expResult==actres, msg); 69 | } 70 | 71 | @DataProvider(name="exp05") 72 | public Object[][] createData05(){ 73 | Object[][] retObjArr={{"clicks=int",true,"测试点:预期结果为int,符合要求"},{"errno=int",false,"测试点:预期结果为int但实际结果为0,0不包含在int范围内"}}; 74 | return retObjArr; 75 | } 76 | 77 | 78 | @Test(description="预期结果中0不包含在",dataProvider="exp05") 79 | public void CompareStrTest05(String expValue,boolean expResult,String msg){ 80 | String actValue = "{\"errno\":0,\"data\":[{\"clicks\":\"8\",\"views\":\"18\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"2\"}," 81 | + "{\"clicks\":\"7\",\"views\":\"16\",\"total_cost\":\"9.00\",\"ad_plan_id\":\"1\"}," 82 | + "{\"clicks\":\"9\",\"views\":\"19\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"3\"}]}"; 83 | boolean actres = compResult.getCompareResult(expValue, actValue,2); 84 | org.testng.Assert.assertTrue(expResult==actres); 85 | } 86 | 87 | @DataProvider(name = "exp10") 88 | public Object[][] createData() { 89 | Object[][] retObjArr = { { "clicks=[8,7,9]", true ,"测试点:json数组完全匹配"}, 90 | { "clicks=[8,9,8]", false,"测试点:json数组中部分值错误" }, { "click=[8,7]", false ,"测试点:json预期结果必须完全包含实际结果的值"}, 91 | { "clicks=9", true,"" } }; 92 | return (retObjArr); 93 | } 94 | 95 | @Test(description="实际结果为json数组,预期结果为数组",dataProvider = "exp10") 96 | public void CompareStrTest10(String expValue,boolean expResult,String msg){ 97 | // String expValue = "clicks=[8,7,9]"; //预期结果 98 | String actValue = "{\"errno\":0,\"data\":[{\"clicks\":\"8\",\"views\":\"18\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"2\"}," 99 | + "{\"clicks\":\"7\",\"views\":\"16\",\"total_cost\":\"9.00\",\"ad_plan_id\":\"1\"}," 100 | + "{\"clicks\":\"9\",\"views\":\"19\",\"total_cost\":\"10.00\",\"ad_plan_id\":\"3\"}]}"; 101 | boolean actres = compResult.getCompareResult(expValue,actValue,2); //实际结果 102 | 103 | org.testng.Assert.assertTrue(expResult==actres, "能正确匹配预期结果中的数组"); 104 | } 105 | 106 | 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/toolkit/TestDbunitUtil.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.github.qihootest.leo.toolkit; 5 | 6 | import com.github.qihootest.leo.ift.IftConf; 7 | import com.github.qihootest.leo.toolkit.dbunit.DbUnitUtil; 8 | import com.github.qihootest.leo.toolkit.mysql.ConnMysql; 9 | 10 | /** 11 | * @author lianghui (lianghui@360.cn) 12 | * 13 | */ 14 | public class TestDbunitUtil { 15 | 16 | /** 17 | * @param args 18 | */ 19 | public static void main(String[] args) { 20 | ConnMysql conn = new ConnMysql("127.0.0.1", "3306", "att", "auto", "auto"); 21 | DbUnitUtil.writeToFileFromMysql(IftConf.RootPath+"test.xml", conn, "select * from att_click_info;select * from att_task_info"); 22 | 23 | DbUnitUtil.writeToFileFromDataBase(IftConf.RootPath+"test.xls", DbUnitUtil.getDatabaseConnectionFromMysql(conn), "select * from att_click_info;select * from att_task_info"); 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/toolkit/TestMysqlUtil.java: -------------------------------------------------------------------------------- 1 | package com.github.qihootest.leo.toolkit; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.github.qihootest.leo.toolkit.mysql.MysqlUtil; 7 | import com.github.qihootest.leo.toolkit.mysql.dao.DaoUtil; 8 | import com.github.qihootest.leo.toolkit.mysql.dao.ITable; 9 | 10 | 11 | /** 12 | * @author lianghui (lianghui@360.cn) 13 | * 14 | */ 15 | public class TestMysqlUtil { 16 | 17 | public static void main(String args[]){ 18 | String ip1 = "106.120.162.231"; 19 | String port1 = "3302"; 20 | String dataName1 = "ad_dianjing07"; 21 | String userName1 = "qa_dj"; 22 | String passWord1 = "kY9RS12NvPXL"; 23 | 24 | String ip2 = "106.120.162.230"; 25 | String port2 = "3302"; 26 | String dataName2 = "ad_dianjing"; 27 | String userName2 = "qa_dj"; 28 | String passWord2 = "kY9RS12NvPXL"; 29 | 30 | String mysql01 = "update ad_group set status=1 where id=\"606379236\""; 31 | String mysql03 = "update ad_group set status=-1 where title=\"test\""; 32 | String mysql02 = "update ad_user_app set status= -1 where id =282"; 33 | 34 | 35 | 36 | MysqlUtil mysqlUtil1 = new MysqlUtil(); 37 | mysqlUtil1.connMysql(ip1, port1, dataName1, userName1, passWord1); 38 | mysqlUtil1.excSql(mysql01); 39 | mysqlUtil1.closedConn(); 40 | 41 | 42 | 43 | MysqlUtil mysqlUtil2 = new MysqlUtil(); 44 | mysqlUtil2.connMysql(ip2, port2, dataName2, userName2, passWord2); 45 | mysqlUtil2.excSql(mysql02); 46 | mysqlUtil2.closedConn(); 47 | // 48 | System.out.println("done!!!!!!!!!!!"); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/test/java/com/github/qihootest/leo/toolkit/att_click_info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.github.qihootest.leo.toolkit; 5 | 6 | import com.github.qihootest.leo.toolkit.mysql.dao.Table; 7 | 8 | /** 9 | * @author lianghui (lianghui@360.cn) 10 | * 11 | */ 12 | public class att_click_info extends Table{ 13 | private String id; 14 | private String url_id; 15 | private String ip; 16 | private String agent; 17 | private String create_time; 18 | private String desc; 19 | public String getId() { 20 | return id; 21 | } 22 | public void setId(String id) { 23 | this.id = id; 24 | } 25 | public String getUrl_id() { 26 | return url_id; 27 | } 28 | public void setUrl_id(String url_id) { 29 | this.url_id = url_id; 30 | } 31 | public String getIp() { 32 | return ip; 33 | } 34 | public void setIp(String ip) { 35 | this.ip = ip; 36 | } 37 | public String getAgent() { 38 | return agent; 39 | } 40 | public void setAgent(String agent) { 41 | this.agent = agent; 42 | } 43 | public String getCreate_time() { 44 | return create_time; 45 | } 46 | public void setCreate_time(String create_time) { 47 | this.create_time = create_time; 48 | } 49 | public String getDesc() { 50 | return desc; 51 | } 52 | public void setDesc(String desc) { 53 | this.desc = desc; 54 | } 55 | 56 | 57 | } 58 | --------------------------------------------------------------------------------