├── .DS_Store ├── .classpath ├── .project ├── .settings ├── .jsdtscope ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.m2e.core.prefs ├── org.eclipse.wst.common.component ├── org.eclipse.wst.common.project.facet.core.xml ├── org.eclipse.wst.jsdt.ui.superType.container ├── org.eclipse.wst.jsdt.ui.superType.name └── org.eclipse.wst.validation.prefs ├── README.md ├── ant-build-file └── build_mail_example.xml ├── logs └── .DS_Store ├── pom.xml ├── shell └── runcase.sh ├── src ├── .DS_Store └── test │ └── java │ ├── c3p0.properties │ ├── com │ └── weibo │ │ ├── cases │ │ ├── example │ │ │ └── ExampleTest.java │ │ └── suite │ │ │ ├── .DS_Store │ │ │ ├── ExampleTestSuite.java │ │ │ └── IntegrationExampleModuleTests.java │ │ ├── common │ │ ├── .DS_Store │ │ └── StatusCommon.java │ │ ├── global │ │ ├── Constant.java │ │ ├── HttpClientBase.java │ │ ├── JsonCommon.java │ │ ├── LogFormatter.java │ │ ├── ParseProperties.java │ │ └── TestLog.java │ │ ├── model │ │ ├── .DS_Store │ │ ├── Account.java │ │ └── Status.java │ │ ├── runfail │ │ ├── ClassThreadRunTest.java │ │ ├── ExecuteCases.java │ │ ├── FailCases.java │ │ ├── FailCasesAnt.java │ │ ├── FailCasesContext.java │ │ ├── NewFailCasesMvn.java │ │ ├── NewWriteLogMvn.java │ │ ├── RealClassMvn.java │ │ ├── Result.txt │ │ ├── RunFailedCases.java │ │ ├── ThreadRunTest.java │ │ ├── WriteLogAnt.java │ │ └── WriteLogFactory.java │ │ ├── runner │ │ ├── Concurrent.java │ │ ├── ConcurrentSuite.java │ │ ├── Retry.java │ │ ├── RetryRunner.java │ │ └── ThreadRunner.java │ │ └── userpool │ │ └── JdbcUtil.java │ ├── global.properties │ └── log4j.properties ├── target ├── .DS_Store ├── classes │ └── META-INF │ │ ├── MANIFEST.MF │ │ └── maven │ │ └── com.weibo │ │ └── WeTest │ │ ├── pom.properties │ │ └── pom.xml └── test-classes │ ├── c3p0.properties │ ├── com │ └── weibo │ │ ├── cases │ │ ├── example │ │ │ ├── ExampleTest.class │ │ │ └── ExampleTest.java │ │ └── suite │ │ │ ├── ExampleTestSuite.class │ │ │ ├── ExampleTestSuite.java │ │ │ ├── IntegrationExampleModuleTests.class │ │ │ └── IntegrationExampleModuleTests.java │ │ ├── common │ │ ├── StatusCommon.class │ │ └── StatusCommon.java │ │ ├── global │ │ ├── Constant.class │ │ ├── Constant.java │ │ ├── HttpClientBase.class │ │ ├── HttpClientBase.java │ │ ├── JsonCommon.class │ │ ├── JsonCommon.java │ │ ├── LogFormatter.class │ │ ├── LogFormatter.java │ │ ├── ParseProperties.class │ │ ├── ParseProperties.java │ │ ├── TestLog.class │ │ └── TestLog.java │ │ ├── model │ │ ├── Account.class │ │ ├── Account.java │ │ ├── Status.class │ │ └── Status.java │ │ ├── runfail │ │ ├── ClassThreadRunTest.class │ │ ├── ClassThreadRunTest.java │ │ ├── ExecuteCases.class │ │ ├── ExecuteCases.java │ │ ├── FailCases.class │ │ ├── FailCases.java │ │ ├── FailCasesAnt.class │ │ ├── FailCasesAnt.java │ │ ├── FailCasesContext.class │ │ ├── FailCasesContext.java │ │ ├── NewFailCasesMvn.class │ │ ├── NewFailCasesMvn.java │ │ ├── NewWriteLogMvn.class │ │ ├── NewWriteLogMvn.java │ │ ├── RealClassMvn.class │ │ ├── RealClassMvn.java │ │ ├── Result.txt │ │ ├── RunFailedCases.class │ │ ├── RunFailedCases.java │ │ ├── ThreadRunTest.class │ │ ├── ThreadRunTest.java │ │ ├── WriteLogAnt.class │ │ ├── WriteLogAnt.java │ │ ├── WriteLogFactory.class │ │ └── WriteLogFactory.java │ │ ├── runner │ │ ├── Concurrent.class │ │ ├── Concurrent.java │ │ ├── ConcurrentSuite$1.class │ │ ├── ConcurrentSuite$2$1.class │ │ ├── ConcurrentSuite$2.class │ │ ├── ConcurrentSuite$3.class │ │ ├── ConcurrentSuite.class │ │ ├── ConcurrentSuite.java │ │ ├── Retry.class │ │ ├── Retry.java │ │ ├── RetryRunner.class │ │ ├── RetryRunner.java │ │ ├── ThreadRunner$1.class │ │ ├── ThreadRunner$Test.class │ │ ├── ThreadRunner.class │ │ └── ThreadRunner.java │ │ └── userpool │ │ ├── JdbcUtil.class │ │ └── JdbcUtil.java │ ├── global.properties │ └── log4j.properties └── test-output └── .DS_Store /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/.DS_Store -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | WeTest 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/.jsdtscope: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/test/java=UTF-8 5 | encoding/=UTF-8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate 4 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.compliance=1.7 7 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 8 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 9 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 10 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 12 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 13 | org.eclipse.jdt.core.compiler.source=1.7 14 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.component: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.container: -------------------------------------------------------------------------------- 1 | org.eclipse.wst.jsdt.launching.baseBrowserLibrary -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.jsdt.ui.superType.name: -------------------------------------------------------------------------------- 1 | Window -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.validation.prefs: -------------------------------------------------------------------------------- 1 | disabled=06target 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### 一.简介 2 | ``` 3 | WeTest是处理API接口测试的轻量级自动化测试框架,java语言实现,拓展JUnit4开源框架,支持Ant/Maven执行方式。 4 | 5 | 工具特点: 6 | 7 | 1.支持suite,根据JUnit4测试类名正则匹配,聚合相同模块的用例,运行单个聚合类即可实现运行一个模块所有的用例; 8 | 2.支持测试类和方法级别用例并发执行,缩短执行时间(用例间需线程安全); 9 | 3.支持失败重试,包括执行中(@Retry注解)和结果跑完(根据Ant/Maven失败日志,扫失败日志,JUnitCore跑失败用例,多线程执行); 10 | 4.邮件通知结果。 11 | ``` 12 | #### 框架图: 13 | ![这里写图片描述](http://img.blog.csdn.net/20151028220329877) 14 | ### 二. 开发环境 15 | 16 | ``` 17 | Java IDE,JDK6以上,JUnit4,Mysql,Ant/maven,Svn。 18 | ``` 19 | ### 三.项目结构 20 | 21 | ``` 22 | 1.包com.weibo.cases.hugang,可以新建多个以模块或者以人的维度管理的用例集,测试用例放在该包下。 23 | 2.包com.weibo.cases.suite,聚合相同模块测试用例的聚合类。 24 | 3.包com.weibo.common,封装不同接口为特定方法。 25 | 5.包com.weibo.global,接口http请求(get或post),HttpClient实现;http请求返回的String反序列化成Javabean对象,Jackson实现。 26 | 6.包com.weibo.model, 接口返回的结果对应的Javabean类。 27 | 7.包com.weibo.runfail, 用例结束后,重跑失败用例。 28 | 8.包com.weibo.runner, 自定义的runner, @Retry(运行中重试),@ThreadRunner(单个类并发),@ConcurrentSuite(Suite类和方法级别)等。 29 | 9.包com.weibo.userpool, 用例中申请测试账号,JDBC实现。 30 | 31 | 配置文件: 32 | c3p0.properties 用户池数据库连接池配置, mysql地址,账号,密码;连接池最大,最小连接数。 33 | global.properties 测试环境设置,ip, port, appkey, retry默认设置。 34 | 35 | ``` 36 | 37 | ### 四.调度方式 38 | 39 | ``` 40 | 以shell脚本进行调度,根据不同模块,执行对应的build.xml; 41 | 在build_***.xml中指定测试模块,shell脚本会根据你的选择,ant执行不同的xml,达到运行某个模块的功能。 42 | 43 | 二期已经使用Taobao toast自动化测试框架二次开发,前端调度。 44 | http://blog.csdn.net/neven7/article/details/45022825 45 | http://blog.csdn.net/neven7/article/details/44886011 46 | 47 | ``` 48 | ### 五.测试用例填写规范 49 | 50 | ``` 51 | 1.每个用例使用 52 | try{ 53 | 用例; 54 | TestLogComment("用例描述"); 55 | }catch(Exception e){ 56 | fail("用例信息"); 57 | }finally{ 58 | 清关系等; 59 | } 60 | 结构;catch()能捕获非assertThat失败,如接口报错; finally里清try语句块构建的关系等; 61 | 2.每个用例之间不能有任何依赖,都是单独的; 62 | 3.每个测试Class名,后缀应该跟该相应模块相关,主要为聚合某一类功能,正则匹配用。 63 | ``` 64 | 65 | ### 六. 使用方法 66 | 67 | 68 | 团队成员,可以将自己添加的case上传到SVN上,协同工作。单个case可以直接在eclipse上运行。 69 | 对于自动化回归测试时,可以根据不同模块,执行对应的build.xml。 70 | 71 | 1 运行shell脚本,运行不同模块用例。 72 | 73 | ![这里写图片描述](http://img.blog.csdn.net/20150904154245930) 74 | 75 | 76 | 2 邮件推送运行结果,并将本次运行的失败日志作为附件发送,将失败日志放到com.weibo.runfail下,运行RunFailedCases.java重试。 77 | 78 | ![这里写图片描述](http://img.blog.csdn.net/20150904115617809) 79 | ![这里写图片描述](http://img.blog.csdn.net/20150904115526196) 80 | 81 | 82 | ### 七.WeTest Features 83 | ![这里写图片描述](http://img.blog.csdn.net/20151028220407942) 84 | ![这里写图片描述](http://img.blog.csdn.net/20151028220419965) 85 | ![这里写图片描述](http://img.blog.csdn.net/20151028220527721) 86 | ![这里写图片描述](http://img.blog.csdn.net/20151028220616281) 87 | ![这里写图片描述](http://img.blog.csdn.net/20151028220559296) 88 | ![这里写图片描述](http://img.blog.csdn.net/20151028220643007) 89 | ![这里写图片描述](http://img.blog.csdn.net/20151028220659487) 90 | ### 八. 流程图 91 | 92 | #### 1. 用例执行流程 93 | 94 | ![这里写图片描述](http://img.blog.csdn.net/20150904113558088) 95 | 96 | #### 2.用户池获取用户 97 | 98 | ![这里写图片描述](http://img.blog.csdn.net/20150904113751032) 99 | 100 | #### 3.接口调用流程 101 | 102 | ![这里写图片描述](http://img.blog.csdn.net/20150904113815022) 103 | 104 | #### 4.调度脚本流程 105 | 106 | ![这里写图片描述](http://img.blog.csdn.net/20150904113941095) 107 | 108 | #### 5.初始化流程 109 | 110 | ![这里写图片描述](http://img.blog.csdn.net/20150904113955968) 111 | 112 | 113 | 相关内容介绍: 114 | 115 | [JUnit结果重跑失败用例(支持Mvn和Ant)](http://blog.csdn.net/neven7/article/details/45221685) 116 | 117 | [JUnit4多线程执行测试用例](http://blog.csdn.net/neven7/article/details/45555687) 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /ant-build-file/build_mail_example.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /logs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/logs/.DS_Store -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.weibo 5 | WeTest 6 | 7 | 0.0.1 8 | WeTest Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 4.12 15 | test 16 | 17 | 18 | org.hamcrest 19 | hamcrest-core 20 | 1.3 21 | 22 | 23 | org.hamcrest 24 | hamcrest-all 25 | 1.3 26 | 27 | 28 | com.mchange 29 | c3p0 30 | 0.9.5 31 | 32 | 33 | org.hamcrest 34 | hamcrest-library 35 | 1.3 36 | 37 | 38 | mysql 39 | mysql-connector-java 40 | 5.1.34 41 | 42 | 43 | redis.clients 44 | jedis 45 | 2.7.2 46 | jar 47 | compile 48 | 49 | 50 | 51 | 52 | 53 | 54 | log4j 55 | log4j 56 | 1.2.14 57 | 58 | 59 | org.apache.httpcomponents 60 | httpclient 61 | 4.3.1 62 | 63 | 64 | 65 | org.apache.httpcomponents 66 | httpcore 67 | 4.3 68 | 69 | 70 | org.apache.httpcomponents 71 | httpmime 72 | 4.3.1 73 | 74 | 75 | org.apache.httpcomponents 76 | httpmime 77 | 4.3.1 78 | 79 | 80 | com.fasterxml.jackson.core 81 | jackson-core 82 | 2.2.3 83 | 84 | 85 | com.fasterxml.jackson.core 86 | jackson-annotations 87 | 2.2.3 88 | 89 | 90 | com.fasterxml.jackson.core 91 | jackson-databind 92 | 2.2.3 93 | 94 | 95 | 96 | org.json 97 | json 98 | 20090211 99 | 100 | 101 | 102 | net.sf.json-lib 103 | json-lib 104 | 2.4 105 | jdk15 106 | 107 | 108 | 109 | com.googlecode.json-simple 110 | json-simple 111 | 1.1.1 112 | 113 | 114 | 115 | ant 116 | ant 117 | 1.7.0 118 | 119 | 120 | 121 | org.apache.ant 122 | ant 123 | 1.9.4 124 | 125 | 126 | 127 | org.apache.ant 128 | ant-junit4 129 | 1.9.4 130 | 131 | 132 | 133 | ant-contrib 134 | ant-contrib 135 | 1.0b3 136 | 137 | 138 | 139 | commons-dbutils 140 | commons-dbutils 141 | 1.6 142 | 143 | 144 | 145 | io.takari.junit 146 | takari-cpsuite 147 | 1.2.7 148 | 149 | 150 | 151 | javax.servlet 152 | servlet-api 153 | 2.5 154 | provided 155 | 156 | 157 | 158 | 159 | commons-beanutils 160 | commons-beanutils 161 | 1.9.2 162 | 163 | 164 | commons-logging 165 | commons-logging 166 | 1.2 167 | 168 | 169 | 170 | 171 | 172 | 173 | 175 | org.apache.maven.plugins 176 | maven-surefire-plugin 177 | 2.19.1 178 | 179 | 180 | true 181 | true 182 | 183 | 184 | 185 | org.apache.maven.surefire 186 | surefire-junit47 187 | 2.19 188 | 189 | 190 | 191 | 192 | 194 | 195 | 196 | src/test/java 197 | 198 | 199 | 200 | WeTest 201 | 202 | 203 | 204 | 1.7 205 | 1.7 206 | UTF-8 207 | java 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /shell/runcase.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | #@hugang 3 | #读配置文件 4 | while read line;do 5 | eval "$line" 6 | done < ./conf/runcase.conf 7 | svn_account=$account 8 | svn_password=$password 9 | svn_project=$projectsvn 10 | path=$basepath 11 | 12 | 13 | 14 | 15 | #初始化 16 | function init() 17 | { 18 | #1.生成临时uuid目录 19 | uuid=`uuidgen` 20 | local_path=$path/$uuid 21 | echo $local_path 22 | sudo mkdir $local_path 23 | #2.拉代码到临时uuid目录 24 | svn co --username $svn_account --password $svn_password --no-auth-cache --non-interactive $projectsvn $local_path 25 | #3.修改工程中ip和port 26 | cat < $local_path/src/test/java/global.properties 27 | url=$ip:$port 28 | source= 29 | retry= 30 | end 31 | 32 | #4.拷贝*.xml到工程中 33 | projectpath=/data1/WeTest 34 | cp -rf $projectpath/antbuild/*.xml $local_path 35 | #5.进入uuid文件下 36 | cd $local_path 37 | } 38 | 39 | 40 | printf "******************************\n" 41 | printf "先选择测试环境,再选择测试模块\n" 42 | printf "******************************\n" 43 | 44 | printf "1.选择环境\n" 45 | #1.选择环境 46 | select word in "预览环境" "线上环境" "自定义环境" "退出" 47 | do 48 | case $word in 49 | "预览环境") 50 | ip= 51 | port= 52 | break; 53 | ;; 54 | "线上环境") 55 | ip= 56 | port= 57 | break; 58 | ;; 59 | "自定义环境") 60 | read -p "请输入IP: " ip 61 | read -p "请输入PORT: " port 62 | break; 63 | ;; 64 | "退出") 65 | printf "Bye\n" 66 | exit 67 | break; 68 | ;; 69 | *) 70 | printf "输入错误,请选1,2,3\n" 71 | ;; 72 | esac 73 | done; 74 | echo "word=$word" 75 | #2.选择模块 76 | printf "2.选择测试模块 \n" 77 | select word in "模块1" "模块2" "退出" 78 | do 79 | case $word in 80 | "模块1") 81 | init $ip $port 82 | ant -buildfile build_mail_status.xml & 83 | break; 84 | ;; 85 | "模块2") 86 | init $ip $port 87 | ant -buildfile build_mail_comment.xml & 88 | break; 89 | ;; 90 | 91 | "退出") 92 | printf "Bye\n" 93 | exit 94 | break; 95 | ;; 96 | *) 97 | printf "输入错误-请输入1-2\n" 98 | ;; 99 | esac 100 | done; 101 | 102 | exit 0 103 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/src/.DS_Store -------------------------------------------------------------------------------- /src/test/java/c3p0.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This file is detritus from various testing attempts 3 | # the values below may change, and often do not represent 4 | # reasonable values for the parameters. 5 | # 6 | 7 | c3p0.jdbcUrl=jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf-8 8 | c3p0.driverClass=com.mysql.jdbc.Driver 9 | c3p0.user=user 10 | c3p0.password=pwd 11 | 12 | 13 | 14 | 15 | c3p0.minPoolSize=500 16 | c3p0.maxPoolSize=1500 17 | 18 | #c3p0.maxStatements=0 19 | #c3p0.checkoutTimeout=18000 20 | 21 | 22 | 23 | #c3p0.numHelperThreads=6 24 | 25 | #c3p0.testConnectionOnCheckout=true 26 | #c3p0.testConnectionOnCheckin=true 27 | 28 | #c3p0.checkoutTimeout=2000 29 | #c3p0.idleConnectionTestPeriod=5 30 | #c3p0.maxConnectionAge=10 31 | #c3p0.maxIdleTime=2 32 | #c3p0.maxIdleTimeExcessConnections=1 33 | #c3p0.propertyCycle=1 34 | #c3p0.numHelperThreads=10 35 | #c3p0.unreturnedConnectionTimeout=15 36 | #c3p0.debugUnreturnedConnectionStackTraces=true 37 | #c3p0.maxStatements=30 38 | #c3p0.maxStatementsPerConnection=5 39 | #c3p0.maxAdministrativeTaskTime=3 40 | #c3p0.preferredTestQuery=SELECT 1 41 | #c3p0.preferredTestQuery=SELECT a FROM emptyyukyuk WHERE a = 5 42 | #c3p0.preferredTestQuery=SELECT a FROM testpbds WHERE a = 5 43 | #c3p0.usesTraditionalReflectiveProxies=true 44 | #c3p0.automaticTestTable=PoopyTestTable 45 | #c3p0.acquireIncrement=4 46 | #c3p0.acquireRetryDelay=1000 47 | #c3p0.acquireRetryAttempts=60 48 | #c3p0.connectionTesterClassName=com.mchange.v2.c3p0.test.AlwaysFailConnectionTester 49 | #c3p0.initialPoolSize=10 50 | com.mchange.v2.log.MLog=com.mchange.v2.log.log4j.Log4jMLog 51 | #com.mchange.v2.log.MLog=com.mchange.v2.log.jdk14logging.Jdk14MLog 52 | #com.mchange.v2.log.MLog=com.mchange.v2.log.FallbackMLog 53 | com.mchange.v2.log.NameTransformer=com.mchange.v2.log.PackageNames 54 | com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL=ALL 55 | 56 | #com.mchange.v2.c3p0.VMID=poop -------------------------------------------------------------------------------- /src/test/java/com/weibo/cases/example/ExampleTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.example; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | import static org.hamcrest.Matchers.is; 7 | 8 | public class ExampleTest { 9 | 10 | @Test 11 | public void testExampleOne() { 12 | try { 13 | // 构造场景 14 | assertThat("abc", is("abc")); 15 | 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | fail("testExampleOne excepiton"); 19 | } finally { 20 | // 清数据 21 | } 22 | } 23 | 24 | @Test 25 | public void testExampleTwo() { 26 | try { 27 | 28 | assertThat("abc", is("def")); 29 | 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | fail("testExampleTwo excepiton"); 33 | } finally { 34 | 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/cases/suite/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/src/test/java/com/weibo/cases/suite/.DS_Store -------------------------------------------------------------------------------- /src/test/java/com/weibo/cases/suite/ExampleTestSuite.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.suite; 2 | 3 | 4 | import org.junit.experimental.categories.Categories; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.Suite.SuiteClasses; 7 | 8 | @RunWith(Categories.class) 9 | @SuiteClasses( IntegrationExampleModuleTests.class ) 10 | public class ExampleTestSuite { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/cases/suite/IntegrationExampleModuleTests.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.suite; 2 | import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; 3 | import org.junit.runner.RunWith; 4 | 5 | import com.weibo.runner.Concurrent; 6 | import com.weibo.runner.ConcurrentSuite; 7 | 8 | @RunWith(ConcurrentSuite.class) 9 | @ClassnameFilters({"com.weibo.cases.example.*Test"}) 10 | @Concurrent 11 | public interface IntegrationExampleModuleTests { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/common/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/src/test/java/com/weibo/common/.DS_Store -------------------------------------------------------------------------------- /src/test/java/com/weibo/common/StatusCommon.java: -------------------------------------------------------------------------------- 1 | package com.weibo.common; 2 | 3 | import java.util.List; 4 | 5 | import org.junit.Ignore; 6 | 7 | import net.sf.json.JSONArray; 8 | import net.sf.json.JSONObject; 9 | 10 | import com.weibo.global.HttpClientBase; 11 | import com.weibo.global.JsonCommon; 12 | import com.weibo.model.Status; 13 | 14 | 15 | public class StatusCommon { 16 | Object status; 17 | Object statusCount; 18 | Object statuses; 19 | Object interest; 20 | Object lastTime; 21 | Object statusesIds; 22 | Object error; 23 | Object exposure; 24 | Object allowComment; 25 | Object userReadCount; 26 | Object darwinTags; 27 | HttpClientBase statusTest = new HttpClientBase(); 28 | String relativeurl; 29 | String statusInfo; 30 | Object objectList; 31 | Object midObject; 32 | Object StatusBean; 33 | Object recomm; 34 | Object getExposureTrigger; 35 | Object getSimilarity; 36 | Object atTimeline; 37 | Object readMetas; 38 | Object phototags; 39 | boolean flag; 40 | 41 | 42 | 43 | public Object commonResult(String statusInfo) throws Exception { 44 | // if (statusInfo.contains("error_code")) { 45 | // error = (ErrorInfo) JsonCommon.getJavabean(statusInfo, 46 | // ErrorInfo.class); 47 | // MbLogger.error(statusInfo, new ExceptionCommon(statusInfo)); 48 | // return error; 49 | // } else { 50 | status = (Status) JsonCommon.getJavabean(statusInfo, Status.class); 51 | return status; 52 | // } 53 | } 54 | 55 | 56 | 57 | /* 58 | * status feed (statuses/friends_timeline) 59 | * 60 | * @param username 61 | * 62 | * @param password 63 | * 64 | * @param parameters required 65 | * 66 | * @return 67 | * 68 | * @throws Exception 69 | */ 70 | public Object friendsTimeline_status(String username, String password, 71 | String parameters) throws Exception { 72 | relativeurl = "/2/statuses/friends_timeline.json"; 73 | statusInfo = statusTest.doGet(username, password, relativeurl, parameters); 74 | statuses = commonResult(statusInfo); 75 | return statuses; 76 | } 77 | 78 | 79 | public Object updateStatusPublic(String username, String password, 80 | String parameters) throws Exception { 81 | relativeurl = "/2/statuses/update.json"; 82 | if (parameters.isEmpty()) { 83 | parameters = "visible=0&status=test public "; 84 | } 85 | statusInfo = statusTest.doPost(username, password, relativeurl, 86 | parameters); 87 | status = commonResult(statusInfo); 88 | 89 | return status; 90 | } 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/Constant.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | public class Constant { 4 | public static final int FREESTATE = 0;//闲置用户帐号 5 | public static final int BUSYSTATE = 1;//占用用户帐号 6 | } 7 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/HttpClientBase.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.InputStream; 5 | import java.io.InputStreamReader; 6 | 7 | import net.sf.json.JSONObject; 8 | 9 | import org.apache.http.HttpEntity; 10 | import org.apache.http.HttpHost; 11 | import org.apache.http.auth.AuthScope; 12 | import org.apache.http.auth.UsernamePasswordCredentials; 13 | import org.apache.http.client.AuthCache; 14 | import org.apache.http.client.CredentialsProvider; 15 | import org.apache.http.client.methods.CloseableHttpResponse; 16 | import org.apache.http.client.methods.HttpGet; 17 | import org.apache.http.client.methods.HttpPost; 18 | import org.apache.http.client.protocol.HttpClientContext; 19 | import org.apache.http.entity.StringEntity; 20 | import org.apache.http.impl.auth.BasicScheme; 21 | import org.apache.http.impl.client.BasicAuthCache; 22 | import org.apache.http.impl.client.BasicCredentialsProvider; 23 | import org.apache.http.impl.client.CloseableHttpClient; 24 | import org.apache.http.impl.client.HttpClients; 25 | import org.apache.http.util.EntityUtils; 26 | 27 | 28 | 29 | public class HttpClientBase { 30 | private static final String HTTP = "http"; 31 | private static final String HTTPHEADER = "http://"; 32 | 33 | /** 34 | * 35 | * @param username 36 | * @param password 37 | * @param relativeurl 38 | * @return 39 | * @throws Exception 40 | */ 41 | public String doGet(String username, String password, String relativeurl, 42 | String parameters) 43 | throws Exception { 44 | if(relativeurl == null || relativeurl.equals("")) 45 | return null; 46 | if(parameters.indexOf("source=") < 0) { 47 | //parameters += "&source=" + ParseProperties.getSystemProperty("source"); 48 | parameters += "&source=*******"; 49 | } 50 | String url = HTTPHEADER + ParseProperties.getSystemProperty("host") + ":" + ParseProperties.getSystemProperty("port") + relativeurl + "?" + parameters; 51 | 52 | HttpGet httpget = new HttpGet(url); 53 | HttpHost targetHost = new HttpHost(httpget.getURI().getHost(), httpget.getURI().getPort(), HTTP); 54 | CredentialsProvider credsProvider = new BasicCredentialsProvider(); 55 | credsProvider.setCredentials(new AuthScope(targetHost.getHostName(),targetHost.getPort()), new UsernamePasswordCredentials(username, password)); 56 | CloseableHttpClient httpclient = HttpClients.custom() 57 | .setDefaultCredentialsProvider(credsProvider).build(); 58 | JSONObject json = null; 59 | String jsonstring = "", line = null; 60 | try { 61 | // Create AuthCache instance 62 | AuthCache authCache = new BasicAuthCache(); 63 | // Generate BASIC scheme object and add it to the local 64 | // auth cache 65 | BasicScheme basicAuth = new BasicScheme(); 66 | authCache.put(targetHost, basicAuth); 67 | // Add AuthCache to the execution context 68 | HttpClientContext localContext = HttpClientContext.create(); 69 | localContext.setAuthCache(authCache); 70 | for (int i = 0; i < 1; i++) { 71 | CloseableHttpResponse response = httpclient.execute(targetHost, 72 | httpget, localContext); 73 | try { 74 | HttpEntity entity = response.getEntity(); 75 | 76 | if (entity != null) { 77 | InputStream in = (InputStream) entity.getContent(); 78 | InputStreamReader ris = new InputStreamReader(in, 79 | "utf-8"); 80 | BufferedReader br = new BufferedReader(ris); 81 | 82 | while ((line = br.readLine()) != null) { 83 | jsonstring += line; 84 | } 85 | } 86 | EntityUtils.consume(entity); 87 | System.out.println("curl -u \"" + username+ ":" + password + "\" \"" + url + "\""); 88 | System.out.println(jsonstring); 89 | System.out.println("-----------------------------------------------"); 90 | } finally { 91 | response.close(); 92 | } 93 | } 94 | } finally { 95 | httpclient.close(); 96 | } 97 | return jsonstring; 98 | } 99 | 100 | /** 101 | * 102 | * @param username 103 | * @param password 104 | * @param relativeurl 105 | * @return 106 | * @throws Exception 107 | */ 108 | public static String doGet(String username, String password, String relativeurl, 109 | String parameters,String host) 110 | throws Exception { 111 | if(relativeurl == null || relativeurl.equals("")) 112 | return null; 113 | if(parameters.indexOf("source=") < 0) { 114 | //parameters += "&source=" + ParseProperties.getSystemProperty("source"); 115 | parameters += "&source="; 116 | } 117 | String url = HTTPHEADER +host + relativeurl + "?" + parameters; 118 | 119 | HttpGet httpget = new HttpGet(url); 120 | HttpHost targetHost = new HttpHost(httpget.getURI().getHost(), httpget 121 | .getURI().getPort(), HTTP); 122 | 123 | CredentialsProvider credsProvider = new BasicCredentialsProvider(); 124 | credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), 125 | targetHost.getPort()), new UsernamePasswordCredentials( 126 | username, password)); 127 | CloseableHttpClient httpclient = HttpClients.custom() 128 | .setDefaultCredentialsProvider(credsProvider).build(); 129 | JSONObject json = null; 130 | String jsonstring = "", line = null; 131 | try { 132 | // Create AuthCache instance 133 | AuthCache authCache = new BasicAuthCache(); 134 | // Generate BASIC scheme object and add it to the local 135 | // auth cache 136 | BasicScheme basicAuth = new BasicScheme(); 137 | authCache.put(targetHost, basicAuth); 138 | // Add AuthCache to the execution context 139 | HttpClientContext localContext = HttpClientContext.create(); 140 | localContext.setAuthCache(authCache); 141 | for (int i = 0; i < 1; i++) { 142 | CloseableHttpResponse response = httpclient.execute(targetHost, 143 | httpget, localContext); 144 | try { 145 | HttpEntity entity = response.getEntity(); 146 | 147 | if (entity != null) { 148 | InputStream in = (InputStream) entity.getContent(); 149 | InputStreamReader ris = new InputStreamReader(in, 150 | "utf-8"); 151 | BufferedReader br = new BufferedReader(ris); 152 | 153 | while ((line = br.readLine()) != null) { 154 | jsonstring += line; 155 | } 156 | } 157 | EntityUtils.consume(entity); 158 | System.out.println("curl -u \"" + username+ ":" + password + "\" \"" + url + "\""); 159 | System.out.println(jsonstring); 160 | System.out.println("-----------------------------------------------"); 161 | } finally { 162 | response.close(); 163 | } 164 | } 165 | } finally { 166 | httpclient.close(); 167 | } 168 | return jsonstring; 169 | } 170 | /** 171 | * 172 | * @param username 173 | * @param password 174 | * @param relativeurl 175 | * @param parameters:post参数 176 | * @return 177 | * @throws Exception 178 | */ 179 | public String doPost(String username, String password, String relativeurl, 180 | String parameters) throws Exception { 181 | if(relativeurl == null || relativeurl.equals("")) 182 | return null; 183 | String source = null; 184 | 185 | if(parameters.indexOf("source=") < 0 ){ 186 | source = "&source=" + ParseProperties.getSystemProperty("source"); 187 | } 188 | 189 | String localurl = HTTPHEADER + ParseProperties.getSystemProperty("host") + ":" + ParseProperties.getSystemProperty("port") + relativeurl + "?" + source; 190 | 191 | HttpPost httppost = new HttpPost(localurl); 192 | HttpHost targetHost = new HttpHost(httppost.getURI().getHost(), httppost 193 | .getURI().getPort(), HTTP); 194 | CredentialsProvider credsProvider = new BasicCredentialsProvider(); 195 | credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), 196 | targetHost.getPort()), new UsernamePasswordCredentials( 197 | username, password)); 198 | CloseableHttpClient httpclient = HttpClients.custom() 199 | .setDefaultCredentialsProvider(credsProvider).build(); 200 | String jsonstring = "", line = null; 201 | StringEntity reqEntity = new StringEntity(parameters,"UTF-8"); 202 | reqEntity.setContentType("application/x-www-form-urlencoded"); 203 | httppost.setEntity(reqEntity); 204 | try { 205 | // Create AuthCache instance 206 | AuthCache authCache = new BasicAuthCache(); 207 | // Generate BASIC scheme object and add it to the local 208 | // auth cache 209 | BasicScheme basicAuth = new BasicScheme(); 210 | authCache.put(targetHost, basicAuth); 211 | // Add AuthCache to the execution context 212 | HttpClientContext localContext = HttpClientContext.create(); 213 | localContext.setAuthCache(authCache); 214 | for (int i = 0; i < 1; i++) { 215 | CloseableHttpResponse response = httpclient.execute(targetHost, 216 | httppost, localContext); 217 | try { 218 | HttpEntity entity = response.getEntity(); 219 | 220 | if (entity != null) { 221 | InputStream in = (InputStream) entity.getContent(); 222 | InputStreamReader ris = new InputStreamReader(in, 223 | "utf-8"); 224 | BufferedReader br = new BufferedReader(ris); 225 | 226 | while ((line = br.readLine()) != null) { 227 | jsonstring += line; 228 | } 229 | 230 | } 231 | EntityUtils.consume(entity); 232 | System.out.println("curl -u \"" + username+ ":" + password + "\" \"" + localurl + "\" -d \"" + parameters + "\""); 233 | System.out.println(jsonstring); 234 | System.out 235 | .println("-----------------------------------------------"); 236 | } finally { 237 | response.close(); 238 | } 239 | } 240 | } finally { 241 | httpclient.close(); 242 | } 243 | return jsonstring; 244 | } 245 | /** 246 | * 247 | * @param username 248 | * @param password 249 | * @param relativeurl 250 | * @param parameters 251 | * @return 252 | * @throws Exception 253 | */ 254 | public String doPost(String username, String password, String relativeurl, 255 | String parameters,String hosts) throws Exception { 256 | if(relativeurl == null || relativeurl.equals("")) 257 | return null; 258 | String source = null; 259 | if(parameters.indexOf("source=") < 0) 260 | source = "&source=" + ParseProperties.getSystemProperty("source"); 261 | 262 | String localurl = HTTPHEADER + hosts + relativeurl + "?" + source; 263 | HttpPost httppost = new HttpPost(localurl); 264 | HttpHost targetHost = new HttpHost(httppost.getURI().getHost(), httppost 265 | .getURI().getPort(), HTTP); 266 | CredentialsProvider credsProvider = new BasicCredentialsProvider(); 267 | credsProvider.setCredentials(new AuthScope(targetHost.getHostName(), 268 | targetHost.getPort()), new UsernamePasswordCredentials( 269 | username, password)); 270 | CloseableHttpClient httpclient = HttpClients.custom() 271 | .setDefaultCredentialsProvider(credsProvider).build(); 272 | String jsonstring = "", line = null; 273 | StringEntity reqEntity = new StringEntity(parameters,"UTF-8"); 274 | reqEntity.setContentType("application/x-www-form-urlencoded"); 275 | httppost.setEntity(reqEntity); 276 | try { 277 | // Create AuthCache instance 278 | AuthCache authCache = new BasicAuthCache(); 279 | // Generate BASIC scheme object and add it to the local 280 | // auth cache 281 | BasicScheme basicAuth = new BasicScheme(); 282 | authCache.put(targetHost, basicAuth); 283 | // Add AuthCache to the execution context 284 | HttpClientContext localContext = HttpClientContext.create(); 285 | localContext.setAuthCache(authCache); 286 | for (int i = 0; i < 1; i++) { 287 | CloseableHttpResponse response = httpclient.execute(targetHost, 288 | httppost, localContext); 289 | try { 290 | HttpEntity entity = response.getEntity(); 291 | 292 | if (entity != null) { 293 | InputStream in = (InputStream) entity.getContent(); 294 | InputStreamReader ris = new InputStreamReader(in, 295 | "utf-8"); 296 | BufferedReader br = new BufferedReader(ris); 297 | 298 | while ((line = br.readLine()) != null) { 299 | jsonstring += line; 300 | } 301 | 302 | } 303 | EntityUtils.consume(entity); 304 | System.out.println("curl -u \"" + username+ ":" + password + "\" \"" + localurl + "\" -d \"" + parameters + "\""); 305 | System.out.println(jsonstring); 306 | System.out 307 | .println("-----------------------------------------------"); 308 | } finally { 309 | response.close(); 310 | } 311 | } 312 | } finally { 313 | httpclient.close(); 314 | } 315 | return jsonstring; 316 | } 317 | } 318 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/JsonCommon.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | 4 | import java.io.IOException; 5 | import java.util.Map; 6 | 7 | import com.fasterxml.jackson.annotation.JsonIgnore; 8 | import com.fasterxml.jackson.core.JsonParseException; 9 | import com.fasterxml.jackson.core.JsonParser.Feature; 10 | import com.fasterxml.jackson.databind.DeserializationFeature; 11 | import com.fasterxml.jackson.databind.JsonMappingException; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | 14 | 15 | //import com.alibaba.fastjson.JSON; 16 | 17 | public class JsonCommon { 18 | // jackSon 反序列化 java对象 19 | public static Object getJavabean(String jsonString, Class classes) 20 | throws JsonParseException, JsonMappingException, IOException { 21 | if (jsonString == null || jsonString.equals("") || classes == null) 22 | return null; 23 | ObjectMapper mapper = new ObjectMapper(); 24 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 25 | false); 26 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 27 | // System.out.println("---------------------------"+classes.getName()); 28 | Object myObject = mapper.readValue(jsonString, classes); 29 | return myObject; 30 | } 31 | 32 | /** @author yanlei3 33 | * write for the JSONobject with unset key 34 | */ 35 | public static Map getMap(String jsonString) 36 | throws JsonParseException, JsonMappingException, IOException { 37 | if (jsonString == null || jsonString.equals("")) 38 | return null; 39 | ObjectMapper mapper = new ObjectMapper(); 40 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 41 | false); 42 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 43 | // System.out.println("---------------------------"+classes.getName()); 44 | Map myMap = mapper.readValue(jsonString, Map.class); 45 | return myMap; 46 | } 47 | 48 | @JsonIgnore 49 | public static Object[] getJavabeans(String jsonString, Class classes) 50 | throws JsonParseException, JsonMappingException, IOException { 51 | if (jsonString == null || jsonString.equals("") || classes == null) 52 | return null; 53 | ObjectMapper mapper = new ObjectMapper(); 54 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 55 | false); 56 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 57 | Object[] myObject = (Object[]) mapper.readValue(jsonString, classes); 58 | return myObject; 59 | } 60 | 61 | ////使用fastjson 反序列为java 对象 62 | // @SuppressWarnings("unchecked") 63 | // public static Object getJavabean(String jsonString, @SuppressWarnings("rawtypes") Class classes) { 64 | // if (jsonString == null || jsonString.equals("") || classes == null) 65 | // return null; 66 | //// ObjectMapper mapper = new ObjectMapper(); 67 | //// mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 68 | //// false); 69 | //// mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 70 | //// // System.out.println("---------------------------"+classes.getName()); 71 | //// Object myObject = mapper.readValue(jsonString, classes); 72 | //// return myObject; 73 | // Object myObject = JSON.parseObject(jsonString, classes); 74 | // return myObject; 75 | // } 76 | // 77 | // @SuppressWarnings("unchecked") 78 | // @JsonIgnore 79 | // public static Object[] getJavabeans(String jsonString, @SuppressWarnings("rawtypes") Class classes) { 80 | // if (jsonString == null || jsonString.equals("") || classes == null) 81 | // return null; 82 | //// ObjectMapper mapper = new ObjectMapper(); 83 | //// mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 84 | //// false); 85 | //// mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 86 | // Object[] myObject = (Object[]) JSON.parseObject(jsonString, classes); 87 | // return myObject; 88 | // } 89 | 90 | 91 | public static String writeEntity2Json(Object object) throws IOException { 92 | String jsonResult = null; 93 | ObjectMapper objectMapper = new ObjectMapper(); 94 | jsonResult = objectMapper.writeValueAsString(object); 95 | return jsonResult; 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/LogFormatter.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | //import java.util.Date; 4 | import java.util.logging.Formatter; 5 | import java.util.logging.LogRecord; 6 | 7 | public class LogFormatter extends Formatter { 8 | @Override 9 | public String format(LogRecord record) { 10 | // Date date = new Date(); 11 | // String sDate = date.toString(); 12 | // return "[" + sDate + "]" + "[" + record.getLevel() + "]" 13 | // + record.getClass() + record.getMessage() + "\n"; 14 | return "[" + record.getMessage() + "]" + "\n"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/ParseProperties.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Properties; 6 | 7 | public class ParseProperties { 8 | 9 | private static final String SYSTEMPROPERTY = "../../../global.properties"; 10 | private static String HOST = null; 11 | private static String PORT = null; 12 | private static String SOURCE = null; 13 | // add retry 14 | private static String RETRY = null; 15 | 16 | private static Properties enc= null; 17 | private static InputStream ins = null; 18 | static { 19 | try { 20 | enc = new Properties(); 21 | ins = ParseProperties.class 22 | .getResourceAsStream(SYSTEMPROPERTY); 23 | enc.load(ins); 24 | HOST = enc.getProperty("host"); 25 | SOURCE = enc.getProperty("source"); 26 | PORT = enc.getProperty("port"); 27 | RETRY = enc.getProperty("retry"); 28 | 29 | } catch (Exception e) { 30 | throw new ExceptionInInitializerError(e); 31 | 32 | }finally 33 | { 34 | try { 35 | ins.close(); 36 | } catch (IOException e) { 37 | // TODO Auto-generated catch block 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | } 43 | 44 | /** 45 | * 根据属性文件和key得到属性的value 46 | * 47 | * @param fileRelativePath 48 | * @param propertyName 49 | * @return 50 | * @throws Exception 51 | */ 52 | public static String getProperty(String fileRelativePath, 53 | String propertyName) throws Exception { 54 | if (fileRelativePath == null || fileRelativePath.equals("") 55 | || propertyName == null || propertyName.equals("")) 56 | throw new Exception("传入参数为空!"); 57 | InputStream ins = ParseProperties.class 58 | .getResourceAsStream(fileRelativePath); 59 | if (ins == null) 60 | throw new Exception("系统配置文件global.peroperties文件不存在!"); 61 | Properties p = new Properties(); 62 | String value = ""; 63 | try { 64 | p.load(ins); 65 | value = p.getProperty(propertyName); 66 | } catch (Exception ex) { 67 | throw new Exception("读取属性文件异常"); 68 | } finally { 69 | ins.close(); 70 | } 71 | return value; 72 | 73 | } 74 | 75 | /** 76 | * 根据key得到系统属性的value 77 | * 78 | * @param propertyName 79 | * @throws Exception 80 | */ 81 | public static String getSystemProperty(String propertyName) 82 | throws Exception { 83 | if (propertyName == null || propertyName.equals("")) 84 | throw new Exception("传入参数为空!"); 85 | if(propertyName.equals("port")) 86 | return PORT; 87 | else if(propertyName.equals("host")) 88 | return HOST; 89 | else if(propertyName.equals("source")) 90 | return SOURCE; 91 | else if(propertyName.equals("retry")) 92 | return RETRY; 93 | return null; 94 | } 95 | 96 | public static void main(String args[]) { 97 | try { 98 | System.out.println("host======"+getSystemProperty("host")); 99 | System.out.println("port======"+getSystemProperty("port")); 100 | System.out.println("source===="+getSystemProperty("source")); 101 | System.out.println("retry====" + getSystemProperty("retry")); 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /src/test/java/com/weibo/global/TestLog.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | import java.util.logging.FileHandler; 6 | import java.util.logging.Formatter; 7 | import java.util.logging.Level; 8 | import java.util.logging.LogRecord; 9 | import java.util.logging.Logger; 10 | 11 | 12 | //import org.apache.log4j.Logger; 13 | //import org.apache.log4j.PropertyConfigurator; 14 | 15 | /* 16 | * 记录 测试步骤 17 | * @author hugang 18 | */ 19 | 20 | public class TestLog { 21 | 22 | public final static String PATH = "./logs/caseinfo.log"; 23 | public final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 24 | 25 | 26 | public static void Comment(String comment) { 27 | try { 28 | LOGGER.setLevel(Level.ALL); 29 | FileHandler fileHandler; 30 | fileHandler = new FileHandler(PATH); 31 | fileHandler.setLevel(Level.ALL); 32 | fileHandler.setFormatter(new LogFormatter()); 33 | LOGGER.addHandler(fileHandler); 34 | LOGGER.info(comment); 35 | } catch (SecurityException e) { 36 | // TODO Auto-generated catch block 37 | e.printStackTrace(); 38 | } catch (IOException e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } 42 | 43 | } 44 | } 45 | 46 | 47 | //public class TestLog { 48 | // 49 | // 50 | // public final static Logger LOGGER = Logger.getLogger(TestLog.class); 51 | // public final static String LOG4JPATH = ".../../../log4j.properties"; 52 | // 53 | // public static void Comment(String comment) { 54 | // try { 55 | // PropertyConfigurator.configure(LOG4JPATH); 56 | // LOGGER.info(comment); 57 | // } catch (SecurityException e) { 58 | // // TODO Auto-generated catch block 59 | // e.printStackTrace(); 60 | // } 61 | // 62 | // } 63 | //} 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/model/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/src/test/java/com/weibo/model/.DS_Store -------------------------------------------------------------------------------- /src/test/java/com/weibo/model/Account.java: -------------------------------------------------------------------------------- 1 | package com.weibo.model; 2 | 3 | public class Account { 4 | private long uid; 5 | private String screen_name; 6 | private String email; 7 | private int id; 8 | private String password; 9 | private int state; 10 | private String groupID; 11 | public long getUid() { 12 | return uid; 13 | } 14 | public void setUid(long uid) { 15 | this.uid = uid; 16 | } 17 | public String getScreen_name() { 18 | return screen_name; 19 | } 20 | public void setScreen_name(String screen_name) { 21 | this.screen_name = screen_name; 22 | } 23 | public String getEmail() { 24 | return email; 25 | } 26 | public void setEmail(String email) { 27 | this.email = email; 28 | } 29 | public int getId() { 30 | return id; 31 | } 32 | public void setId(int id) { 33 | this.id = id; 34 | } 35 | public String getPassword() { 36 | return password; 37 | } 38 | public void setPassword(String password) { 39 | this.password = password; 40 | } 41 | public int getState() { 42 | return state; 43 | } 44 | public void setState(int state) { 45 | this.state = state; 46 | } 47 | public String getGroupID() { 48 | return groupID; 49 | } 50 | public void setGroupID(String groupID) { 51 | this.groupID = groupID; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/model/Status.java: -------------------------------------------------------------------------------- 1 | package com.weibo.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 7 | 8 | @JsonIgnoreProperties(value = { "geo" }) 9 | public class Status { 10 | private String created_at; 11 | 12 | private long id; 13 | private long mid; 14 | private String idstr; 15 | private List pic_ids = new ArrayList(); 16 | 17 | public List getPic_ids() { 18 | return pic_ids; 19 | } 20 | 21 | public void setPic_ids(List pic_ids) { 22 | this.pic_ids = pic_ids; 23 | } 24 | 25 | int position; 26 | String mark; 27 | 28 | public int getPosition() { 29 | return position; 30 | } 31 | 32 | public void setPosition(int position) { 33 | this.position = position; 34 | } 35 | 36 | public String getMark() { 37 | return mark; 38 | } 39 | 40 | public void setMark(String mark) { 41 | this.mark = mark; 42 | } 43 | 44 | private String result; 45 | private int reposts_count; 46 | private int comments_count; 47 | private int attitudes_count; 48 | private int read_count; 49 | private int mlevel; 50 | 51 | private String cover_image; 52 | private int state; 53 | private String deleted; 54 | 55 | private boolean liked; 56 | private boolean truncated; 57 | 58 | private String rid; 59 | private int mblogtype; 60 | private String ctrlType; 61 | private List cmt_picids = new ArrayList(); 62 | private long uid; 63 | 64 | long expire_time; 65 | 66 | private int source_type; 67 | private int source_allowclick; 68 | private long original_mblog_read_count; 69 | private long original_article_read_count; 70 | private long original_status_count; 71 | private long original_article_count; 72 | private String type; 73 | private String text; 74 | private String pid; 75 | private String source; 76 | 77 | private boolean favorited; 78 | 79 | private String in_reply_to_status_id; 80 | 81 | private String in_reply_to_user_id; 82 | 83 | private String in_reply_to_screen_name; 84 | 85 | private String thumbnail_pic; 86 | 87 | private String bmiddle_pic; 88 | 89 | private String original_pic; 90 | 91 | private Status retweeted_status; 92 | 93 | public long getExpire_time() { 94 | return expire_time; 95 | } 96 | 97 | public void setExpire_time(long expire_time) { 98 | this.expire_time = expire_time; 99 | } 100 | 101 | public int getSource_type() { 102 | return source_type; 103 | } 104 | 105 | public void setSource_type(int source_type) { 106 | this.source_type = source_type; 107 | } 108 | 109 | public long getOriginal_mblog_read_count() { 110 | return original_mblog_read_count; 111 | } 112 | 113 | public void setOriginal_mblog_read_count(long original_mblog_read_count) { 114 | this.original_mblog_read_count = original_mblog_read_count; 115 | } 116 | 117 | public long getOriginal_article_read_count() { 118 | return original_article_read_count; 119 | } 120 | 121 | public void setOriginal_article_read_count(long original_article_read_count) { 122 | this.original_article_read_count = original_article_read_count; 123 | } 124 | 125 | public long getOriginal_status_count() { 126 | return original_status_count; 127 | } 128 | 129 | public void setOriginal_status_count(long original_status_count) { 130 | this.original_status_count = original_status_count; 131 | } 132 | 133 | public long getOriginal_article_count() { 134 | return original_article_count; 135 | } 136 | 137 | public void setOriginal_article_count(long original_article_count) { 138 | this.original_article_count = original_article_count; 139 | } 140 | 141 | public int getState() { 142 | return state; 143 | } 144 | 145 | public void setState(int state) { 146 | this.state = state; 147 | } 148 | 149 | public String getCover_image() { 150 | return cover_image; 151 | } 152 | 153 | public void setCover_image(String cover_image) { 154 | this.cover_image = cover_image; 155 | } 156 | 157 | public int getReposts_count() { 158 | return reposts_count; 159 | } 160 | 161 | public void setReposts_count(int reposts_count) { 162 | this.reposts_count = reposts_count; 163 | } 164 | 165 | public int getComments_count() { 166 | return comments_count; 167 | } 168 | 169 | public void setComments_count(int comments_count) { 170 | this.comments_count = comments_count; 171 | } 172 | 173 | public int getAttitudes_count() { 174 | return attitudes_count; 175 | } 176 | 177 | public void setAttitudes_count(int attitudes_count) { 178 | this.attitudes_count = attitudes_count; 179 | } 180 | 181 | public int getMlevel() { 182 | return mlevel; 183 | } 184 | 185 | public void setMlevel(int mlevel) { 186 | this.mlevel = mlevel; 187 | } 188 | 189 | public String getIdstr() { 190 | return idstr; 191 | } 192 | 193 | public void setIdstr(String idstr) { 194 | this.idstr = idstr; 195 | } 196 | 197 | public long getMid() { 198 | return mid; 199 | } 200 | 201 | public void setMid(long mid) { 202 | this.mid = mid; 203 | } 204 | 205 | public String getPid() { 206 | return pid; 207 | } 208 | 209 | public void setPid(String pid) { 210 | this.pid = pid; 211 | } 212 | 213 | public String getBmiddle_pic() { 214 | return bmiddle_pic; 215 | } 216 | 217 | public void setBmiddle_pic(String bmiddle_pic) { 218 | this.bmiddle_pic = bmiddle_pic; 219 | } 220 | 221 | public String getCreated_at() { 222 | return created_at; 223 | } 224 | 225 | public void setCreated_at(String created_at) { 226 | this.created_at = created_at; 227 | } 228 | 229 | public boolean isFavorited() { 230 | return favorited; 231 | } 232 | 233 | public void setFavorited(boolean favorited) { 234 | this.favorited = favorited; 235 | } 236 | 237 | public long getId() { 238 | return id; 239 | } 240 | 241 | public void setId(long id) { 242 | this.id = id; 243 | } 244 | 245 | public String getIn_reply_to_screen_name() { 246 | return in_reply_to_screen_name; 247 | } 248 | 249 | public void setIn_reply_to_screen_name(String in_reply_to_screen_name) { 250 | this.in_reply_to_screen_name = in_reply_to_screen_name; 251 | } 252 | 253 | public String getIn_reply_to_status_id() { 254 | return in_reply_to_status_id; 255 | } 256 | 257 | public void setIn_reply_to_status_id(String in_reply_to_status_id) { 258 | this.in_reply_to_status_id = in_reply_to_status_id; 259 | } 260 | 261 | public String getIn_reply_to_user_id() { 262 | return in_reply_to_user_id; 263 | } 264 | 265 | public void setIn_reply_to_user_id(String in_reply_to_user_id) { 266 | this.in_reply_to_user_id = in_reply_to_user_id; 267 | } 268 | 269 | public String getOriginal_pic() { 270 | return original_pic; 271 | } 272 | 273 | public void setOriginal_pic(String original_pic) { 274 | this.original_pic = original_pic; 275 | } 276 | 277 | public Status getRetweeted_status() { 278 | return retweeted_status; 279 | } 280 | 281 | public void setRetweeted_status(Status retweeted_status) { 282 | this.retweeted_status = retweeted_status; 283 | } 284 | 285 | public String getSource() { 286 | return source; 287 | } 288 | 289 | public void setSource(String source) { 290 | this.source = source; 291 | } 292 | 293 | public String getText() { 294 | return text; 295 | } 296 | 297 | public void setText(String text) { 298 | this.text = text; 299 | } 300 | 301 | public String getThumbnail_pic() { 302 | return thumbnail_pic; 303 | } 304 | 305 | public void setThumbnail_pic(String thumbnail_pic) { 306 | this.thumbnail_pic = thumbnail_pic; 307 | } 308 | 309 | public boolean isTruncated() { 310 | return truncated; 311 | } 312 | 313 | public void setTruncated(boolean truncated) { 314 | this.truncated = truncated; 315 | } 316 | 317 | public boolean isLiked() { 318 | return liked; 319 | } 320 | 321 | public void setLiked(boolean liked) { 322 | this.liked = liked; 323 | } 324 | 325 | public String getRid() { 326 | return rid; 327 | } 328 | 329 | public void setRid(String rid) { 330 | this.rid = rid; 331 | } 332 | 333 | public int getMblogtype() { 334 | return mblogtype; 335 | } 336 | 337 | public void setMblogtype(int mblogtype) { 338 | this.mblogtype = mblogtype; 339 | } 340 | 341 | public String getCtrlType() { 342 | return ctrlType; 343 | } 344 | 345 | public void setCtrlType(String ctrlType) { 346 | this.ctrlType = ctrlType; 347 | } 348 | 349 | public List getCmt_picids() { 350 | return cmt_picids; 351 | } 352 | 353 | public void setCmt_picids(List cmt_picids) { 354 | this.cmt_picids = cmt_picids; 355 | } 356 | 357 | public long getUid() { 358 | return uid; 359 | } 360 | 361 | public void setUid(long uid) { 362 | this.uid = uid; 363 | } 364 | 365 | public String getDeleted() { 366 | return deleted; 367 | } 368 | 369 | public void setDeleted(String deleted) { 370 | this.deleted = deleted; 371 | } 372 | 373 | public int getSource_allowclick() { 374 | return source_allowclick; 375 | } 376 | 377 | public void setSource_allowclick(int source_allowclick) { 378 | this.source_allowclick = source_allowclick; 379 | } 380 | 381 | public String getResult() { 382 | return result; 383 | } 384 | 385 | public void setResult(String result) { 386 | this.result = result; 387 | } 388 | 389 | 390 | 391 | 392 | 393 | public int getRead_count() { 394 | return read_count; 395 | } 396 | 397 | public void setRead_count(int read_count) { 398 | this.read_count = read_count; 399 | } 400 | 401 | public String getType() { 402 | return type; 403 | } 404 | 405 | public void setType(String type) { 406 | this.type = type; 407 | } 408 | 409 | } 410 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/ClassThreadRunTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | /** 4 | * @hugang 5 | */ 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.Callable; 11 | 12 | import org.junit.runner.JUnitCore; 13 | import org.junit.runner.Request; 14 | import org.junit.runner.Result; 15 | 16 | 17 | 18 | // 类并发执行,方法级别串行 19 | public class ClassThreadRunTest implements Callable> { 20 | 21 | 22 | Class testClass; 23 | List failMethod; 24 | 25 | // 类的方法集 结果,线程安全的List 26 | List singClassResult = Collections.synchronizedList(new ArrayList()); 27 | 28 | public ClassThreadRunTest(Class testClass, List failMethod){ 29 | this.testClass = testClass; 30 | this.failMethod = failMethod; 31 | } 32 | 33 | // 线程执行体 34 | public List call() { 35 | // TODO Auto-generated method stub 36 | // 一个类下顺序执行方法 37 | for(int i = 0; i < failMethod.size(); i++){ 38 | JUnitCore junitRunner = new JUnitCore(); 39 | Request request = Request.method(testClass, failMethod.get(i)); 40 | Result result = junitRunner.run(request); 41 | singClassResult.add(result); 42 | } 43 | return singClassResult; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/ExecuteCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.Future; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | import org.junit.runner.JUnitCore; 19 | import org.junit.runner.Request; 20 | import org.junit.runner.Result; 21 | 22 | 23 | /* 24 | * @author hugang 25 | */ 26 | public class ExecuteCases { 27 | // 线程池大小 28 | final static int THREADCOUNT = 50; 29 | 30 | public void writeResult(String resultPath, List methodsResult, 31 | int failNum, int successNum, int casesNum, long runTime, 32 | String logPath, String logType) throws IOException { 33 | String filePath = resultPath; 34 | File file = new File(filePath); 35 | if (file.exists()) { 36 | file.delete(); 37 | } 38 | if (!file.exists()) { 39 | file.createNewFile(); 40 | } 41 | FileOutputStream fop = new FileOutputStream(file); 42 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS"); 43 | fop.write("(一).Time's Result generated on: ".getBytes()); 44 | fop.write(sdf.format(new Date()).getBytes()); 45 | fop.write("\n".getBytes()); 46 | 47 | StringBuffer sb = new StringBuffer(); 48 | sb.append("(二).日志类型:" + logType); 49 | sb.append("\n"); 50 | sb.append("(三).日志名:" + logPath); 51 | sb.append("\n"); 52 | sb.append("===================== 结果集 ====================="); 53 | sb.append("\n"); 54 | sb.append("用例总数:" + casesNum); 55 | sb.append(", 成功数:" + successNum); 56 | sb.append(", 失败数:" + failNum); 57 | sb.append(", 运行时间:" + (runTime / 1000) / 60 + " 分钟 " + (runTime / 1000) 58 | % 60 + " 秒"); 59 | sb.append("\n"); 60 | sb.append("================================================="); 61 | sb.append("\n"); 62 | sb.append("\n"); 63 | fop.write(sb.toString().getBytes()); 64 | for (int j = 0; j < methodsResult.size(); j++) { 65 | // 将JUnitCore失败信息中的换行符去掉, harmcrest中断言是多行显示 66 | String LineFailStr = methodsResult.get(j).getFailures().toString().replaceAll("\n", ""); 67 | fop.write(LineFailStr.getBytes()); 68 | fop.write("\n".getBytes()); 69 | fop.write("\n".getBytes()); 70 | } 71 | // 输出结果mvn格式, 便于前端展示 72 | // Tests run: 5, Failures: 2, Errors: 0, Skipped: 0 73 | System.out.println("Tests run: " + casesNum + ", Failures: " + failNum + ", Errors: 0, Skipped: 0"); 74 | fop.flush(); 75 | fop.close(); 76 | } 77 | 78 | 79 | // 方法级别并发执行 80 | public void executorMethodCases(Map, List> failcasesMap, 81 | String logPath, String resultPath, String logType) 82 | throws ExecutionException, IOException { 83 | // 失败cases, key:Class, value:List of methods 84 | Map, List> runcaseMap; 85 | runcaseMap = failcasesMap; 86 | 87 | int failNum = 0; 88 | int successNum = 0; 89 | int casesNum = 0; 90 | long runTime = 0L; 91 | List methodsResult = new ArrayList(); 92 | 93 | // 线程池 94 | ExecutorService executorService = Executors 95 | .newFixedThreadPool(THREADCOUNT); 96 | // 存运行结果 97 | List> listFr = new ArrayList>(); 98 | long startTime = System.currentTimeMillis(); 99 | // 多线程执行用例 100 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 101 | Class testClass = entry.getKey(); 102 | List failMethod = entry.getValue(); 103 | casesNum += failMethod.size(); 104 | for (int i = 0; i < failMethod.size(); i++) { 105 | Future fr = executorService.submit(new ThreadRunTest( 106 | testClass, failMethod.get(i))); 107 | listFr.add(fr); 108 | } 109 | } 110 | // 记录结果 111 | for (Future fr : listFr) { 112 | try { 113 | while (!fr.isDone()) 114 | ; 115 | Result result = fr.get(); 116 | if (result.wasSuccessful()) { 117 | successNum++; 118 | } else { 119 | failNum++; 120 | methodsResult.add(result); 121 | } 122 | } catch (InterruptedException e) { 123 | e.printStackTrace(); 124 | } finally { 125 | executorService.shutdown(); 126 | } 127 | } 128 | long endTime = System.currentTimeMillis(); 129 | runTime = endTime - startTime; 130 | // 写结果日志 131 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 132 | runTime, logPath, logType); 133 | 134 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 135 | WriteLogFactory wlf = new WriteLogFactory(); 136 | wlf.writeLog(logPath, logType, resultPath); 137 | } 138 | 139 | // 类级别并发执行 140 | public void executorClassCases(Map, List> failcasesMap, 141 | String logPath, String resultPath, String logType) 142 | throws ExecutionException, IOException { 143 | // 失败cases, key:Class, value:List of methods 144 | Map, List> runcaseMap; 145 | runcaseMap = failcasesMap; 146 | 147 | int failNum = 0; 148 | int successNum = 0; 149 | int casesNum = 0; 150 | long runTime = 0L; 151 | List methodsResult = new ArrayList(); 152 | 153 | // 线程池 154 | // ExecutorService executorService = Executors 155 | // .newFixedThreadPool(THREADCOUNT); 156 | ExecutorService executorService = Executors.newCachedThreadPool(); 157 | // 存运行结果 158 | List>> listFr = new ArrayList>>(); 159 | long startTime = System.currentTimeMillis(); 160 | // 多线程执行用例 161 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 162 | Class testClass = entry.getKey(); 163 | List failMethod = entry.getValue(); 164 | casesNum += failMethod.size(); 165 | Future> fr = executorService 166 | .submit(new ClassThreadRunTest(testClass, failMethod)); 167 | listFr.add(fr); 168 | } 169 | // 记录结果 170 | for (Future> fr : listFr) { 171 | try { 172 | while (!fr.isDone()) 173 | ; 174 | // 单个类的结果 175 | List listResult = fr.get(); 176 | for (int i = 0; i < listResult.size(); i++) { 177 | if (listResult.get(i).wasSuccessful()) { 178 | successNum++; 179 | } else { 180 | failNum++; 181 | methodsResult.add(listResult.get(i)); 182 | } 183 | } 184 | 185 | } catch (InterruptedException e) { 186 | e.printStackTrace(); 187 | } finally { 188 | executorService.shutdown(); 189 | } 190 | } 191 | long endTime = System.currentTimeMillis(); 192 | runTime = endTime - startTime; 193 | // 写结果日志 194 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 195 | runTime, logPath, logType); 196 | 197 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 198 | WriteLogFactory wlf = new WriteLogFactory(); 199 | wlf.writeLog(logPath, logType, resultPath); 200 | 201 | } 202 | 203 | // 串行执行 204 | public void SerialExecutorCases(Map, List> failcasesMap, 205 | String logPath, String resultPath, String logType) 206 | throws ExecutionException, IOException { 207 | // 失败cases, key:Class, value:List of methods 208 | Map, List> runcaseMap; 209 | runcaseMap = failcasesMap; 210 | 211 | int failNum = 0; 212 | int successNum = 0; 213 | int casesNum = 0; 214 | long runTime = 0L; 215 | 216 | // 记录失败用例 217 | List methodsResult = new ArrayList(); 218 | 219 | // 存运行结果 220 | List listFr = new ArrayList(); 221 | long startTime = System.currentTimeMillis(); 222 | 223 | // 遍历执行用例 224 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 225 | Class testClass = entry.getKey(); 226 | List failMethod = entry.getValue(); 227 | casesNum += failMethod.size(); 228 | for (int i = 0; i < failMethod.size(); i++) { 229 | JUnitCore junitRunner = new JUnitCore(); 230 | Request request = Request.method(testClass, failMethod.get(i)); 231 | Result result = junitRunner.run(request); 232 | listFr.add(result); 233 | } 234 | } 235 | 236 | // 将失败用例添加到methodsResult, 并统计成功和失败数 237 | for (Result finResult : listFr) { 238 | if (finResult.wasSuccessful()) { 239 | ++successNum; 240 | } else { 241 | ++failNum; 242 | methodsResult.add(finResult); 243 | } 244 | } 245 | 246 | long endTime = System.currentTimeMillis(); 247 | runTime = endTime - startTime; 248 | // 写结果日志 249 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 250 | runTime, logPath, logType); 251 | 252 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 253 | WriteLogFactory wlf = new WriteLogFactory(); 254 | wlf.writeLog(logPath, logType, resultPath); 255 | 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/FailCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | /* 6 | * @author hugang 7 | */ 8 | public abstract class FailCases { 9 | public abstract Map, List> findFailedCases(String logPath); 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/FailCasesAnt.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.io.Reader; 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.Iterator; 12 | import java.util.LinkedHashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Set; 16 | import java.util.TreeSet; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | /* 24 | * @atuhor hugang 25 | */ 26 | public class FailCasesAnt extends FailCases { 27 | 28 | @Override 29 | public Map, List> findFailedCases(String logPath) { 30 | // TODO Auto-generated method stub 31 | // 文本每一行 32 | List strList = new ArrayList(); 33 | // 行号 34 | List flags = new ArrayList(); 35 | // 记录FAILED和ERROR 36 | Set failSet = new TreeSet(); 37 | // String regexStr = 38 | // "(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sFAILED)|(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sCaused\\san\\sERROR)"; 39 | Pattern p = Pattern.compile("Testcase"); 40 | Matcher m; 41 | int i = 0; 42 | 43 | try { 44 | Reader re = new FileReader(new File(logPath)); 45 | BufferedReader bre = new BufferedReader(re); 46 | while (bre.ready()) { 47 | String str = bre.readLine(); 48 | strList.add(str); 49 | m = p.matcher(str); 50 | // 匹配后,记录匹配的行号 51 | if (m.find()) { 52 | flags.add(i); 53 | System.out.println("find " + i); 54 | } 55 | i++; 56 | } 57 | for (int k = 0; k < flags.size(); k++) { 58 | // 去除SKIPPED, 只存 FAILED和ERROR 59 | if (!strList.get(flags.get(k)).contains("SKIPPED")) { 60 | // 从文本中取满足匹配的那行字符串 61 | failSet.add(strList.get(flags.get(k))); 62 | } 63 | } 64 | bre.close(); 65 | re.close(); 66 | } catch (IOException e) { 67 | // TODO Auto-generated catch block 68 | e.printStackTrace(); 69 | } 70 | 71 | System.out.println("找到失败用例数: " + failSet.size()); 72 | // 存失败用例 73 | Map, List> myClassMethodMap = new LinkedHashMap(); 74 | 75 | // JUnitCore执行结果中,形如这种结果,某个方法初始化失败直接抛错,“[com.weibo.cases.xiaoyu.FrontAppStatusesTest: 76 | // It should get success]” 77 | // 有“方法(类)”和“类”, 运行其类下所有方法,不让其方法(类)再进myClassMethodMap: 78 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 79 | // should create success] 80 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 81 | 82 | // 标记该类是否通过“类”记录到myClassMethodMap 83 | Map, Integer> bitMap = new LinkedHashMap(); 84 | 85 | List className = new ArrayList(); 86 | List methodName = new ArrayList(); 87 | 88 | for (Iterator it = failSet.iterator(); it.hasNext();) { 89 | // System.out.println(it.next().toString()); 90 | // Testcase: 91 | // testAPIRequest(com.weibo.cases.xuelian.FeedWithDarwinTagsForMovieStatusTest): 92 | // FAILED 93 | // 取出失败的行 94 | String str = it.next().toString(); 95 | 96 | 97 | // 先处理只有类信息的失败用例,执行该类所有方法(无法判断该方法是什么) 98 | // “[com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success]”格式的失败用例 99 | 100 | // 标记当个类 101 | Class singleFailClass = null; 102 | 103 | if (!str.contains("(")) { 104 | // ant 生成的单个类失败 105 | // 处理单个失败类,形如: 106 | // Testcase: 107 | // com.weibo.cases.xiaoyu.TopicFrontAddHasNewAndTopStatusTopicTest: 108 | // FAILED 109 | 110 | // JUnitCore生成的,单个类报错, 形如: 111 | // Testcase:[com.weibo.cases.xiaoyu.StatusTopicTest: null] 112 | 113 | List singleClassMethod = new ArrayList(); 114 | int singleClassLeft = 10; 115 | // 从singleClassLeft开始找 116 | int singleClassRight = str.indexOf(":", singleClassLeft); 117 | String singleFail = str.substring(singleClassLeft, 118 | singleClassRight); 119 | try { 120 | singleFailClass = Class.forName(singleFail); 121 | // 拿失败类中的方法 122 | Method[] met = singleFailClass.getMethods(); 123 | for (Method method : met) { 124 | // 只拿@Test 方法 125 | if (method.isAnnotationPresent(Test.class) 126 | && (!method.isAnnotationPresent(Ignore.class))) { 127 | // method.getName() 返回的格式:testLikeVideo 128 | System.out.println(method.getName()); 129 | singleClassMethod.add(method.getName()); 130 | } 131 | } 132 | // 将类下所有的用例放到myClassMethodMap下 133 | myClassMethodMap.put(singleFailClass, singleClassMethod); 134 | // 标记该类已通过“类”的方式进入失败用例集,无须进入“方法(类)”的方式进入失败用例集 135 | bitMap.put(singleFailClass, 1); 136 | } catch (ClassNotFoundException e) { 137 | // TODO Auto-generated catch block 138 | e.printStackTrace(); 139 | } 140 | 141 | } else { 142 | // Ant生成的正常失败信息 143 | // 形如 144 | // Testcase: 145 | // testStatusWangYiGCard(com.weibo.cases.xiaoyu.StatusMusicStatusTest): 146 | // FAILED 147 | // JUnitCore 生成的正常失败信息 148 | // Testcase:[testFriendsTimelineMuti(com.weibo.cases.xiaoyu.IsReadStatusTest): 149 | // expected:<{"3859449779315109":[1]}> but 150 | // was:<{"3859449779315109":[0]}>] 151 | // 方法(类) 152 | int classBegin = str.indexOf("("); 153 | int classEnd = str.indexOf(")"); 154 | // 类名 155 | String classPart = str.substring(classBegin + 1, classEnd); 156 | // 方法名,起始位置为10(固定) 157 | int beginFind = 10; 158 | String methodPart = str.substring(beginFind, classBegin); 159 | 160 | Class failClass = null; 161 | try { 162 | failClass = Class.forName(classPart); 163 | // 判断该类是否已通过“类”的方式进入错误用例集,不存在,则以“方法(类)”处理 164 | if(!bitMap.containsKey(failClass)){ 165 | // 聚合 class-method 一对多 166 | if (myClassMethodMap.containsKey(failClass)) { 167 | // 拿到之前的class 对应的list, 并在该list下新增 method, 再放回map 168 | List beforeFailMethod = myClassMethodMap 169 | .get(failClass); 170 | beforeFailMethod.add(methodPart); 171 | myClassMethodMap.put(failClass, beforeFailMethod); 172 | } else { 173 | // 第一次添加该class时 174 | List firstMethod = new ArrayList(); 175 | firstMethod.add(methodPart); 176 | myClassMethodMap.put(failClass, firstMethod); 177 | } 178 | } 179 | 180 | } catch (ClassNotFoundException e) { 181 | // TODO Auto-generated catch block 182 | e.printStackTrace(); 183 | } 184 | } 185 | 186 | 187 | } 188 | return myClassMethodMap; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/FailCasesContext.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | /* 6 | * @author hugang 7 | */ 8 | public class FailCasesContext { 9 | FailCases fc = null; 10 | 11 | // 简单工厂模式和策略模式, 根据type声明,实例化不同实例 12 | public FailCasesContext(String type) { 13 | // 为了支持JDK6 , case后用数字; JDK7可以直接String类型 14 | // 默认为2, ant 15 | int typeNum =2; 16 | if("MVN".equals(type)){ 17 | typeNum = 1; 18 | }else if("ANT".equals(type)){ 19 | typeNum = 2; 20 | } 21 | switch (typeNum) { 22 | case 1: 23 | // FailCasesMvn fcm = new FailCasesMvn(); 24 | // 重构匹配mvn test 25 | NewFailCasesMvn fcm = new NewFailCasesMvn(); 26 | fc = fcm; 27 | break; 28 | case 2: 29 | FailCasesAnt fca = new FailCasesAnt(); 30 | fc = fca; 31 | break; 32 | } 33 | } 34 | 35 | public Map,List> getFailCases(String logPath) { 36 | return fc.findFailedCases(logPath); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/NewFailCasesMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.io.Reader; 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.HashSet; 13 | import java.util.LinkedHashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Set; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | 24 | /* 25 | *
 26 |  * 正则匹配出失败用例,maven-surefire-customresult自定义输出格式
 27 |  * 
 28 |  * CustomResult Fail@后面
 29 |  * 
 30 |  * CustomResult Error@后面
 31 |  * 
 32 |  * 1) 后面带(),com.weibo.cases.wanglei16.PublicMentionsStatusTest.testFilterType(com.weibo.cases.wanglei16.PublicMentionsStatusTest)
 33 |  * 2)后面不带(),com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest.com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest
 34 |  * 
 35 |  * 
 36 |  * 
37 | * 38 | * 39 | * @author hugang 40 | */ 41 | public class NewFailCasesMvn extends FailCases { 42 | 43 | // 找出所有失败用例 每行字符串信息 44 | public Set failCasesStr(String logPath){ 45 | String failRegex = "^CustomResult Fail@(.*)"; 46 | Pattern failPattern = Pattern.compile(failRegex); 47 | Matcher matchFail; 48 | 49 | String errorRegex = "^CustomResult Error@(.*)"; 50 | Pattern errorPattern = Pattern.compile(errorRegex); 51 | Matcher matchError; 52 | 53 | // 去掉重复的 54 | Set failSet = new HashSet(); 55 | 56 | try (BufferedReader bre = new BufferedReader(new FileReader(new File(logPath)));){ 57 | while (bre.ready()) { 58 | String str = bre.readLine(); 59 | matchFail = failPattern.matcher(str); 60 | matchError = errorPattern.matcher(str); 61 | if(matchFail.matches() || matchError.matches()){ 62 | failSet.add(str); 63 | } 64 | } 65 | } catch (IOException e) { 66 | // TODO Auto-generated catch block 67 | e.printStackTrace(); 68 | } 69 | return failSet; 70 | } 71 | 72 | // 处理字符串信息, 将信息转换成Map 73 | public Map, List> getResultMap(Set failSet) { 74 | Map, List> resultMap = new LinkedHashMap, List>(); 75 | String className; 76 | List methodList = new ArrayList(); 77 | Class failClass = null; 78 | // 标记Class是否将全部方法放入Map中 79 | Map, Integer> bitMap = new HashMap, Integer>(); 80 | for(String str : failSet){ 81 | // 先处理不带(), 表示整个类失败 82 | if( ! str.contains("(")){ 83 | className = str.substring(str.lastIndexOf("com"), str.length()); 84 | try { 85 | failClass = Class.forName(className); 86 | } catch (ClassNotFoundException e) { 87 | // TODO Auto-generated catch block 88 | e.printStackTrace(); 89 | } 90 | // 拿失败类中的方法 91 | Method[] met = failClass.getMethods(); 92 | for (Method method : met) { 93 | // 只拿@Test 方法 94 | if (method.isAnnotationPresent(Test.class) 95 | && (!method 96 | .isAnnotationPresent(Ignore.class))) { 97 | // method.getName() 返回的格式:testLikeVideo 98 | System.out.println(method.getName()); 99 | methodList.add(method.getName()); 100 | } 101 | } 102 | resultMap.put(failClass, methodList); 103 | bitMap.put(failClass, 1); 104 | }else{ 105 | // 处理单个测试方法 106 | className = str.substring(str.indexOf("(") + 1, str.length() - 1); 107 | try { 108 | failClass = Class.forName(className); 109 | } catch (ClassNotFoundException e) { 110 | // TODO Auto-generated catch block 111 | e.printStackTrace(); 112 | } 113 | 114 | // 之后支持 添加JUnitCore格式 115 | int last = str.indexOf("("); 116 | String methodPart = str.substring(str.lastIndexOf(".", last) + 1, last); 117 | 118 | 119 | // 判断该类是否已通过“类”的方式进入错误用例集,不存在,则以“方法(类)”处理 120 | if(!bitMap.containsKey(failClass)){ 121 | // 聚合 class-method 一对多 122 | if (resultMap.containsKey(failClass)) { 123 | // 拿到之前的class 对应的list, 并在该list下新增 method, 再放回map 124 | List beforeFailMethod = resultMap 125 | .get(failClass); 126 | beforeFailMethod.add(methodPart); 127 | resultMap.put(failClass, beforeFailMethod); 128 | } else { 129 | // 第一次添加该class时 130 | List firstMethod = new ArrayList(); 131 | firstMethod.add(methodPart); 132 | resultMap.put(failClass, firstMethod); 133 | } 134 | } 135 | } 136 | } 137 | 138 | int casesNum = 0; 139 | List myMethod = new ArrayList(); 140 | for(Map.Entry, List> myCases: resultMap.entrySet()){ 141 | 142 | myMethod = myCases.getValue(); 143 | casesNum += myMethod.size(); 144 | System.out.println(myCases.getKey() + ":" + myMethod + ":" + myMethod.size() ); 145 | } 146 | System.out.println("mvn 找到用例数:" + casesNum); 147 | return resultMap; 148 | } 149 | 150 | @Override 151 | public Map, List> findFailedCases(String logPath) { 152 | return getResultMap(failCasesStr(logPath)); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/NewWriteLogMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.List; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | /* 17 | * 将JUnitCore执行结果,回写到源日志 18 | * author hugang 19 | */ 20 | public class NewWriteLogMvn { 21 | 22 | 23 | // 格式转换,将JUnitCore装换成Mvn 24 | public List FormatJUnitCoreToMvn(List failStr){ 25 | List mvnFailList = new ArrayList(); 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | return mvnFailList; 34 | } 35 | 36 | 37 | 38 | public void writeLogMvn(String logPath, String resultPath) 39 | throws IOException { 40 | BufferedWriter writer; 41 | BufferedReader reader; 42 | 43 | // 日志文件 44 | File sourceFile = new File(logPath); 45 | if (!sourceFile.exists()) { 46 | sourceFile.createNewFile(); 47 | } 48 | writer = new BufferedWriter(new FileWriter(sourceFile)); 49 | 50 | // 结果日志 51 | File readFile = new File(resultPath); 52 | if (!readFile.exists()) { 53 | readFile.createNewFile(); 54 | System.out.println("read 文件不存在, Result.txt 不存在"); 55 | } else { 56 | System.out.println("" + readFile.canRead() + " " 57 | + readFile.length() + " " + readFile.getAbsolutePath() 58 | + " " + readFile.getCanonicalPath()); 59 | } 60 | reader = new BufferedReader(new FileReader(readFile)); 61 | 62 | // 1 63 | // 根据Result.txt , 正则表达式找失败用例 64 | // 形如 方法(类) 格式 65 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 66 | // should create success] 67 | String pattern = "\\[(\\w+)\\((.*)\\):(.*)\\]"; 68 | Pattern pt = Pattern.compile(pattern); 69 | Matcher mt; 70 | 71 | List strList = new ArrayList(); 72 | 73 | // 2 74 | // 根据Result.txt , 正则表达式找失败用例(只提供失败类信息) 75 | // 形如: 76 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 77 | String patternClass = "\\[((\\w+\\.)+(\\w+)):(.*)\\]"; 78 | Pattern ptClass = Pattern.compile(patternClass); 79 | Matcher mtClass; 80 | 81 | // 行号 82 | List flags = new ArrayList(); 83 | int i = 0; 84 | 85 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 86 | 87 | writer.write(sdf.format(new Date())); 88 | writer.write("mvn 回写失败结果"); 89 | writer.newLine(); 90 | 91 | String failStackTrace = "CustomResult Failed StackTrace@"; 92 | String failInfo = "CustomResult Fail@"; 93 | String failMethodStackTraceStr; 94 | String failMethodInfoStr; 95 | 96 | String failClassStackTraceStr; 97 | String failClassInfoStr; 98 | try { 99 | while (reader.ready()) { 100 | String str = reader.readLine(); 101 | strList.add(str); 102 | mt = pt.matcher(str); 103 | mtClass = ptClass.matcher(str); 104 | // 匹配1后,记录匹配的行号 105 | if (mt.find()) { 106 | String[] className = mt.group(2).split("\\."); 107 | int size = className.length; 108 | String methodName = mt.group(1); 109 | // 模拟MVN 日志 110 | // 1.错误栈信息,供前端解析 111 | // CustomResult Failed StackTrace@SassPart2ShortUrlStatusTest.testPublicRepost:88 testPublicRepost exception 112 | failMethodStackTraceStr = failStackTrace + className[size - 1] + "." 113 | + methodName + mt.group(3).replaceAll("\n", ""); 114 | // 2.用例信息 115 | // CustomResult Fail@com.weibo.cases.wanglei16.SassPart2ShortUrlStatusTest.testPublicRepost(com.weibo.cases.wanglei16.SassPart2ShortUrlStatusTest) 116 | failMethodInfoStr = failInfo + mt.group(2) + "." + methodName + "(" + mt.group(2) + ")"; 117 | writer.write(failMethodStackTraceStr); 118 | // 供前端解析 119 | System.out.println(failMethodStackTraceStr); 120 | writer.newLine(); 121 | writer.write(failMethodInfoStr); 122 | writer.newLine(); 123 | i++; 124 | } 125 | // 类失败 126 | if (mtClass.find()) { 127 | // 模拟MVN 日志 128 | // 1.错误栈信息, group(1) 全限类名, group(4)栈信息 129 | failClassStackTraceStr = failStackTrace + mtClass.group(1) + " " + mtClass.group(4).replaceAll("\n", ""); 130 | // com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest.com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest 131 | failClassInfoStr = failInfo + mtClass.group(1) + "." + mtClass.group(1); 132 | writer.write(failClassStackTraceStr); 133 | // 供前端解析 134 | System.out.println(failClassStackTraceStr); 135 | writer.newLine(); 136 | writer.write(failClassInfoStr); 137 | writer.newLine(); 138 | i++; 139 | } 140 | } 141 | 142 | } finally { 143 | writer.close(); 144 | reader.close(); 145 | 146 | } 147 | 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/RealClassMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | /* 3 | * @author hugang 4 | */ 5 | public class RealClassMvn { 6 | String[] packageName = { 7 | "com.weibo.cases.hugang", "com.weibo.cases.lingna", "com.weibo.cases.maincase", 8 | "com.weibo.cases.qiaoli", "com.weibo.cases.wanglei16", "com.weibo.cases.xiaoyu", 9 | "com.weibo.cases.xuelian", "com.weibo.cases.beibei12", "com.weibo.cases.publicservice", 10 | "com.weibo.cases.yanlei3", "com.weibo.cases.guanglu" 11 | }; 12 | 13 | int now = 0; 14 | int retryNum = packageName.length; 15 | 16 | String realClassName; 17 | 18 | 19 | public String getRealClassName() { 20 | return realClassName; 21 | } 22 | 23 | 24 | public void setRealClassName(String realClassName) { 25 | this.realClassName = realClassName; 26 | } 27 | 28 | // 由于, mvn执行结果中失败的用例只返回类名(ActivitiesTimelineSpActivitiesTest), 29 | // 而不是完全类名 30 | // (包括包名,e.g.com.weibo.cases.xuelian.ActivitiesTimelineSpActivitiesTest) 31 | // 导致Class.forName(类名)抛异常 32 | // 使用递归加上不同包名,进行判断,找到正确完全类名 33 | public void findClass(String className) throws Throwable{ 34 | try{ 35 | realClassName = packageName[now++] + "." + className; 36 | Class.forName(realClassName); 37 | setRealClassName(realClassName); 38 | }catch(ClassNotFoundException e){ 39 | if(now < retryNum){ 40 | findClass(className); 41 | }else{ 42 | throw e; 43 | } 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/Result.txt: -------------------------------------------------------------------------------- 1 | (一).Time's Result generated on: 2015.08.31 13:45:18,722 2 | (二).日志类型:ANT 3 | (三).日志名:/Users/hugang/myworkspace/AutoTestContent/src/test/java/com/weibo/runfail/TEST-com.weibo.cases.suite.LikeTestSuite.txt 4 | ===================== 结果集 ===================== 5 | 用例总数:4, 成功数:3, 失败数:1, 运行时间:0 分钟 9 秒 6 | ================================================= 7 | 8 | [testMultiType(com.weibo.cases.wanglei16.LikesByMeBatchLikeTest): testMultiType fail] 9 | 10 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/RunFailedCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ExecutionException; 7 | /* 8 | *
 9 |  *      根据ant/mvn 执行日志,执行失败用例
10 |  * 
11 | * @author hugang 12 | */ 13 | public class RunFailedCases { 14 | 15 | // 失败日志名 16 | // public static final String LOGNAME = "725.txt"; 17 | // // 日志类型,支持MVN, ANT等2种 18 | // public static final String LOGTYPE = "MVN"; 19 | // 20 | // // 失败日志名 21 | public static final String LOGNAME = "TEST-com.weibo.cases.suite.HugangTestSuite.txt"; 22 | // 日志类型,支持MVN, ANT等2种 23 | public static final String LOGTYPE = "ANT"; 24 | // 运行结果日志名,无需修改 25 | public static final String RESULTLOG = "Result.txt"; 26 | // 执行用例方式: 27 | // 1.类级别并发(方法串行) 28 | // 2.方法级别并发 29 | // 3.串行 30 | // 默认以1.类级别并发(方法串行)执行 31 | public static final int RUNTYPE = 1; 32 | 33 | public static void main(String[] args) throws ExecutionException, IOException { 34 | // 记录失败用例,key:Class , value:List of methods 35 | Map, List> failMap; 36 | 37 | // 失败用例日志路径 38 | String logPath = System.getProperty("user.dir") 39 | + System.getProperty("file.separator") + "src" 40 | + System.getProperty("file.separator") + "test" 41 | + System.getProperty("file.separator") + "java" 42 | + System.getProperty("file.separator") + "com" 43 | + System.getProperty("file.separator") + "weibo" 44 | + System.getProperty("file.separator") + "runfail" 45 | + System.getProperty("file.separator") 46 | + LOGNAME; 47 | 48 | // 结果日志路径 49 | String resultPath = System.getProperty("user.dir") 50 | + System.getProperty("file.separator") + "src" 51 | + System.getProperty("file.separator") + "test" 52 | + System.getProperty("file.separator") + "java" 53 | + System.getProperty("file.separator") + "com" 54 | + System.getProperty("file.separator") + "weibo" 55 | + System.getProperty("file.separator") + "runfail" 56 | + System.getProperty("file.separator") 57 | + RESULTLOG; 58 | 59 | System.out.println(logPath); 60 | System.out.println(resultPath); 61 | 62 | // "\"的转义字符 63 | logPath = logPath.replace("\\", "\\\\"); 64 | 65 | // 简单工厂模式和策略模式, 根据不同的LOGTYPE创建不同实例 66 | FailCasesContext fcc = new FailCasesContext(LOGTYPE); 67 | // 通过扫日志,拿到对应失败case的Map 68 | failMap = fcc.getFailCases(logPath); 69 | 70 | // 执行失败用例 71 | ExecuteCases ec = new ExecuteCases(); 72 | // 执行 73 | switch(RUNTYPE){ 74 | case 1: 75 | ec.executorClassCases(failMap, logPath, resultPath, LOGTYPE); 76 | break; 77 | case 2: 78 | ec.executorMethodCases(failMap, logPath, resultPath, LOGTYPE); 79 | break; 80 | case 3: 81 | ec.SerialExecutorCases(failMap, logPath, resultPath, LOGTYPE); 82 | break; 83 | default: 84 | ec.executorClassCases(failMap, logPath, resultPath, LOGTYPE); 85 | break; 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/ThreadRunTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import org.junit.runner.JUnitCore; 6 | import org.junit.runner.Request; 7 | import org.junit.runner.Result; 8 | /* 9 | * @author 10 | */ 11 | //Callable实现类,一个线程执行一个case, 返回结果Result 12 | class ThreadRunTest implements Callable{ 13 | private Class oneFailClass; 14 | private String oneFailMethod; 15 | 16 | public ThreadRunTest(Class oneFailClass, String oneFailMethod){ 17 | this.oneFailClass = oneFailClass; 18 | this.oneFailMethod = oneFailMethod; 19 | } 20 | 21 | 22 | public Result call() throws Exception { 23 | // TODO Auto-generated method stub 24 | // JUnitCore执行JUnit用例 25 | JUnitCore junitRunner = new JUnitCore(); 26 | Request request = Request.method(oneFailClass, oneFailMethod); 27 | Result result = junitRunner.run(request); 28 | 29 | return result; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/WriteLogAnt.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.List; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | 17 | 18 | /* 19 | * @author hugang 20 | */ 21 | public class WriteLogAnt { 22 | public void writeLogAnt(String logPath, String resultPath) 23 | throws IOException { 24 | BufferedWriter writer; 25 | BufferedReader reader; 26 | 27 | // 日志文件 28 | File sourceFile = new File(logPath); 29 | if (!sourceFile.exists()) { 30 | sourceFile.createNewFile(); 31 | } 32 | writer = new BufferedWriter(new FileWriter(sourceFile)); 33 | 34 | // 结果日志 35 | File readFile = new File(resultPath); 36 | if (!readFile.exists()) { 37 | readFile.createNewFile(); 38 | System.out.println("read 文件不存在, Result.txt 不存在"); 39 | } else { 40 | System.out.println("" + readFile.canRead() + " " 41 | + readFile.length() + " " + readFile.getAbsolutePath() 42 | + " " + readFile.getCanonicalPath()); 43 | } 44 | reader = new BufferedReader(new FileReader(readFile)); 45 | 46 | // 根据Result.txt , 正则表达式找失败用例, 47 | // 形如 方法(类) 格式 48 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 49 | // should create success] 50 | String pattern = "\\[(\\w+)\\((.*)\\)"; 51 | 52 | Pattern pt = Pattern.compile(pattern); 53 | Matcher mt; 54 | 55 | // 根据Result.txt , 正则表达式找失败用例(只提供失败类信息) 56 | // 形如: 57 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 58 | String patternClass = "\\[((\\w+\\.)+\\w+):"; 59 | Pattern ptClass = Pattern.compile(patternClass); 60 | Matcher mtClass; 61 | 62 | List strList = new ArrayList(); 63 | // 行号 64 | List flags = new ArrayList(); 65 | int i = 0; 66 | 67 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 68 | // 写时间戳 69 | writer.write(sdf.format(new Date())); 70 | writer.newLine(); 71 | 72 | try { 73 | while (reader.ready()) { 74 | String str = reader.readLine(); 75 | strList.add(str); 76 | mt = pt.matcher(str); 77 | mtClass = ptClass.matcher(str); 78 | // 匹配后,记录匹配的行号 79 | if (mt.find() || mtClass.find()) { 80 | flags.add(i); 81 | } 82 | i++; 83 | } 84 | for (int k = 0; k < flags.size(); k++) { 85 | // 模拟 FindFailTest.java 截取的规则 86 | String failStr = "Testcase:" + strList.get(flags.get(k)); 87 | writer.write(failStr); 88 | writer.newLine(); 89 | } 90 | // System.out.println("--------------------------------------"); 91 | // System.out.println(" Ant Model find failcases number: " + i); 92 | // System.out.println("--------------------------------------"); 93 | // Utils.sleep(2000); 94 | } finally { 95 | writer.close(); 96 | reader.close(); 97 | 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runfail/WriteLogFactory.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.IOException; 4 | /* 5 | * @author hugang 6 | */ 7 | public class WriteLogFactory { 8 | public void writeLog(String logPath, String logType, String resultPath) 9 | throws IOException { 10 | // 为了支持JDK6 , case后用数字; JDK7可以直接String类型 11 | int typeNum = 2; 12 | if ("MVN".equals(logType)) { 13 | typeNum = 1; 14 | } else if ("ANT".equals(logType)) { 15 | typeNum = 2; 16 | } 17 | 18 | switch (typeNum) { 19 | case 1: 20 | // new WriteLogMvn().writeLogMvn(logPath, resultPath); 21 | new NewWriteLogMvn().writeLogMvn(logPath, resultPath); 22 | break; 23 | case 2: 24 | new WriteLogAnt().writeLogAnt(logPath, resultPath); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runner/Concurrent.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | import java.lang.annotation.ElementType; 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | import java.lang.annotation.Target; 6 | 7 | @Retention(RetentionPolicy.RUNTIME) 8 | @Target({ ElementType.TYPE }) 9 | public @interface Concurrent { 10 | // int threads() default 400; 11 | int threads() default 100; 12 | } -------------------------------------------------------------------------------- /src/test/java/com/weibo/runner/ConcurrentSuite.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.junit.experimental.categories.Categories; 6 | import org.junit.extensions.cpsuite.ClasspathSuite; 7 | import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; 8 | import org.junit.runner.Runner; 9 | import org.junit.runners.ParentRunner; 10 | import org.junit.runners.model.InitializationError; 11 | import org.junit.runners.model.RunnerBuilder; 12 | import org.junit.runners.model.RunnerScheduler; 13 | 14 | 15 | import java.lang.reflect.Method; 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.LinkedList; 19 | import java.util.List; 20 | import java.util.Queue; 21 | import java.util.concurrent.CompletionService; 22 | import java.util.concurrent.ExecutorCompletionService; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.Future; 26 | import java.util.concurrent.ThreadFactory; 27 | import java.util.concurrent.TimeUnit; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | 30 | /** 31 | * 32 | * 自定义runner, 并发执行 33 | * 34 | * 35 | * @author hugang 36 | * 37 | */ 38 | public final class ConcurrentSuite extends ClasspathSuite { 39 | 40 | public static Runner MulThread(Runner runner) { 41 | if (runner instanceof ParentRunner) { 42 | // setScheduler(RunnerScheduler scheduler):Sets a scheduler that 43 | // determines the order and parallelization of children 44 | // RunnerScheduler:Represents a strategy for scheduling when 45 | // individual test methods should be run (in serial or parallel) 46 | ((ParentRunner) runner).setScheduler(new RunnerScheduler() { 47 | private final ExecutorService fService = Executors 48 | .newCachedThreadPool(); 49 | 50 | // private final ExecutorService fService = 51 | // Executors.newFixedThreadPool(10); 52 | 53 | // Schedule a child statement to run 54 | public void schedule(Runnable childStatement) { 55 | this.fService.submit(childStatement); 56 | } 57 | 58 | // Override to implement any behavior that must occur after all 59 | // children have been scheduled 60 | public void finished() { 61 | try { 62 | this.fService.shutdown(); 63 | this.fService.awaitTermination(9223372036854775807L, 64 | TimeUnit.NANOSECONDS); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(System.err); 67 | } 68 | } 69 | }); 70 | } 71 | return runner; 72 | } 73 | 74 | public ConcurrentSuite(final Class klass) throws InitializationError { 75 | // 调用父类ClasspathSuite构造函数 76 | // AllDefaultPossibilitiesBuilder根据不同的测试类定义(@RunWith的信息)返回Runner,使用职责链模式 77 | super(klass, new AllDefaultPossibilitiesBuilder(true) { 78 | @Override 79 | public Runner runnerForClass(Class testClass) throws Throwable { 80 | List builders = Arrays 81 | .asList(new RunnerBuilder[] { 82 | // 创建Runner, 工厂类, 83 | // 自定义自己的Runner,找出注解为@Ignore,并输出@Ignore的类和方法名 84 | new RunnerBuilder() { 85 | @Override 86 | public Runner runnerForClass( 87 | Class testClass) 88 | throws Throwable { 89 | // 获取类的所有方法 90 | Method[] methods = testClass 91 | .getMethods(); 92 | 93 | // 如果类有@Ignore,则只输出类名,因为Junit最后计算结果时,会把@Ignore类记为1个用例, 94 | // 不是计算类下面的测试方法数(实验验证过) 95 | // 否则,遍历方法,如果方法有@Ignore,则输出该方法 96 | if (testClass 97 | .isAnnotationPresent(Ignore.class)) { 98 | 99 | System.out.println("Ignore: " 100 | + testClass.getName()); 101 | 102 | } else { 103 | for (Method method : methods) { 104 | if (method 105 | .isAnnotationPresent(Ignore.class)) { 106 | System.out.println("Ignore: " 107 | + testClass 108 | .getName() 109 | + "." 110 | + method.getName()); 111 | } 112 | } 113 | } 114 | return null; 115 | } 116 | }, ignoredBuilder(), annotatedBuilder(), 117 | suiteMethodBuilder(), junit3Builder(), 118 | junit4Builder() }); 119 | for (RunnerBuilder each : builders) { 120 | // 根据不同的测试类定义(@RunWith的信息)返回Runner 121 | Runner runner = each.safeRunnerForClass(testClass); 122 | if (runner != null) 123 | // 方法级别,多线程执行 124 | // return MulThread(runner); 125 | return runner; 126 | } 127 | return null; 128 | } 129 | }); 130 | 131 | // 类级别,多线程执行 132 | setScheduler(new RunnerScheduler() { 133 | private final ExecutorService fService = Executors 134 | .newCachedThreadPool(); 135 | 136 | public void schedule(Runnable paramRunnable) { 137 | // TODO Auto-generated method stub 138 | fService.submit(paramRunnable); 139 | } 140 | 141 | public void finished() { 142 | // TODO Auto-generated method stub 143 | try { 144 | fService.shutdown(); 145 | fService.awaitTermination(Long.MAX_VALUE, 146 | TimeUnit.NANOSECONDS); 147 | } catch (InterruptedException e) { 148 | e.printStackTrace(System.err); 149 | } 150 | } 151 | // 152 | // // ExecutorService executorService = 153 | // Executors.newFixedThreadPool( 154 | // // klass.isAnnotationPresent(Concurrent.class) ? 155 | // // klass.getAnnotation(Concurrent.class).threads() : 156 | // // (int) (Runtime.getRuntime().availableProcessors() * 1.5), 157 | // // new NamedThreadFactory(klass.getSimpleName())); 158 | // // CompletionService completionService = new 159 | // // ExecutorCompletionService(executorService); 160 | // // Queue> tasks = new LinkedList>(); 161 | // // 162 | // // @Override 163 | // // public void schedule(Runnable childStatement) { 164 | // // tasks.offer(completionService.submit(childStatement, null)); 165 | // // } 166 | // // 167 | // // @Override 168 | // // public void finished() { 169 | // // try { 170 | // // while (!tasks.isEmpty()) 171 | // // tasks.remove(completionService.take()); 172 | // // } catch (InterruptedException e) { 173 | // // Thread.currentThread().interrupt(); 174 | // // } finally { 175 | // // while (!tasks.isEmpty()) 176 | // // tasks.poll().cancel(true); 177 | // // executorService.shutdownNow(); 178 | // // } 179 | // 180 | }); 181 | } 182 | 183 | // static final class NamedThreadFactory implements ThreadFactory { 184 | // static final AtomicInteger poolNumber = new AtomicInteger(1); 185 | // final AtomicInteger threadNumber = new AtomicInteger(1); 186 | // final ThreadGroup group; 187 | // 188 | // NamedThreadFactory(String poolName) { 189 | // group = new ThreadGroup(poolName + "-" 190 | // + poolNumber.getAndIncrement()); 191 | // } 192 | // 193 | // @Override 194 | // public Thread newThread(Runnable r) { 195 | // System.out.println(group.getName() + "-thread-"); 196 | // 197 | // return new Thread(group, r, group.getName() + "-thread-" 198 | // + threadNumber.getAndIncrement(), 0); 199 | // } 200 | // } 201 | 202 | } -------------------------------------------------------------------------------- /src/test/java/com/weibo/runner/Retry.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import com.weibo.global.ParseProperties; 9 | 10 | // 重试次数,默认2 11 | // 方法会覆盖类,子类会覆盖父类 12 | 13 | // 重试默认值改用配置文件global.properties中 retry 字段指定 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.METHOD,ElementType.TYPE}) 16 | public @interface Retry { 17 | int value() default 2; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runner/RetryRunner.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | 4 | 5 | import java.lang.annotation.Annotation; 6 | 7 | import junit.framework.AssertionFailedError; 8 | 9 | import org.junit.Ignore; 10 | import org.junit.internal.AssumptionViolatedException; 11 | import org.junit.internal.runners.model.EachTestNotifier; 12 | import org.junit.runner.Description; 13 | import org.junit.runner.notification.RunNotifier; 14 | import org.junit.runner.notification.StoppedByUserException; 15 | import org.junit.runners.BlockJUnit4ClassRunner; 16 | import org.junit.runners.model.FrameworkMethod; 17 | import org.junit.runners.model.InitializationError; 18 | import org.junit.runners.model.MultipleFailureException; 19 | import org.junit.runners.model.Statement; 20 | 21 | import com.weibo.global.ParseProperties; 22 | 23 | /** 24 | * 自定义runner, 运行中重试 25 | * @author hugang 26 | * 27 | */ 28 | public class RetryRunner extends BlockJUnit4ClassRunner { 29 | 30 | private int retryTime; 31 | private int now = 0; 32 | 33 | public RetryRunner(Class klass) throws InitializationError { 34 | super(klass); 35 | } 36 | 37 | @Override 38 | protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 39 | Description description = describeChild(method); 40 | if (method.getAnnotation(Ignore.class) != null) { 41 | notifier.fireTestIgnored(description); 42 | } else 43 | try { 44 | if (shouldRetry(method)) { // 需要重试,走重试逻辑 45 | runLeafRetry(methodBlock(method), description, notifier); 46 | } else { // 不需要重试,走原来逻辑 47 | runLeaf(methodBlock(method), description, notifier); 48 | } 49 | } catch (Exception e) { 50 | // TODO Auto-generated catch block 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | private boolean shouldRetry(final FrameworkMethod method) throws Exception { 56 | Retry retry = null; 57 | // 类上有@Retry 58 | retry = getClassRetry(getTestClass().getJavaClass()); 59 | // 方法有@Retry 60 | Retry annotation = method.getAnnotation(Retry.class); 61 | // 方法的@Retry替换类的@Retry 62 | if (annotation != null) { 63 | retry = annotation; 64 | } 65 | if (retry != null) { 66 | if (retry.value() > 0) { 67 | // 之前根据注解@Retry, 获取重试次数 68 | // retryTime = retry.value(); 69 | // 现在更改为,根据global.properties中retry判断次数, 为空不重试, 其他值为默认重试次数 70 | String retryProperty = ParseProperties.getSystemProperty("retry"); 71 | if("".equals(retryProperty) || (1 == retry.value())){ 72 | retryTime = 1; 73 | }else{ 74 | retryTime = Integer.parseInt(retryProperty); 75 | } 76 | // System.out.println("test property get retry: " + retryTime); 77 | } else { 78 | // retry.value()<=0时,为1 79 | retryTime = 1; 80 | } 81 | now = 0; 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | private Retry getClassRetry(Class mClass) { 88 | if (mClass == null || mClass == Object.class) { 89 | return null; 90 | } 91 | Retry retry = null; 92 | Annotation[] annotations = mClass.getAnnotations(); 93 | for (Annotation annotation : annotations) { 94 | if (annotation instanceof Retry) { 95 | retry = (Retry) annotation; 96 | break; 97 | } 98 | } 99 | // 判断父类 100 | if (null == retry) { 101 | retry = getClassRetry(mClass.getSuperclass()); 102 | } 103 | return retry; 104 | } 105 | 106 | protected final void runLeafRetry(Statement statement, 107 | Description description, RunNotifier notifier) { 108 | EachTestNotifier eachNotifier = new EachTestNotifier(notifier, 109 | description); 110 | eachNotifier.fireTestStarted(); 111 | try { 112 | retryRun(statement); 113 | // 标记成功用例信息 114 | System.out.println("SuccessCase: " + description); 115 | } catch (AssumptionViolatedException e) { 116 | eachNotifier.addFailedAssumption(e); 117 | } catch (Throwable e) { 118 | eachNotifier.addFailure(e); 119 | } finally { 120 | eachNotifier.fireTestFinished(); 121 | } 122 | } 123 | 124 | private void retryRun(Statement statement) throws Throwable { 125 | try { 126 | now++; 127 | statement.evaluate(); 128 | 129 | } catch (AssertionFailedError e) { 130 | if (now < retryTime) { 131 | retryRun(statement); 132 | } else { 133 | throw e; 134 | } 135 | } catch (MultipleFailureException e) { 136 | if (now < retryTime) { 137 | retryRun(statement); 138 | } else { 139 | throw e; 140 | } 141 | } catch (AssertionError e) { 142 | // assertThat断言失败,抛AssertionError 143 | if (now < retryTime) { 144 | retryRun(statement); 145 | } else { 146 | throw e; 147 | } 148 | } catch (Throwable e) { 149 | // Throwable 所有异常 150 | if (now < retryTime) { 151 | retryRun(statement); 152 | } else { 153 | throw e; 154 | } 155 | } 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/runner/ThreadRunner.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import org.junit.runner.notification.RunNotifier; 9 | import org.junit.runners.BlockJUnit4ClassRunner; 10 | import org.junit.runners.model.FrameworkMethod; 11 | import org.junit.runners.model.InitializationError; 12 | import org.junit.runners.model.Statement; 13 | 14 | /** 15 | * Runs all tests in parallel and waits for them to complete. 16 | * Up to {@link #maxThreads} will be run at once. 17 | * 自定义runner: 单个测试类,方法并发执行 18 | * @hugang 19 | * 20 | */ 21 | public class ThreadRunner extends BlockJUnit4ClassRunner { 22 | 23 | private AtomicInteger numThreads; 24 | 25 | public static int maxThreads = 25; 26 | 27 | public ThreadRunner(Class klass) throws InitializationError { 28 | super(klass); 29 | // TODO Auto-generated constructor stub 30 | numThreads = new AtomicInteger(0); 31 | } 32 | 33 | protected void runChild(final FrameworkMethod method, final RunNotifier notifier) { 34 | while(numThreads.get() > maxThreads){ 35 | try{ 36 | Thread.sleep(1000); 37 | }catch(InterruptedException e){ 38 | e.printStackTrace(); 39 | return; 40 | } 41 | } 42 | 43 | numThreads.incrementAndGet(); 44 | new Thread(new Test(method, notifier)).start(); 45 | } 46 | 47 | protected Statement childrenInvoker(final RunNotifier notifier){ 48 | return new Statement(){ 49 | 50 | @Override 51 | public void evaluate() throws Throwable { 52 | // TODO Auto-generated method stub 53 | ThreadRunner.super.childrenInvoker(notifier).evaluate(); 54 | while(numThreads.get() > 0){ 55 | Thread.sleep(1000); 56 | } 57 | } 58 | 59 | }; 60 | } 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | class Test implements Runnable{ 69 | private final FrameworkMethod method; 70 | private final RunNotifier notifier; 71 | 72 | public Test(FrameworkMethod method, RunNotifier notifier){ 73 | this.method = method; 74 | this.notifier = notifier; 75 | } 76 | 77 | 78 | public void run() { 79 | ThreadRunner.super.runChild(method, notifier); 80 | // TODO Auto-generated method stub 81 | numThreads.decrementAndGet(); 82 | 83 | } 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/com/weibo/userpool/JdbcUtil.java: -------------------------------------------------------------------------------- 1 | package com.weibo.userpool; 2 | 3 | import java.beans.PropertyVetoException; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.sql.Connection; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.sql.Statement; 10 | import java.util.Properties; 11 | 12 | import org.apache.commons.dbutils.DbUtils; 13 | 14 | import com.mchange.v2.c3p0.ComboPooledDataSource; 15 | 16 | /** 17 | * 18 | * 19 | * jdbc 使用C3PO连接池 获得Connection 20 | * @author hugang 21 | * 22 | */ 23 | public class JdbcUtil { 24 | private static Properties enc; 25 | private static InputStream in; 26 | private static ComboPooledDataSource ds = new ComboPooledDataSource(); 27 | static { 28 | try { 29 | enc = new Properties(); 30 | in = JdbcUtil.class.getResourceAsStream("../../../c3p0.properties"); 31 | enc.load(in); 32 | } catch (Exception e) { 33 | throw new ExceptionInInitializerError(e); 34 | } 35 | finally { 36 | try { 37 | in.close(); 38 | } catch (IOException e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } 42 | } 43 | } 44 | 45 | static { 46 | try { 47 | ds.setDriverClass(enc.getProperty("c3p0.driverClass")); 48 | } catch (PropertyVetoException e) { 49 | // TODO Auto-generated catch block 50 | e.printStackTrace(); 51 | } 52 | ds.setUser(enc.getProperty("c3p0.user")); 53 | ds.setPassword(enc.getProperty("c3p0.password")); 54 | ds.setJdbcUrl(enc.getProperty("c3p0.jdbcUrl")); 55 | } 56 | 57 | public static Connection getConnection() { 58 | 59 | try { 60 | 61 | return ds.getConnection(); 62 | 63 | } catch (SQLException e) { 64 | // TODO Auto-generated catch block 65 | e.printStackTrace(); 66 | } 67 | return null; 68 | } 69 | 70 | public static void close(ResultSet rs, Statement st, Connection con) { 71 | DbUtils.closeQuietly(rs); 72 | DbUtils.closeQuietly(st); 73 | DbUtils.closeQuietly(con); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/test/java/global.properties: -------------------------------------------------------------------------------- 1 | # appkey 2 | source= 3 | 4 | 5 | # web server ip:port 6 | host= 7 | port= 8 | 9 | # run failed cases times(default value) 10 | retry=1 11 | -------------------------------------------------------------------------------- /src/test/java/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug 2 | 3 | log4j.logger.error=error,errorfile 4 | log4j.logger.info=debug,infofile 5 | log4j.logger.testlog=info,file 6 | log4j.logger.caselog=debug,casefile 7 | 8 | log4j.appender.casefile=org.apache.log4j.DailyRollingFileAppender 9 | log4j.appender.casefile.DatePattern='.'yyyyMMdd-HH 10 | log4j.appender.casefile.File=./logs/execute.log 11 | log4j.appender.casefile.Append=true 12 | log4j.appender.casefile.layout=org.apache.log4j.PatternLayout 13 | log4j.appender.casefile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 14 | 15 | log4j.appender.infofile=org.apache.log4j.DailyRollingFileAppender 16 | log4j.appender.infofile.DatePattern='.'yyyyMMdd-HH 17 | log4j.appender.infofile.File=./logs/info.log 18 | log4j.appender.infofile.Append=true 19 | log4j.appender.infofile.Threshold=DEBUG 20 | log4j.appender.infofile.layout=org.apache.log4j.PatternLayout 21 | log4j.appender.infofile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 22 | 23 | log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender 24 | log4j.appender.errorfile.DatePattern='.'yyyyMMdd-HH 25 | log4j.appender.errorfile.File=./logs/error.log 26 | log4j.appender.errorfile.Append=true 27 | log4j.appender.errorfile.Threshold=ERROR 28 | log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout 29 | log4j.appender.errorfile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 30 | 31 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 32 | log4j.appender.file.DatePattern='.'yyyyMMdd-HH 33 | log4j.appender.file.File=./logs/test.log 34 | log4j.appender.file.Append=true 35 | log4j.appender.file.Threshold=DEBUG 36 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 37 | log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 38 | 39 | 40 | -------------------------------------------------------------------------------- /target/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/.DS_Store -------------------------------------------------------------------------------- /target/classes/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Build-Jdk: 1.7.0_60-ea 3 | Built-By: hugang 4 | Created-By: Maven Integration for Eclipse 5 | 6 | -------------------------------------------------------------------------------- /target/classes/META-INF/maven/com.weibo/WeTest/pom.properties: -------------------------------------------------------------------------------- 1 | #Generated by Maven Integration for Eclipse 2 | #Tue Jul 19 08:54:43 CST 2016 3 | version=0.0.1 4 | groupId=com.weibo 5 | m2e.projectName=WeTest 6 | m2e.projectLocation=/Users/hugang/WeTest 7 | artifactId=WeTest 8 | -------------------------------------------------------------------------------- /target/classes/META-INF/maven/com.weibo/WeTest/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.weibo 5 | WeTest 6 | 7 | 0.0.1 8 | WeTest Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 4.12 15 | test 16 | 17 | 18 | org.hamcrest 19 | hamcrest-core 20 | 1.3 21 | 22 | 23 | org.hamcrest 24 | hamcrest-all 25 | 1.3 26 | 27 | 28 | com.mchange 29 | c3p0 30 | 0.9.5 31 | 32 | 33 | org.hamcrest 34 | hamcrest-library 35 | 1.3 36 | 37 | 38 | mysql 39 | mysql-connector-java 40 | 5.1.34 41 | 42 | 43 | redis.clients 44 | jedis 45 | 2.7.2 46 | jar 47 | compile 48 | 49 | 50 | 51 | 52 | 53 | 54 | log4j 55 | log4j 56 | 1.2.14 57 | 58 | 59 | org.apache.httpcomponents 60 | httpclient 61 | 4.3.1 62 | 63 | 64 | 65 | org.apache.httpcomponents 66 | httpcore 67 | 4.3 68 | 69 | 70 | org.apache.httpcomponents 71 | httpmime 72 | 4.3.1 73 | 74 | 75 | org.apache.httpcomponents 76 | httpmime 77 | 4.3.1 78 | 79 | 80 | com.fasterxml.jackson.core 81 | jackson-core 82 | 2.2.3 83 | 84 | 85 | com.fasterxml.jackson.core 86 | jackson-annotations 87 | 2.2.3 88 | 89 | 90 | com.fasterxml.jackson.core 91 | jackson-databind 92 | 2.2.3 93 | 94 | 95 | 96 | org.json 97 | json 98 | 20090211 99 | 100 | 101 | 102 | net.sf.json-lib 103 | json-lib 104 | 2.4 105 | jdk15 106 | 107 | 108 | 109 | com.googlecode.json-simple 110 | json-simple 111 | 1.1.1 112 | 113 | 114 | 115 | ant 116 | ant 117 | 1.7.0 118 | 119 | 120 | 121 | org.apache.ant 122 | ant 123 | 1.9.4 124 | 125 | 126 | 127 | org.apache.ant 128 | ant-junit4 129 | 1.9.4 130 | 131 | 132 | 133 | ant-contrib 134 | ant-contrib 135 | 1.0b3 136 | 137 | 138 | 139 | commons-dbutils 140 | commons-dbutils 141 | 1.6 142 | 143 | 144 | 145 | io.takari.junit 146 | takari-cpsuite 147 | 1.2.7 148 | 149 | 150 | 151 | javax.servlet 152 | servlet-api 153 | 2.5 154 | provided 155 | 156 | 157 | 158 | 159 | commons-beanutils 160 | commons-beanutils 161 | 1.9.2 162 | 163 | 164 | commons-logging 165 | commons-logging 166 | 1.2 167 | 168 | 169 | 170 | 171 | 172 | 173 | 175 | org.apache.maven.plugins 176 | maven-surefire-plugin 177 | 2.19.1 178 | 179 | 180 | true 181 | true 182 | 183 | 184 | 185 | org.apache.maven.surefire 186 | surefire-junit47 187 | 2.19 188 | 189 | 190 | 191 | 192 | 194 | 195 | 196 | src/test/java 197 | 198 | 199 | 200 | WeTest 201 | 202 | 203 | 204 | 1.7 205 | 1.7 206 | UTF-8 207 | java 208 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /target/test-classes/c3p0.properties: -------------------------------------------------------------------------------- 1 | # 2 | # This file is detritus from various testing attempts 3 | # the values below may change, and often do not represent 4 | # reasonable values for the parameters. 5 | # 6 | 7 | c3p0.jdbcUrl=jdbc:mysql://ip:port/dbname?useUnicode=true&characterEncoding=utf-8 8 | c3p0.driverClass=com.mysql.jdbc.Driver 9 | c3p0.user=user 10 | c3p0.password=pwd 11 | 12 | 13 | 14 | 15 | c3p0.minPoolSize=500 16 | c3p0.maxPoolSize=1500 17 | 18 | #c3p0.maxStatements=0 19 | #c3p0.checkoutTimeout=18000 20 | 21 | 22 | 23 | #c3p0.numHelperThreads=6 24 | 25 | #c3p0.testConnectionOnCheckout=true 26 | #c3p0.testConnectionOnCheckin=true 27 | 28 | #c3p0.checkoutTimeout=2000 29 | #c3p0.idleConnectionTestPeriod=5 30 | #c3p0.maxConnectionAge=10 31 | #c3p0.maxIdleTime=2 32 | #c3p0.maxIdleTimeExcessConnections=1 33 | #c3p0.propertyCycle=1 34 | #c3p0.numHelperThreads=10 35 | #c3p0.unreturnedConnectionTimeout=15 36 | #c3p0.debugUnreturnedConnectionStackTraces=true 37 | #c3p0.maxStatements=30 38 | #c3p0.maxStatementsPerConnection=5 39 | #c3p0.maxAdministrativeTaskTime=3 40 | #c3p0.preferredTestQuery=SELECT 1 41 | #c3p0.preferredTestQuery=SELECT a FROM emptyyukyuk WHERE a = 5 42 | #c3p0.preferredTestQuery=SELECT a FROM testpbds WHERE a = 5 43 | #c3p0.usesTraditionalReflectiveProxies=true 44 | #c3p0.automaticTestTable=PoopyTestTable 45 | #c3p0.acquireIncrement=4 46 | #c3p0.acquireRetryDelay=1000 47 | #c3p0.acquireRetryAttempts=60 48 | #c3p0.connectionTesterClassName=com.mchange.v2.c3p0.test.AlwaysFailConnectionTester 49 | #c3p0.initialPoolSize=10 50 | com.mchange.v2.log.MLog=com.mchange.v2.log.log4j.Log4jMLog 51 | #com.mchange.v2.log.MLog=com.mchange.v2.log.jdk14logging.Jdk14MLog 52 | #com.mchange.v2.log.MLog=com.mchange.v2.log.FallbackMLog 53 | com.mchange.v2.log.NameTransformer=com.mchange.v2.log.PackageNames 54 | com.mchange.v2.log.FallbackMLog.DEFAULT_CUTOFF_LEVEL=ALL 55 | 56 | #com.mchange.v2.c3p0.VMID=poop -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/example/ExampleTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/cases/example/ExampleTest.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/example/ExampleTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.example; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | import static org.hamcrest.Matchers.is; 7 | 8 | public class ExampleTest { 9 | 10 | @Test 11 | public void testExampleOne() { 12 | try { 13 | // 构造场景 14 | assertThat("abc", is("abc")); 15 | 16 | } catch (Exception e) { 17 | e.printStackTrace(); 18 | fail("testExampleOne excepiton"); 19 | } finally { 20 | // 清数据 21 | } 22 | } 23 | 24 | @Test 25 | public void testExampleTwo() { 26 | try { 27 | 28 | assertThat("abc", is("def")); 29 | 30 | } catch (Exception e) { 31 | e.printStackTrace(); 32 | fail("testExampleTwo excepiton"); 33 | } finally { 34 | 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/suite/ExampleTestSuite.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/cases/suite/ExampleTestSuite.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/suite/ExampleTestSuite.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.suite; 2 | 3 | 4 | import org.junit.experimental.categories.Categories; 5 | import org.junit.runner.RunWith; 6 | import org.junit.runners.Suite.SuiteClasses; 7 | 8 | @RunWith(Categories.class) 9 | @SuiteClasses( IntegrationExampleModuleTests.class ) 10 | public class ExampleTestSuite { 11 | 12 | } 13 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/suite/IntegrationExampleModuleTests.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/cases/suite/IntegrationExampleModuleTests.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/cases/suite/IntegrationExampleModuleTests.java: -------------------------------------------------------------------------------- 1 | package com.weibo.cases.suite; 2 | import org.junit.extensions.cpsuite.ClasspathSuite.ClassnameFilters; 3 | import org.junit.runner.RunWith; 4 | 5 | import com.weibo.runner.Concurrent; 6 | import com.weibo.runner.ConcurrentSuite; 7 | 8 | @RunWith(ConcurrentSuite.class) 9 | @ClassnameFilters({"com.weibo.cases.example.*Test"}) 10 | @Concurrent 11 | public interface IntegrationExampleModuleTests { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/common/StatusCommon.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/common/StatusCommon.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/common/StatusCommon.java: -------------------------------------------------------------------------------- 1 | package com.weibo.common; 2 | 3 | import java.util.List; 4 | 5 | import org.junit.Ignore; 6 | 7 | import net.sf.json.JSONArray; 8 | import net.sf.json.JSONObject; 9 | 10 | import com.weibo.global.HttpClientBase; 11 | import com.weibo.global.JsonCommon; 12 | import com.weibo.model.Status; 13 | 14 | 15 | public class StatusCommon { 16 | Object status; 17 | Object statusCount; 18 | Object statuses; 19 | Object interest; 20 | Object lastTime; 21 | Object statusesIds; 22 | Object error; 23 | Object exposure; 24 | Object allowComment; 25 | Object userReadCount; 26 | Object darwinTags; 27 | HttpClientBase statusTest = new HttpClientBase(); 28 | String relativeurl; 29 | String statusInfo; 30 | Object objectList; 31 | Object midObject; 32 | Object StatusBean; 33 | Object recomm; 34 | Object getExposureTrigger; 35 | Object getSimilarity; 36 | Object atTimeline; 37 | Object readMetas; 38 | Object phototags; 39 | boolean flag; 40 | 41 | 42 | 43 | public Object commonResult(String statusInfo) throws Exception { 44 | // if (statusInfo.contains("error_code")) { 45 | // error = (ErrorInfo) JsonCommon.getJavabean(statusInfo, 46 | // ErrorInfo.class); 47 | // MbLogger.error(statusInfo, new ExceptionCommon(statusInfo)); 48 | // return error; 49 | // } else { 50 | status = (Status) JsonCommon.getJavabean(statusInfo, Status.class); 51 | return status; 52 | // } 53 | } 54 | 55 | 56 | 57 | /* 58 | * status feed (statuses/friends_timeline) 59 | * 60 | * @param username 61 | * 62 | * @param password 63 | * 64 | * @param parameters required 65 | * 66 | * @return 67 | * 68 | * @throws Exception 69 | */ 70 | public Object friendsTimeline_status(String username, String password, 71 | String parameters) throws Exception { 72 | relativeurl = "/2/statuses/friends_timeline.json"; 73 | statusInfo = statusTest.doGet(username, password, relativeurl, parameters); 74 | statuses = commonResult(statusInfo); 75 | return statuses; 76 | } 77 | 78 | 79 | public Object updateStatusPublic(String username, String password, 80 | String parameters) throws Exception { 81 | relativeurl = "/2/statuses/update.json"; 82 | if (parameters.isEmpty()) { 83 | parameters = "visible=0&status=test public "; 84 | } 85 | statusInfo = statusTest.doPost(username, password, relativeurl, 86 | parameters); 87 | status = commonResult(statusInfo); 88 | 89 | return status; 90 | } 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | } 118 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/Constant.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/Constant.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/Constant.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | public class Constant { 4 | public static final int FREESTATE = 0;//闲置用户帐号 5 | public static final int BUSYSTATE = 1;//占用用户帐号 6 | } 7 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/HttpClientBase.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/HttpClientBase.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/JsonCommon.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/JsonCommon.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/JsonCommon.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | 4 | import java.io.IOException; 5 | import java.util.Map; 6 | 7 | import com.fasterxml.jackson.annotation.JsonIgnore; 8 | import com.fasterxml.jackson.core.JsonParseException; 9 | import com.fasterxml.jackson.core.JsonParser.Feature; 10 | import com.fasterxml.jackson.databind.DeserializationFeature; 11 | import com.fasterxml.jackson.databind.JsonMappingException; 12 | import com.fasterxml.jackson.databind.ObjectMapper; 13 | 14 | 15 | //import com.alibaba.fastjson.JSON; 16 | 17 | public class JsonCommon { 18 | // jackSon 反序列化 java对象 19 | public static Object getJavabean(String jsonString, Class classes) 20 | throws JsonParseException, JsonMappingException, IOException { 21 | if (jsonString == null || jsonString.equals("") || classes == null) 22 | return null; 23 | ObjectMapper mapper = new ObjectMapper(); 24 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 25 | false); 26 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 27 | // System.out.println("---------------------------"+classes.getName()); 28 | Object myObject = mapper.readValue(jsonString, classes); 29 | return myObject; 30 | } 31 | 32 | /** @author yanlei3 33 | * write for the JSONobject with unset key 34 | */ 35 | public static Map getMap(String jsonString) 36 | throws JsonParseException, JsonMappingException, IOException { 37 | if (jsonString == null || jsonString.equals("")) 38 | return null; 39 | ObjectMapper mapper = new ObjectMapper(); 40 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 41 | false); 42 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 43 | // System.out.println("---------------------------"+classes.getName()); 44 | Map myMap = mapper.readValue(jsonString, Map.class); 45 | return myMap; 46 | } 47 | 48 | @JsonIgnore 49 | public static Object[] getJavabeans(String jsonString, Class classes) 50 | throws JsonParseException, JsonMappingException, IOException { 51 | if (jsonString == null || jsonString.equals("") || classes == null) 52 | return null; 53 | ObjectMapper mapper = new ObjectMapper(); 54 | mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 55 | false); 56 | mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 57 | Object[] myObject = (Object[]) mapper.readValue(jsonString, classes); 58 | return myObject; 59 | } 60 | 61 | ////使用fastjson 反序列为java 对象 62 | // @SuppressWarnings("unchecked") 63 | // public static Object getJavabean(String jsonString, @SuppressWarnings("rawtypes") Class classes) { 64 | // if (jsonString == null || jsonString.equals("") || classes == null) 65 | // return null; 66 | //// ObjectMapper mapper = new ObjectMapper(); 67 | //// mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 68 | //// false); 69 | //// mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 70 | //// // System.out.println("---------------------------"+classes.getName()); 71 | //// Object myObject = mapper.readValue(jsonString, classes); 72 | //// return myObject; 73 | // Object myObject = JSON.parseObject(jsonString, classes); 74 | // return myObject; 75 | // } 76 | // 77 | // @SuppressWarnings("unchecked") 78 | // @JsonIgnore 79 | // public static Object[] getJavabeans(String jsonString, @SuppressWarnings("rawtypes") Class classes) { 80 | // if (jsonString == null || jsonString.equals("") || classes == null) 81 | // return null; 82 | //// ObjectMapper mapper = new ObjectMapper(); 83 | //// mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, 84 | //// false); 85 | //// mapper.configure(Feature.ALLOW_UNQUOTED_FIELD_NAMES, true); 86 | // Object[] myObject = (Object[]) JSON.parseObject(jsonString, classes); 87 | // return myObject; 88 | // } 89 | 90 | 91 | public static String writeEntity2Json(Object object) throws IOException { 92 | String jsonResult = null; 93 | ObjectMapper objectMapper = new ObjectMapper(); 94 | jsonResult = objectMapper.writeValueAsString(object); 95 | return jsonResult; 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/LogFormatter.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/LogFormatter.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/LogFormatter.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | //import java.util.Date; 4 | import java.util.logging.Formatter; 5 | import java.util.logging.LogRecord; 6 | 7 | public class LogFormatter extends Formatter { 8 | @Override 9 | public String format(LogRecord record) { 10 | // Date date = new Date(); 11 | // String sDate = date.toString(); 12 | // return "[" + sDate + "]" + "[" + record.getLevel() + "]" 13 | // + record.getClass() + record.getMessage() + "\n"; 14 | return "[" + record.getMessage() + "]" + "\n"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/ParseProperties.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/ParseProperties.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/ParseProperties.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.Properties; 6 | 7 | public class ParseProperties { 8 | 9 | private static final String SYSTEMPROPERTY = "../../../global.properties"; 10 | private static String HOST = null; 11 | private static String PORT = null; 12 | private static String SOURCE = null; 13 | // add retry 14 | private static String RETRY = null; 15 | 16 | private static Properties enc= null; 17 | private static InputStream ins = null; 18 | static { 19 | try { 20 | enc = new Properties(); 21 | ins = ParseProperties.class 22 | .getResourceAsStream(SYSTEMPROPERTY); 23 | enc.load(ins); 24 | HOST = enc.getProperty("host"); 25 | SOURCE = enc.getProperty("source"); 26 | PORT = enc.getProperty("port"); 27 | RETRY = enc.getProperty("retry"); 28 | 29 | } catch (Exception e) { 30 | throw new ExceptionInInitializerError(e); 31 | 32 | }finally 33 | { 34 | try { 35 | ins.close(); 36 | } catch (IOException e) { 37 | // TODO Auto-generated catch block 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | } 43 | 44 | /** 45 | * 根据属性文件和key得到属性的value 46 | * 47 | * @param fileRelativePath 48 | * @param propertyName 49 | * @return 50 | * @throws Exception 51 | */ 52 | public static String getProperty(String fileRelativePath, 53 | String propertyName) throws Exception { 54 | if (fileRelativePath == null || fileRelativePath.equals("") 55 | || propertyName == null || propertyName.equals("")) 56 | throw new Exception("传入参数为空!"); 57 | InputStream ins = ParseProperties.class 58 | .getResourceAsStream(fileRelativePath); 59 | if (ins == null) 60 | throw new Exception("系统配置文件global.peroperties文件不存在!"); 61 | Properties p = new Properties(); 62 | String value = ""; 63 | try { 64 | p.load(ins); 65 | value = p.getProperty(propertyName); 66 | } catch (Exception ex) { 67 | throw new Exception("读取属性文件异常"); 68 | } finally { 69 | ins.close(); 70 | } 71 | return value; 72 | 73 | } 74 | 75 | /** 76 | * 根据key得到系统属性的value 77 | * 78 | * @param propertyName 79 | * @throws Exception 80 | */ 81 | public static String getSystemProperty(String propertyName) 82 | throws Exception { 83 | if (propertyName == null || propertyName.equals("")) 84 | throw new Exception("传入参数为空!"); 85 | if(propertyName.equals("port")) 86 | return PORT; 87 | else if(propertyName.equals("host")) 88 | return HOST; 89 | else if(propertyName.equals("source")) 90 | return SOURCE; 91 | else if(propertyName.equals("retry")) 92 | return RETRY; 93 | return null; 94 | } 95 | 96 | public static void main(String args[]) { 97 | try { 98 | System.out.println("host======"+getSystemProperty("host")); 99 | System.out.println("port======"+getSystemProperty("port")); 100 | System.out.println("source===="+getSystemProperty("source")); 101 | System.out.println("retry====" + getSystemProperty("retry")); 102 | } catch (Exception e) { 103 | e.printStackTrace(); 104 | } 105 | } 106 | } -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/TestLog.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/global/TestLog.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/global/TestLog.java: -------------------------------------------------------------------------------- 1 | package com.weibo.global; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | import java.util.logging.FileHandler; 6 | import java.util.logging.Formatter; 7 | import java.util.logging.Level; 8 | import java.util.logging.LogRecord; 9 | import java.util.logging.Logger; 10 | 11 | 12 | //import org.apache.log4j.Logger; 13 | //import org.apache.log4j.PropertyConfigurator; 14 | 15 | /* 16 | * 记录 测试步骤 17 | * @author hugang 18 | */ 19 | 20 | public class TestLog { 21 | 22 | public final static String PATH = "./logs/caseinfo.log"; 23 | public final static Logger LOGGER = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME); 24 | 25 | 26 | public static void Comment(String comment) { 27 | try { 28 | LOGGER.setLevel(Level.ALL); 29 | FileHandler fileHandler; 30 | fileHandler = new FileHandler(PATH); 31 | fileHandler.setLevel(Level.ALL); 32 | fileHandler.setFormatter(new LogFormatter()); 33 | LOGGER.addHandler(fileHandler); 34 | LOGGER.info(comment); 35 | } catch (SecurityException e) { 36 | // TODO Auto-generated catch block 37 | e.printStackTrace(); 38 | } catch (IOException e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } 42 | 43 | } 44 | } 45 | 46 | 47 | //public class TestLog { 48 | // 49 | // 50 | // public final static Logger LOGGER = Logger.getLogger(TestLog.class); 51 | // public final static String LOG4JPATH = ".../../../log4j.properties"; 52 | // 53 | // public static void Comment(String comment) { 54 | // try { 55 | // PropertyConfigurator.configure(LOG4JPATH); 56 | // LOGGER.info(comment); 57 | // } catch (SecurityException e) { 58 | // // TODO Auto-generated catch block 59 | // e.printStackTrace(); 60 | // } 61 | // 62 | // } 63 | //} 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/model/Account.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/model/Account.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/model/Account.java: -------------------------------------------------------------------------------- 1 | package com.weibo.model; 2 | 3 | public class Account { 4 | private long uid; 5 | private String screen_name; 6 | private String email; 7 | private int id; 8 | private String password; 9 | private int state; 10 | private String groupID; 11 | public long getUid() { 12 | return uid; 13 | } 14 | public void setUid(long uid) { 15 | this.uid = uid; 16 | } 17 | public String getScreen_name() { 18 | return screen_name; 19 | } 20 | public void setScreen_name(String screen_name) { 21 | this.screen_name = screen_name; 22 | } 23 | public String getEmail() { 24 | return email; 25 | } 26 | public void setEmail(String email) { 27 | this.email = email; 28 | } 29 | public int getId() { 30 | return id; 31 | } 32 | public void setId(int id) { 33 | this.id = id; 34 | } 35 | public String getPassword() { 36 | return password; 37 | } 38 | public void setPassword(String password) { 39 | this.password = password; 40 | } 41 | public int getState() { 42 | return state; 43 | } 44 | public void setState(int state) { 45 | this.state = state; 46 | } 47 | public String getGroupID() { 48 | return groupID; 49 | } 50 | public void setGroupID(String groupID) { 51 | this.groupID = groupID; 52 | } 53 | 54 | 55 | } 56 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/model/Status.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/model/Status.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/model/Status.java: -------------------------------------------------------------------------------- 1 | package com.weibo.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; 7 | 8 | @JsonIgnoreProperties(value = { "geo" }) 9 | public class Status { 10 | private String created_at; 11 | 12 | private long id; 13 | private long mid; 14 | private String idstr; 15 | private List pic_ids = new ArrayList(); 16 | 17 | public List getPic_ids() { 18 | return pic_ids; 19 | } 20 | 21 | public void setPic_ids(List pic_ids) { 22 | this.pic_ids = pic_ids; 23 | } 24 | 25 | int position; 26 | String mark; 27 | 28 | public int getPosition() { 29 | return position; 30 | } 31 | 32 | public void setPosition(int position) { 33 | this.position = position; 34 | } 35 | 36 | public String getMark() { 37 | return mark; 38 | } 39 | 40 | public void setMark(String mark) { 41 | this.mark = mark; 42 | } 43 | 44 | private String result; 45 | private int reposts_count; 46 | private int comments_count; 47 | private int attitudes_count; 48 | private int read_count; 49 | private int mlevel; 50 | 51 | private String cover_image; 52 | private int state; 53 | private String deleted; 54 | 55 | private boolean liked; 56 | private boolean truncated; 57 | 58 | private String rid; 59 | private int mblogtype; 60 | private String ctrlType; 61 | private List cmt_picids = new ArrayList(); 62 | private long uid; 63 | 64 | long expire_time; 65 | 66 | private int source_type; 67 | private int source_allowclick; 68 | private long original_mblog_read_count; 69 | private long original_article_read_count; 70 | private long original_status_count; 71 | private long original_article_count; 72 | private String type; 73 | private String text; 74 | private String pid; 75 | private String source; 76 | 77 | private boolean favorited; 78 | 79 | private String in_reply_to_status_id; 80 | 81 | private String in_reply_to_user_id; 82 | 83 | private String in_reply_to_screen_name; 84 | 85 | private String thumbnail_pic; 86 | 87 | private String bmiddle_pic; 88 | 89 | private String original_pic; 90 | 91 | private Status retweeted_status; 92 | 93 | public long getExpire_time() { 94 | return expire_time; 95 | } 96 | 97 | public void setExpire_time(long expire_time) { 98 | this.expire_time = expire_time; 99 | } 100 | 101 | public int getSource_type() { 102 | return source_type; 103 | } 104 | 105 | public void setSource_type(int source_type) { 106 | this.source_type = source_type; 107 | } 108 | 109 | public long getOriginal_mblog_read_count() { 110 | return original_mblog_read_count; 111 | } 112 | 113 | public void setOriginal_mblog_read_count(long original_mblog_read_count) { 114 | this.original_mblog_read_count = original_mblog_read_count; 115 | } 116 | 117 | public long getOriginal_article_read_count() { 118 | return original_article_read_count; 119 | } 120 | 121 | public void setOriginal_article_read_count(long original_article_read_count) { 122 | this.original_article_read_count = original_article_read_count; 123 | } 124 | 125 | public long getOriginal_status_count() { 126 | return original_status_count; 127 | } 128 | 129 | public void setOriginal_status_count(long original_status_count) { 130 | this.original_status_count = original_status_count; 131 | } 132 | 133 | public long getOriginal_article_count() { 134 | return original_article_count; 135 | } 136 | 137 | public void setOriginal_article_count(long original_article_count) { 138 | this.original_article_count = original_article_count; 139 | } 140 | 141 | public int getState() { 142 | return state; 143 | } 144 | 145 | public void setState(int state) { 146 | this.state = state; 147 | } 148 | 149 | public String getCover_image() { 150 | return cover_image; 151 | } 152 | 153 | public void setCover_image(String cover_image) { 154 | this.cover_image = cover_image; 155 | } 156 | 157 | public int getReposts_count() { 158 | return reposts_count; 159 | } 160 | 161 | public void setReposts_count(int reposts_count) { 162 | this.reposts_count = reposts_count; 163 | } 164 | 165 | public int getComments_count() { 166 | return comments_count; 167 | } 168 | 169 | public void setComments_count(int comments_count) { 170 | this.comments_count = comments_count; 171 | } 172 | 173 | public int getAttitudes_count() { 174 | return attitudes_count; 175 | } 176 | 177 | public void setAttitudes_count(int attitudes_count) { 178 | this.attitudes_count = attitudes_count; 179 | } 180 | 181 | public int getMlevel() { 182 | return mlevel; 183 | } 184 | 185 | public void setMlevel(int mlevel) { 186 | this.mlevel = mlevel; 187 | } 188 | 189 | public String getIdstr() { 190 | return idstr; 191 | } 192 | 193 | public void setIdstr(String idstr) { 194 | this.idstr = idstr; 195 | } 196 | 197 | public long getMid() { 198 | return mid; 199 | } 200 | 201 | public void setMid(long mid) { 202 | this.mid = mid; 203 | } 204 | 205 | public String getPid() { 206 | return pid; 207 | } 208 | 209 | public void setPid(String pid) { 210 | this.pid = pid; 211 | } 212 | 213 | public String getBmiddle_pic() { 214 | return bmiddle_pic; 215 | } 216 | 217 | public void setBmiddle_pic(String bmiddle_pic) { 218 | this.bmiddle_pic = bmiddle_pic; 219 | } 220 | 221 | public String getCreated_at() { 222 | return created_at; 223 | } 224 | 225 | public void setCreated_at(String created_at) { 226 | this.created_at = created_at; 227 | } 228 | 229 | public boolean isFavorited() { 230 | return favorited; 231 | } 232 | 233 | public void setFavorited(boolean favorited) { 234 | this.favorited = favorited; 235 | } 236 | 237 | public long getId() { 238 | return id; 239 | } 240 | 241 | public void setId(long id) { 242 | this.id = id; 243 | } 244 | 245 | public String getIn_reply_to_screen_name() { 246 | return in_reply_to_screen_name; 247 | } 248 | 249 | public void setIn_reply_to_screen_name(String in_reply_to_screen_name) { 250 | this.in_reply_to_screen_name = in_reply_to_screen_name; 251 | } 252 | 253 | public String getIn_reply_to_status_id() { 254 | return in_reply_to_status_id; 255 | } 256 | 257 | public void setIn_reply_to_status_id(String in_reply_to_status_id) { 258 | this.in_reply_to_status_id = in_reply_to_status_id; 259 | } 260 | 261 | public String getIn_reply_to_user_id() { 262 | return in_reply_to_user_id; 263 | } 264 | 265 | public void setIn_reply_to_user_id(String in_reply_to_user_id) { 266 | this.in_reply_to_user_id = in_reply_to_user_id; 267 | } 268 | 269 | public String getOriginal_pic() { 270 | return original_pic; 271 | } 272 | 273 | public void setOriginal_pic(String original_pic) { 274 | this.original_pic = original_pic; 275 | } 276 | 277 | public Status getRetweeted_status() { 278 | return retweeted_status; 279 | } 280 | 281 | public void setRetweeted_status(Status retweeted_status) { 282 | this.retweeted_status = retweeted_status; 283 | } 284 | 285 | public String getSource() { 286 | return source; 287 | } 288 | 289 | public void setSource(String source) { 290 | this.source = source; 291 | } 292 | 293 | public String getText() { 294 | return text; 295 | } 296 | 297 | public void setText(String text) { 298 | this.text = text; 299 | } 300 | 301 | public String getThumbnail_pic() { 302 | return thumbnail_pic; 303 | } 304 | 305 | public void setThumbnail_pic(String thumbnail_pic) { 306 | this.thumbnail_pic = thumbnail_pic; 307 | } 308 | 309 | public boolean isTruncated() { 310 | return truncated; 311 | } 312 | 313 | public void setTruncated(boolean truncated) { 314 | this.truncated = truncated; 315 | } 316 | 317 | public boolean isLiked() { 318 | return liked; 319 | } 320 | 321 | public void setLiked(boolean liked) { 322 | this.liked = liked; 323 | } 324 | 325 | public String getRid() { 326 | return rid; 327 | } 328 | 329 | public void setRid(String rid) { 330 | this.rid = rid; 331 | } 332 | 333 | public int getMblogtype() { 334 | return mblogtype; 335 | } 336 | 337 | public void setMblogtype(int mblogtype) { 338 | this.mblogtype = mblogtype; 339 | } 340 | 341 | public String getCtrlType() { 342 | return ctrlType; 343 | } 344 | 345 | public void setCtrlType(String ctrlType) { 346 | this.ctrlType = ctrlType; 347 | } 348 | 349 | public List getCmt_picids() { 350 | return cmt_picids; 351 | } 352 | 353 | public void setCmt_picids(List cmt_picids) { 354 | this.cmt_picids = cmt_picids; 355 | } 356 | 357 | public long getUid() { 358 | return uid; 359 | } 360 | 361 | public void setUid(long uid) { 362 | this.uid = uid; 363 | } 364 | 365 | public String getDeleted() { 366 | return deleted; 367 | } 368 | 369 | public void setDeleted(String deleted) { 370 | this.deleted = deleted; 371 | } 372 | 373 | public int getSource_allowclick() { 374 | return source_allowclick; 375 | } 376 | 377 | public void setSource_allowclick(int source_allowclick) { 378 | this.source_allowclick = source_allowclick; 379 | } 380 | 381 | public String getResult() { 382 | return result; 383 | } 384 | 385 | public void setResult(String result) { 386 | this.result = result; 387 | } 388 | 389 | 390 | 391 | 392 | 393 | public int getRead_count() { 394 | return read_count; 395 | } 396 | 397 | public void setRead_count(int read_count) { 398 | this.read_count = read_count; 399 | } 400 | 401 | public String getType() { 402 | return type; 403 | } 404 | 405 | public void setType(String type) { 406 | this.type = type; 407 | } 408 | 409 | } 410 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ClassThreadRunTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/ClassThreadRunTest.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ClassThreadRunTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | /** 4 | * @hugang 5 | */ 6 | import java.util.ArrayList; 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.Callable; 11 | 12 | import org.junit.runner.JUnitCore; 13 | import org.junit.runner.Request; 14 | import org.junit.runner.Result; 15 | 16 | 17 | 18 | // 类并发执行,方法级别串行 19 | public class ClassThreadRunTest implements Callable> { 20 | 21 | 22 | Class testClass; 23 | List failMethod; 24 | 25 | // 类的方法集 结果,线程安全的List 26 | List singClassResult = Collections.synchronizedList(new ArrayList()); 27 | 28 | public ClassThreadRunTest(Class testClass, List failMethod){ 29 | this.testClass = testClass; 30 | this.failMethod = failMethod; 31 | } 32 | 33 | // 线程执行体 34 | public List call() { 35 | // TODO Auto-generated method stub 36 | // 一个类下顺序执行方法 37 | for(int i = 0; i < failMethod.size(); i++){ 38 | JUnitCore junitRunner = new JUnitCore(); 39 | Request request = Request.method(testClass, failMethod.get(i)); 40 | Result result = junitRunner.run(request); 41 | singClassResult.add(result); 42 | } 43 | return singClassResult; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ExecuteCases.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/ExecuteCases.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ExecuteCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.File; 4 | import java.io.FileOutputStream; 5 | import java.io.IOException; 6 | import java.text.SimpleDateFormat; 7 | import java.util.ArrayList; 8 | import java.util.Date; 9 | import java.util.List; 10 | import java.util.Map; 11 | import java.util.concurrent.ExecutionException; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.Executors; 14 | import java.util.concurrent.Future; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | import org.junit.runner.JUnitCore; 19 | import org.junit.runner.Request; 20 | import org.junit.runner.Result; 21 | 22 | 23 | /* 24 | * @author hugang 25 | */ 26 | public class ExecuteCases { 27 | // 线程池大小 28 | final static int THREADCOUNT = 50; 29 | 30 | public void writeResult(String resultPath, List methodsResult, 31 | int failNum, int successNum, int casesNum, long runTime, 32 | String logPath, String logType) throws IOException { 33 | String filePath = resultPath; 34 | File file = new File(filePath); 35 | if (file.exists()) { 36 | file.delete(); 37 | } 38 | if (!file.exists()) { 39 | file.createNewFile(); 40 | } 41 | FileOutputStream fop = new FileOutputStream(file); 42 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss,SSS"); 43 | fop.write("(一).Time's Result generated on: ".getBytes()); 44 | fop.write(sdf.format(new Date()).getBytes()); 45 | fop.write("\n".getBytes()); 46 | 47 | StringBuffer sb = new StringBuffer(); 48 | sb.append("(二).日志类型:" + logType); 49 | sb.append("\n"); 50 | sb.append("(三).日志名:" + logPath); 51 | sb.append("\n"); 52 | sb.append("===================== 结果集 ====================="); 53 | sb.append("\n"); 54 | sb.append("用例总数:" + casesNum); 55 | sb.append(", 成功数:" + successNum); 56 | sb.append(", 失败数:" + failNum); 57 | sb.append(", 运行时间:" + (runTime / 1000) / 60 + " 分钟 " + (runTime / 1000) 58 | % 60 + " 秒"); 59 | sb.append("\n"); 60 | sb.append("================================================="); 61 | sb.append("\n"); 62 | sb.append("\n"); 63 | fop.write(sb.toString().getBytes()); 64 | for (int j = 0; j < methodsResult.size(); j++) { 65 | // 将JUnitCore失败信息中的换行符去掉, harmcrest中断言是多行显示 66 | String LineFailStr = methodsResult.get(j).getFailures().toString().replaceAll("\n", ""); 67 | fop.write(LineFailStr.getBytes()); 68 | fop.write("\n".getBytes()); 69 | fop.write("\n".getBytes()); 70 | } 71 | // 输出结果mvn格式, 便于前端展示 72 | // Tests run: 5, Failures: 2, Errors: 0, Skipped: 0 73 | System.out.println("Tests run: " + casesNum + ", Failures: " + failNum + ", Errors: 0, Skipped: 0"); 74 | fop.flush(); 75 | fop.close(); 76 | } 77 | 78 | 79 | // 方法级别并发执行 80 | public void executorMethodCases(Map, List> failcasesMap, 81 | String logPath, String resultPath, String logType) 82 | throws ExecutionException, IOException { 83 | // 失败cases, key:Class, value:List of methods 84 | Map, List> runcaseMap; 85 | runcaseMap = failcasesMap; 86 | 87 | int failNum = 0; 88 | int successNum = 0; 89 | int casesNum = 0; 90 | long runTime = 0L; 91 | List methodsResult = new ArrayList(); 92 | 93 | // 线程池 94 | ExecutorService executorService = Executors 95 | .newFixedThreadPool(THREADCOUNT); 96 | // 存运行结果 97 | List> listFr = new ArrayList>(); 98 | long startTime = System.currentTimeMillis(); 99 | // 多线程执行用例 100 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 101 | Class testClass = entry.getKey(); 102 | List failMethod = entry.getValue(); 103 | casesNum += failMethod.size(); 104 | for (int i = 0; i < failMethod.size(); i++) { 105 | Future fr = executorService.submit(new ThreadRunTest( 106 | testClass, failMethod.get(i))); 107 | listFr.add(fr); 108 | } 109 | } 110 | // 记录结果 111 | for (Future fr : listFr) { 112 | try { 113 | while (!fr.isDone()) 114 | ; 115 | Result result = fr.get(); 116 | if (result.wasSuccessful()) { 117 | successNum++; 118 | } else { 119 | failNum++; 120 | methodsResult.add(result); 121 | } 122 | } catch (InterruptedException e) { 123 | e.printStackTrace(); 124 | } finally { 125 | executorService.shutdown(); 126 | } 127 | } 128 | long endTime = System.currentTimeMillis(); 129 | runTime = endTime - startTime; 130 | // 写结果日志 131 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 132 | runTime, logPath, logType); 133 | 134 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 135 | WriteLogFactory wlf = new WriteLogFactory(); 136 | wlf.writeLog(logPath, logType, resultPath); 137 | } 138 | 139 | // 类级别并发执行 140 | public void executorClassCases(Map, List> failcasesMap, 141 | String logPath, String resultPath, String logType) 142 | throws ExecutionException, IOException { 143 | // 失败cases, key:Class, value:List of methods 144 | Map, List> runcaseMap; 145 | runcaseMap = failcasesMap; 146 | 147 | int failNum = 0; 148 | int successNum = 0; 149 | int casesNum = 0; 150 | long runTime = 0L; 151 | List methodsResult = new ArrayList(); 152 | 153 | // 线程池 154 | // ExecutorService executorService = Executors 155 | // .newFixedThreadPool(THREADCOUNT); 156 | ExecutorService executorService = Executors.newCachedThreadPool(); 157 | // 存运行结果 158 | List>> listFr = new ArrayList>>(); 159 | long startTime = System.currentTimeMillis(); 160 | // 多线程执行用例 161 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 162 | Class testClass = entry.getKey(); 163 | List failMethod = entry.getValue(); 164 | casesNum += failMethod.size(); 165 | Future> fr = executorService 166 | .submit(new ClassThreadRunTest(testClass, failMethod)); 167 | listFr.add(fr); 168 | } 169 | // 记录结果 170 | for (Future> fr : listFr) { 171 | try { 172 | while (!fr.isDone()) 173 | ; 174 | // 单个类的结果 175 | List listResult = fr.get(); 176 | for (int i = 0; i < listResult.size(); i++) { 177 | if (listResult.get(i).wasSuccessful()) { 178 | successNum++; 179 | } else { 180 | failNum++; 181 | methodsResult.add(listResult.get(i)); 182 | } 183 | } 184 | 185 | } catch (InterruptedException e) { 186 | e.printStackTrace(); 187 | } finally { 188 | executorService.shutdown(); 189 | } 190 | } 191 | long endTime = System.currentTimeMillis(); 192 | runTime = endTime - startTime; 193 | // 写结果日志 194 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 195 | runTime, logPath, logType); 196 | 197 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 198 | WriteLogFactory wlf = new WriteLogFactory(); 199 | wlf.writeLog(logPath, logType, resultPath); 200 | 201 | } 202 | 203 | // 串行执行 204 | public void SerialExecutorCases(Map, List> failcasesMap, 205 | String logPath, String resultPath, String logType) 206 | throws ExecutionException, IOException { 207 | // 失败cases, key:Class, value:List of methods 208 | Map, List> runcaseMap; 209 | runcaseMap = failcasesMap; 210 | 211 | int failNum = 0; 212 | int successNum = 0; 213 | int casesNum = 0; 214 | long runTime = 0L; 215 | 216 | // 记录失败用例 217 | List methodsResult = new ArrayList(); 218 | 219 | // 存运行结果 220 | List listFr = new ArrayList(); 221 | long startTime = System.currentTimeMillis(); 222 | 223 | // 遍历执行用例 224 | for (Map.Entry, List> entry : runcaseMap.entrySet()) { 225 | Class testClass = entry.getKey(); 226 | List failMethod = entry.getValue(); 227 | casesNum += failMethod.size(); 228 | for (int i = 0; i < failMethod.size(); i++) { 229 | JUnitCore junitRunner = new JUnitCore(); 230 | Request request = Request.method(testClass, failMethod.get(i)); 231 | Result result = junitRunner.run(request); 232 | listFr.add(result); 233 | } 234 | } 235 | 236 | // 将失败用例添加到methodsResult, 并统计成功和失败数 237 | for (Result finResult : listFr) { 238 | if (finResult.wasSuccessful()) { 239 | ++successNum; 240 | } else { 241 | ++failNum; 242 | methodsResult.add(finResult); 243 | } 244 | } 245 | 246 | long endTime = System.currentTimeMillis(); 247 | runTime = endTime - startTime; 248 | // 写结果日志 249 | writeResult(resultPath, methodsResult, failNum, successNum, casesNum, 250 | runTime, logPath, logType); 251 | 252 | // 回写日志, 根据logType回写不同格式的运行失败用例回日志文件, 简单工厂模式 253 | WriteLogFactory wlf = new WriteLogFactory(); 254 | wlf.writeLog(logPath, logType, resultPath); 255 | 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCases.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/FailCases.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | /* 6 | * @author hugang 7 | */ 8 | public abstract class FailCases { 9 | public abstract Map, List> findFailedCases(String logPath); 10 | } 11 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCasesAnt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/FailCasesAnt.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCasesAnt.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.io.Reader; 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.Iterator; 12 | import java.util.LinkedHashMap; 13 | import java.util.List; 14 | import java.util.Map; 15 | import java.util.Set; 16 | import java.util.TreeSet; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | /* 24 | * @atuhor hugang 25 | */ 26 | public class FailCasesAnt extends FailCases { 27 | 28 | @Override 29 | public Map, List> findFailedCases(String logPath) { 30 | // TODO Auto-generated method stub 31 | // 文本每一行 32 | List strList = new ArrayList(); 33 | // 行号 34 | List flags = new ArrayList(); 35 | // 记录FAILED和ERROR 36 | Set failSet = new TreeSet(); 37 | // String regexStr = 38 | // "(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sFAILED)|(Testcase:\\s\\w*([\\w]*.{3,}\\w*.):\\sCaused\\san\\sERROR)"; 39 | Pattern p = Pattern.compile("Testcase"); 40 | Matcher m; 41 | int i = 0; 42 | 43 | try { 44 | Reader re = new FileReader(new File(logPath)); 45 | BufferedReader bre = new BufferedReader(re); 46 | while (bre.ready()) { 47 | String str = bre.readLine(); 48 | strList.add(str); 49 | m = p.matcher(str); 50 | // 匹配后,记录匹配的行号 51 | if (m.find()) { 52 | flags.add(i); 53 | System.out.println("find " + i); 54 | } 55 | i++; 56 | } 57 | for (int k = 0; k < flags.size(); k++) { 58 | // 去除SKIPPED, 只存 FAILED和ERROR 59 | if (!strList.get(flags.get(k)).contains("SKIPPED")) { 60 | // 从文本中取满足匹配的那行字符串 61 | failSet.add(strList.get(flags.get(k))); 62 | } 63 | } 64 | bre.close(); 65 | re.close(); 66 | } catch (IOException e) { 67 | // TODO Auto-generated catch block 68 | e.printStackTrace(); 69 | } 70 | 71 | System.out.println("找到失败用例数: " + failSet.size()); 72 | // 存失败用例 73 | Map, List> myClassMethodMap = new LinkedHashMap(); 74 | 75 | // JUnitCore执行结果中,形如这种结果,某个方法初始化失败直接抛错,“[com.weibo.cases.xiaoyu.FrontAppStatusesTest: 76 | // It should get success]” 77 | // 有“方法(类)”和“类”, 运行其类下所有方法,不让其方法(类)再进myClassMethodMap: 78 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 79 | // should create success] 80 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 81 | 82 | // 标记该类是否通过“类”记录到myClassMethodMap 83 | Map, Integer> bitMap = new LinkedHashMap(); 84 | 85 | List className = new ArrayList(); 86 | List methodName = new ArrayList(); 87 | 88 | for (Iterator it = failSet.iterator(); it.hasNext();) { 89 | // System.out.println(it.next().toString()); 90 | // Testcase: 91 | // testAPIRequest(com.weibo.cases.xuelian.FeedWithDarwinTagsForMovieStatusTest): 92 | // FAILED 93 | // 取出失败的行 94 | String str = it.next().toString(); 95 | 96 | 97 | // 先处理只有类信息的失败用例,执行该类所有方法(无法判断该方法是什么) 98 | // “[com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success]”格式的失败用例 99 | 100 | // 标记当个类 101 | Class singleFailClass = null; 102 | 103 | if (!str.contains("(")) { 104 | // ant 生成的单个类失败 105 | // 处理单个失败类,形如: 106 | // Testcase: 107 | // com.weibo.cases.xiaoyu.TopicFrontAddHasNewAndTopStatusTopicTest: 108 | // FAILED 109 | 110 | // JUnitCore生成的,单个类报错, 形如: 111 | // Testcase:[com.weibo.cases.xiaoyu.StatusTopicTest: null] 112 | 113 | List singleClassMethod = new ArrayList(); 114 | int singleClassLeft = 10; 115 | // 从singleClassLeft开始找 116 | int singleClassRight = str.indexOf(":", singleClassLeft); 117 | String singleFail = str.substring(singleClassLeft, 118 | singleClassRight); 119 | try { 120 | singleFailClass = Class.forName(singleFail); 121 | // 拿失败类中的方法 122 | Method[] met = singleFailClass.getMethods(); 123 | for (Method method : met) { 124 | // 只拿@Test 方法 125 | if (method.isAnnotationPresent(Test.class) 126 | && (!method.isAnnotationPresent(Ignore.class))) { 127 | // method.getName() 返回的格式:testLikeVideo 128 | System.out.println(method.getName()); 129 | singleClassMethod.add(method.getName()); 130 | } 131 | } 132 | // 将类下所有的用例放到myClassMethodMap下 133 | myClassMethodMap.put(singleFailClass, singleClassMethod); 134 | // 标记该类已通过“类”的方式进入失败用例集,无须进入“方法(类)”的方式进入失败用例集 135 | bitMap.put(singleFailClass, 1); 136 | } catch (ClassNotFoundException e) { 137 | // TODO Auto-generated catch block 138 | e.printStackTrace(); 139 | } 140 | 141 | } else { 142 | // Ant生成的正常失败信息 143 | // 形如 144 | // Testcase: 145 | // testStatusWangYiGCard(com.weibo.cases.xiaoyu.StatusMusicStatusTest): 146 | // FAILED 147 | // JUnitCore 生成的正常失败信息 148 | // Testcase:[testFriendsTimelineMuti(com.weibo.cases.xiaoyu.IsReadStatusTest): 149 | // expected:<{"3859449779315109":[1]}> but 150 | // was:<{"3859449779315109":[0]}>] 151 | // 方法(类) 152 | int classBegin = str.indexOf("("); 153 | int classEnd = str.indexOf(")"); 154 | // 类名 155 | String classPart = str.substring(classBegin + 1, classEnd); 156 | // 方法名,起始位置为10(固定) 157 | int beginFind = 10; 158 | String methodPart = str.substring(beginFind, classBegin); 159 | 160 | Class failClass = null; 161 | try { 162 | failClass = Class.forName(classPart); 163 | // 判断该类是否已通过“类”的方式进入错误用例集,不存在,则以“方法(类)”处理 164 | if(!bitMap.containsKey(failClass)){ 165 | // 聚合 class-method 一对多 166 | if (myClassMethodMap.containsKey(failClass)) { 167 | // 拿到之前的class 对应的list, 并在该list下新增 method, 再放回map 168 | List beforeFailMethod = myClassMethodMap 169 | .get(failClass); 170 | beforeFailMethod.add(methodPart); 171 | myClassMethodMap.put(failClass, beforeFailMethod); 172 | } else { 173 | // 第一次添加该class时 174 | List firstMethod = new ArrayList(); 175 | firstMethod.add(methodPart); 176 | myClassMethodMap.put(failClass, firstMethod); 177 | } 178 | } 179 | 180 | } catch (ClassNotFoundException e) { 181 | // TODO Auto-generated catch block 182 | e.printStackTrace(); 183 | } 184 | } 185 | 186 | 187 | } 188 | return myClassMethodMap; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCasesContext.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/FailCasesContext.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/FailCasesContext.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.List; 4 | import java.util.Map; 5 | /* 6 | * @author hugang 7 | */ 8 | public class FailCasesContext { 9 | FailCases fc = null; 10 | 11 | // 简单工厂模式和策略模式, 根据type声明,实例化不同实例 12 | public FailCasesContext(String type) { 13 | // 为了支持JDK6 , case后用数字; JDK7可以直接String类型 14 | // 默认为2, ant 15 | int typeNum =2; 16 | if("MVN".equals(type)){ 17 | typeNum = 1; 18 | }else if("ANT".equals(type)){ 19 | typeNum = 2; 20 | } 21 | switch (typeNum) { 22 | case 1: 23 | // FailCasesMvn fcm = new FailCasesMvn(); 24 | // 重构匹配mvn test 25 | NewFailCasesMvn fcm = new NewFailCasesMvn(); 26 | fc = fcm; 27 | break; 28 | case 2: 29 | FailCasesAnt fca = new FailCasesAnt(); 30 | fc = fca; 31 | break; 32 | } 33 | } 34 | 35 | public Map,List> getFailCases(String logPath) { 36 | return fc.findFailedCases(logPath); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/NewFailCasesMvn.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/NewFailCasesMvn.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/NewFailCasesMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.io.Reader; 9 | import java.lang.reflect.Method; 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.HashSet; 13 | import java.util.LinkedHashMap; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.Set; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | import org.junit.Ignore; 21 | import org.junit.Test; 22 | 23 | 24 | /* 25 | *
 26 |  * 正则匹配出失败用例,maven-surefire-customresult自定义输出格式
 27 |  * 
 28 |  * CustomResult Fail@后面
 29 |  * 
 30 |  * CustomResult Error@后面
 31 |  * 
 32 |  * 1) 后面带(),com.weibo.cases.wanglei16.PublicMentionsStatusTest.testFilterType(com.weibo.cases.wanglei16.PublicMentionsStatusTest)
 33 |  * 2)后面不带(),com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest.com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest
 34 |  * 
 35 |  * 
 36 |  * 
37 | * 38 | * 39 | * @author hugang 40 | */ 41 | public class NewFailCasesMvn extends FailCases { 42 | 43 | // 找出所有失败用例 每行字符串信息 44 | public Set failCasesStr(String logPath){ 45 | String failRegex = "^CustomResult Fail@(.*)"; 46 | Pattern failPattern = Pattern.compile(failRegex); 47 | Matcher matchFail; 48 | 49 | String errorRegex = "^CustomResult Error@(.*)"; 50 | Pattern errorPattern = Pattern.compile(errorRegex); 51 | Matcher matchError; 52 | 53 | // 去掉重复的 54 | Set failSet = new HashSet(); 55 | 56 | try (BufferedReader bre = new BufferedReader(new FileReader(new File(logPath)));){ 57 | while (bre.ready()) { 58 | String str = bre.readLine(); 59 | matchFail = failPattern.matcher(str); 60 | matchError = errorPattern.matcher(str); 61 | if(matchFail.matches() || matchError.matches()){ 62 | failSet.add(str); 63 | } 64 | } 65 | } catch (IOException e) { 66 | // TODO Auto-generated catch block 67 | e.printStackTrace(); 68 | } 69 | return failSet; 70 | } 71 | 72 | // 处理字符串信息, 将信息转换成Map 73 | public Map, List> getResultMap(Set failSet) { 74 | Map, List> resultMap = new LinkedHashMap, List>(); 75 | String className; 76 | List methodList = new ArrayList(); 77 | Class failClass = null; 78 | // 标记Class是否将全部方法放入Map中 79 | Map, Integer> bitMap = new HashMap, Integer>(); 80 | for(String str : failSet){ 81 | // 先处理不带(), 表示整个类失败 82 | if( ! str.contains("(")){ 83 | className = str.substring(str.lastIndexOf("com"), str.length()); 84 | try { 85 | failClass = Class.forName(className); 86 | } catch (ClassNotFoundException e) { 87 | // TODO Auto-generated catch block 88 | e.printStackTrace(); 89 | } 90 | // 拿失败类中的方法 91 | Method[] met = failClass.getMethods(); 92 | for (Method method : met) { 93 | // 只拿@Test 方法 94 | if (method.isAnnotationPresent(Test.class) 95 | && (!method 96 | .isAnnotationPresent(Ignore.class))) { 97 | // method.getName() 返回的格式:testLikeVideo 98 | System.out.println(method.getName()); 99 | methodList.add(method.getName()); 100 | } 101 | } 102 | resultMap.put(failClass, methodList); 103 | bitMap.put(failClass, 1); 104 | }else{ 105 | // 处理单个测试方法 106 | className = str.substring(str.indexOf("(") + 1, str.length() - 1); 107 | try { 108 | failClass = Class.forName(className); 109 | } catch (ClassNotFoundException e) { 110 | // TODO Auto-generated catch block 111 | e.printStackTrace(); 112 | } 113 | 114 | // 之后支持 添加JUnitCore格式 115 | int last = str.indexOf("("); 116 | String methodPart = str.substring(str.lastIndexOf(".", last) + 1, last); 117 | 118 | 119 | // 判断该类是否已通过“类”的方式进入错误用例集,不存在,则以“方法(类)”处理 120 | if(!bitMap.containsKey(failClass)){ 121 | // 聚合 class-method 一对多 122 | if (resultMap.containsKey(failClass)) { 123 | // 拿到之前的class 对应的list, 并在该list下新增 method, 再放回map 124 | List beforeFailMethod = resultMap 125 | .get(failClass); 126 | beforeFailMethod.add(methodPart); 127 | resultMap.put(failClass, beforeFailMethod); 128 | } else { 129 | // 第一次添加该class时 130 | List firstMethod = new ArrayList(); 131 | firstMethod.add(methodPart); 132 | resultMap.put(failClass, firstMethod); 133 | } 134 | } 135 | } 136 | } 137 | 138 | int casesNum = 0; 139 | List myMethod = new ArrayList(); 140 | for(Map.Entry, List> myCases: resultMap.entrySet()){ 141 | 142 | myMethod = myCases.getValue(); 143 | casesNum += myMethod.size(); 144 | System.out.println(myCases.getKey() + ":" + myMethod + ":" + myMethod.size() ); 145 | } 146 | System.out.println("mvn 找到用例数:" + casesNum); 147 | return resultMap; 148 | } 149 | 150 | @Override 151 | public Map, List> findFailedCases(String logPath) { 152 | return getResultMap(failCasesStr(logPath)); 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/NewWriteLogMvn.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/NewWriteLogMvn.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/NewWriteLogMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.List; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | /* 17 | * 将JUnitCore执行结果,回写到源日志 18 | * author hugang 19 | */ 20 | public class NewWriteLogMvn { 21 | 22 | 23 | // 格式转换,将JUnitCore装换成Mvn 24 | public List FormatJUnitCoreToMvn(List failStr){ 25 | List mvnFailList = new ArrayList(); 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | return mvnFailList; 34 | } 35 | 36 | 37 | 38 | public void writeLogMvn(String logPath, String resultPath) 39 | throws IOException { 40 | BufferedWriter writer; 41 | BufferedReader reader; 42 | 43 | // 日志文件 44 | File sourceFile = new File(logPath); 45 | if (!sourceFile.exists()) { 46 | sourceFile.createNewFile(); 47 | } 48 | writer = new BufferedWriter(new FileWriter(sourceFile)); 49 | 50 | // 结果日志 51 | File readFile = new File(resultPath); 52 | if (!readFile.exists()) { 53 | readFile.createNewFile(); 54 | System.out.println("read 文件不存在, Result.txt 不存在"); 55 | } else { 56 | System.out.println("" + readFile.canRead() + " " 57 | + readFile.length() + " " + readFile.getAbsolutePath() 58 | + " " + readFile.getCanonicalPath()); 59 | } 60 | reader = new BufferedReader(new FileReader(readFile)); 61 | 62 | // 1 63 | // 根据Result.txt , 正则表达式找失败用例 64 | // 形如 方法(类) 格式 65 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 66 | // should create success] 67 | String pattern = "\\[(\\w+)\\((.*)\\):(.*)\\]"; 68 | Pattern pt = Pattern.compile(pattern); 69 | Matcher mt; 70 | 71 | List strList = new ArrayList(); 72 | 73 | // 2 74 | // 根据Result.txt , 正则表达式找失败用例(只提供失败类信息) 75 | // 形如: 76 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 77 | String patternClass = "\\[((\\w+\\.)+(\\w+)):(.*)\\]"; 78 | Pattern ptClass = Pattern.compile(patternClass); 79 | Matcher mtClass; 80 | 81 | // 行号 82 | List flags = new ArrayList(); 83 | int i = 0; 84 | 85 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 86 | 87 | writer.write(sdf.format(new Date())); 88 | writer.write("mvn 回写失败结果"); 89 | writer.newLine(); 90 | 91 | String failStackTrace = "CustomResult Failed StackTrace@"; 92 | String failInfo = "CustomResult Fail@"; 93 | String failMethodStackTraceStr; 94 | String failMethodInfoStr; 95 | 96 | String failClassStackTraceStr; 97 | String failClassInfoStr; 98 | try { 99 | while (reader.ready()) { 100 | String str = reader.readLine(); 101 | strList.add(str); 102 | mt = pt.matcher(str); 103 | mtClass = ptClass.matcher(str); 104 | // 匹配1后,记录匹配的行号 105 | if (mt.find()) { 106 | String[] className = mt.group(2).split("\\."); 107 | int size = className.length; 108 | String methodName = mt.group(1); 109 | // 模拟MVN 日志 110 | // 1.错误栈信息,供前端解析 111 | // CustomResult Failed StackTrace@SassPart2ShortUrlStatusTest.testPublicRepost:88 testPublicRepost exception 112 | failMethodStackTraceStr = failStackTrace + className[size - 1] + "." 113 | + methodName + mt.group(3).replaceAll("\n", ""); 114 | // 2.用例信息 115 | // CustomResult Fail@com.weibo.cases.wanglei16.SassPart2ShortUrlStatusTest.testPublicRepost(com.weibo.cases.wanglei16.SassPart2ShortUrlStatusTest) 116 | failMethodInfoStr = failInfo + mt.group(2) + "." + methodName + "(" + mt.group(2) + ")"; 117 | writer.write(failMethodStackTraceStr); 118 | // 供前端解析 119 | System.out.println(failMethodStackTraceStr); 120 | writer.newLine(); 121 | writer.write(failMethodInfoStr); 122 | writer.newLine(); 123 | i++; 124 | } 125 | // 类失败 126 | if (mtClass.find()) { 127 | // 模拟MVN 日志 128 | // 1.错误栈信息, group(1) 全限类名, group(4)栈信息 129 | failClassStackTraceStr = failStackTrace + mtClass.group(1) + " " + mtClass.group(4).replaceAll("\n", ""); 130 | // com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest.com.weibo.cases.maincase.XiaoyuGroupStatusLikeBVTTest 131 | failClassInfoStr = failInfo + mtClass.group(1) + "." + mtClass.group(1); 132 | writer.write(failClassStackTraceStr); 133 | // 供前端解析 134 | System.out.println(failClassStackTraceStr); 135 | writer.newLine(); 136 | writer.write(failClassInfoStr); 137 | writer.newLine(); 138 | i++; 139 | } 140 | } 141 | 142 | } finally { 143 | writer.close(); 144 | reader.close(); 145 | 146 | } 147 | 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/RealClassMvn.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/RealClassMvn.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/RealClassMvn.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | /* 3 | * @author hugang 4 | */ 5 | public class RealClassMvn { 6 | String[] packageName = { 7 | "com.weibo.cases.hugang", "com.weibo.cases.lingna", "com.weibo.cases.maincase", 8 | "com.weibo.cases.qiaoli", "com.weibo.cases.wanglei16", "com.weibo.cases.xiaoyu", 9 | "com.weibo.cases.xuelian", "com.weibo.cases.beibei12", "com.weibo.cases.publicservice", 10 | "com.weibo.cases.yanlei3", "com.weibo.cases.guanglu" 11 | }; 12 | 13 | int now = 0; 14 | int retryNum = packageName.length; 15 | 16 | String realClassName; 17 | 18 | 19 | public String getRealClassName() { 20 | return realClassName; 21 | } 22 | 23 | 24 | public void setRealClassName(String realClassName) { 25 | this.realClassName = realClassName; 26 | } 27 | 28 | // 由于, mvn执行结果中失败的用例只返回类名(ActivitiesTimelineSpActivitiesTest), 29 | // 而不是完全类名 30 | // (包括包名,e.g.com.weibo.cases.xuelian.ActivitiesTimelineSpActivitiesTest) 31 | // 导致Class.forName(类名)抛异常 32 | // 使用递归加上不同包名,进行判断,找到正确完全类名 33 | public void findClass(String className) throws Throwable{ 34 | try{ 35 | realClassName = packageName[now++] + "." + className; 36 | Class.forName(realClassName); 37 | setRealClassName(realClassName); 38 | }catch(ClassNotFoundException e){ 39 | if(now < retryNum){ 40 | findClass(className); 41 | }else{ 42 | throw e; 43 | } 44 | } 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/Result.txt: -------------------------------------------------------------------------------- 1 | (一).Time's Result generated on: 2015.08.31 13:45:18,722 2 | (二).日志类型:ANT 3 | (三).日志名:/Users/hugang/myworkspace/AutoTestContent/src/test/java/com/weibo/runfail/TEST-com.weibo.cases.suite.LikeTestSuite.txt 4 | ===================== 结果集 ===================== 5 | 用例总数:4, 成功数:3, 失败数:1, 运行时间:0 分钟 9 秒 6 | ================================================= 7 | 8 | [testMultiType(com.weibo.cases.wanglei16.LikesByMeBatchLikeTest): testMultiType fail] 9 | 10 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/RunFailedCases.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/RunFailedCases.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/RunFailedCases.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.IOException; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ExecutionException; 7 | /* 8 | *
 9 |  *      根据ant/mvn 执行日志,执行失败用例
10 |  * 
11 | * @author hugang 12 | */ 13 | public class RunFailedCases { 14 | 15 | // 失败日志名 16 | // public static final String LOGNAME = "725.txt"; 17 | // // 日志类型,支持MVN, ANT等2种 18 | // public static final String LOGTYPE = "MVN"; 19 | // 20 | // // 失败日志名 21 | public static final String LOGNAME = "TEST-com.weibo.cases.suite.HugangTestSuite.txt"; 22 | // 日志类型,支持MVN, ANT等2种 23 | public static final String LOGTYPE = "ANT"; 24 | // 运行结果日志名,无需修改 25 | public static final String RESULTLOG = "Result.txt"; 26 | // 执行用例方式: 27 | // 1.类级别并发(方法串行) 28 | // 2.方法级别并发 29 | // 3.串行 30 | // 默认以1.类级别并发(方法串行)执行 31 | public static final int RUNTYPE = 1; 32 | 33 | public static void main(String[] args) throws ExecutionException, IOException { 34 | // 记录失败用例,key:Class , value:List of methods 35 | Map, List> failMap; 36 | 37 | // 失败用例日志路径 38 | String logPath = System.getProperty("user.dir") 39 | + System.getProperty("file.separator") + "src" 40 | + System.getProperty("file.separator") + "test" 41 | + System.getProperty("file.separator") + "java" 42 | + System.getProperty("file.separator") + "com" 43 | + System.getProperty("file.separator") + "weibo" 44 | + System.getProperty("file.separator") + "runfail" 45 | + System.getProperty("file.separator") 46 | + LOGNAME; 47 | 48 | // 结果日志路径 49 | String resultPath = System.getProperty("user.dir") 50 | + System.getProperty("file.separator") + "src" 51 | + System.getProperty("file.separator") + "test" 52 | + System.getProperty("file.separator") + "java" 53 | + System.getProperty("file.separator") + "com" 54 | + System.getProperty("file.separator") + "weibo" 55 | + System.getProperty("file.separator") + "runfail" 56 | + System.getProperty("file.separator") 57 | + RESULTLOG; 58 | 59 | System.out.println(logPath); 60 | System.out.println(resultPath); 61 | 62 | // "\"的转义字符 63 | logPath = logPath.replace("\\", "\\\\"); 64 | 65 | // 简单工厂模式和策略模式, 根据不同的LOGTYPE创建不同实例 66 | FailCasesContext fcc = new FailCasesContext(LOGTYPE); 67 | // 通过扫日志,拿到对应失败case的Map 68 | failMap = fcc.getFailCases(logPath); 69 | 70 | // 执行失败用例 71 | ExecuteCases ec = new ExecuteCases(); 72 | // 执行 73 | switch(RUNTYPE){ 74 | case 1: 75 | ec.executorClassCases(failMap, logPath, resultPath, LOGTYPE); 76 | break; 77 | case 2: 78 | ec.executorMethodCases(failMap, logPath, resultPath, LOGTYPE); 79 | break; 80 | case 3: 81 | ec.SerialExecutorCases(failMap, logPath, resultPath, LOGTYPE); 82 | break; 83 | default: 84 | ec.executorClassCases(failMap, logPath, resultPath, LOGTYPE); 85 | break; 86 | } 87 | 88 | } 89 | 90 | } 91 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ThreadRunTest.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/ThreadRunTest.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/ThreadRunTest.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | import org.junit.runner.JUnitCore; 6 | import org.junit.runner.Request; 7 | import org.junit.runner.Result; 8 | /* 9 | * @author 10 | */ 11 | //Callable实现类,一个线程执行一个case, 返回结果Result 12 | class ThreadRunTest implements Callable{ 13 | private Class oneFailClass; 14 | private String oneFailMethod; 15 | 16 | public ThreadRunTest(Class oneFailClass, String oneFailMethod){ 17 | this.oneFailClass = oneFailClass; 18 | this.oneFailMethod = oneFailMethod; 19 | } 20 | 21 | 22 | public Result call() throws Exception { 23 | // TODO Auto-generated method stub 24 | // JUnitCore执行JUnit用例 25 | JUnitCore junitRunner = new JUnitCore(); 26 | Request request = Request.method(oneFailClass, oneFailMethod); 27 | Result result = junitRunner.run(request); 28 | 29 | return result; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/WriteLogAnt.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/WriteLogAnt.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/WriteLogAnt.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.BufferedWriter; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.text.SimpleDateFormat; 10 | import java.util.ArrayList; 11 | import java.util.Date; 12 | import java.util.List; 13 | import java.util.regex.Matcher; 14 | import java.util.regex.Pattern; 15 | 16 | 17 | 18 | /* 19 | * @author hugang 20 | */ 21 | public class WriteLogAnt { 22 | public void writeLogAnt(String logPath, String resultPath) 23 | throws IOException { 24 | BufferedWriter writer; 25 | BufferedReader reader; 26 | 27 | // 日志文件 28 | File sourceFile = new File(logPath); 29 | if (!sourceFile.exists()) { 30 | sourceFile.createNewFile(); 31 | } 32 | writer = new BufferedWriter(new FileWriter(sourceFile)); 33 | 34 | // 结果日志 35 | File readFile = new File(resultPath); 36 | if (!readFile.exists()) { 37 | readFile.createNewFile(); 38 | System.out.println("read 文件不存在, Result.txt 不存在"); 39 | } else { 40 | System.out.println("" + readFile.canRead() + " " 41 | + readFile.length() + " " + readFile.getAbsolutePath() 42 | + " " + readFile.getCanonicalPath()); 43 | } 44 | reader = new BufferedReader(new FileReader(readFile)); 45 | 46 | // 根据Result.txt , 正则表达式找失败用例, 47 | // 形如 方法(类) 格式 48 | // [GroupChatNotFrontTest(com.weibo.cases.xiaoyu.FrontAppStatusesTest): 49 | // should create success] 50 | String pattern = "\\[(\\w+)\\((.*)\\)"; 51 | 52 | Pattern pt = Pattern.compile(pattern); 53 | Matcher mt; 54 | 55 | // 根据Result.txt , 正则表达式找失败用例(只提供失败类信息) 56 | // 形如: 57 | // [com.weibo.cases.xiaoyu.FrontAppStatusesTest: It should get success] 58 | String patternClass = "\\[((\\w+\\.)+\\w+):"; 59 | Pattern ptClass = Pattern.compile(patternClass); 60 | Matcher mtClass; 61 | 62 | List strList = new ArrayList(); 63 | // 行号 64 | List flags = new ArrayList(); 65 | int i = 0; 66 | 67 | SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 68 | // 写时间戳 69 | writer.write(sdf.format(new Date())); 70 | writer.newLine(); 71 | 72 | try { 73 | while (reader.ready()) { 74 | String str = reader.readLine(); 75 | strList.add(str); 76 | mt = pt.matcher(str); 77 | mtClass = ptClass.matcher(str); 78 | // 匹配后,记录匹配的行号 79 | if (mt.find() || mtClass.find()) { 80 | flags.add(i); 81 | } 82 | i++; 83 | } 84 | for (int k = 0; k < flags.size(); k++) { 85 | // 模拟 FindFailTest.java 截取的规则 86 | String failStr = "Testcase:" + strList.get(flags.get(k)); 87 | writer.write(failStr); 88 | writer.newLine(); 89 | } 90 | // System.out.println("--------------------------------------"); 91 | // System.out.println(" Ant Model find failcases number: " + i); 92 | // System.out.println("--------------------------------------"); 93 | // Utils.sleep(2000); 94 | } finally { 95 | writer.close(); 96 | reader.close(); 97 | 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/WriteLogFactory.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runfail/WriteLogFactory.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runfail/WriteLogFactory.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runfail; 2 | 3 | import java.io.IOException; 4 | /* 5 | * @author hugang 6 | */ 7 | public class WriteLogFactory { 8 | public void writeLog(String logPath, String logType, String resultPath) 9 | throws IOException { 10 | // 为了支持JDK6 , case后用数字; JDK7可以直接String类型 11 | int typeNum = 2; 12 | if ("MVN".equals(logType)) { 13 | typeNum = 1; 14 | } else if ("ANT".equals(logType)) { 15 | typeNum = 2; 16 | } 17 | 18 | switch (typeNum) { 19 | case 1: 20 | // new WriteLogMvn().writeLogMvn(logPath, resultPath); 21 | new NewWriteLogMvn().writeLogMvn(logPath, resultPath); 22 | break; 23 | case 2: 24 | new WriteLogAnt().writeLogAnt(logPath, resultPath); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/Concurrent.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/Concurrent.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/Concurrent.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | import java.lang.annotation.ElementType; 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | import java.lang.annotation.Target; 6 | 7 | @Retention(RetentionPolicy.RUNTIME) 8 | @Target({ ElementType.TYPE }) 9 | public @interface Concurrent { 10 | // int threads() default 400; 11 | int threads() default 100; 12 | } -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ConcurrentSuite$1.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite$2$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ConcurrentSuite$2$1.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite$2.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ConcurrentSuite$2.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite$3.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ConcurrentSuite$3.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ConcurrentSuite.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ConcurrentSuite.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import org.junit.Ignore; 4 | import org.junit.Test; 5 | import org.junit.experimental.categories.Categories; 6 | import org.junit.extensions.cpsuite.ClasspathSuite; 7 | import org.junit.internal.builders.AllDefaultPossibilitiesBuilder; 8 | import org.junit.runner.Runner; 9 | import org.junit.runners.ParentRunner; 10 | import org.junit.runners.model.InitializationError; 11 | import org.junit.runners.model.RunnerBuilder; 12 | import org.junit.runners.model.RunnerScheduler; 13 | 14 | 15 | import java.lang.reflect.Method; 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.LinkedList; 19 | import java.util.List; 20 | import java.util.Queue; 21 | import java.util.concurrent.CompletionService; 22 | import java.util.concurrent.ExecutorCompletionService; 23 | import java.util.concurrent.ExecutorService; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.Future; 26 | import java.util.concurrent.ThreadFactory; 27 | import java.util.concurrent.TimeUnit; 28 | import java.util.concurrent.atomic.AtomicInteger; 29 | 30 | /** 31 | * 32 | * 自定义runner, 并发执行 33 | * 34 | * 35 | * @author hugang 36 | * 37 | */ 38 | public final class ConcurrentSuite extends ClasspathSuite { 39 | 40 | public static Runner MulThread(Runner runner) { 41 | if (runner instanceof ParentRunner) { 42 | // setScheduler(RunnerScheduler scheduler):Sets a scheduler that 43 | // determines the order and parallelization of children 44 | // RunnerScheduler:Represents a strategy for scheduling when 45 | // individual test methods should be run (in serial or parallel) 46 | ((ParentRunner) runner).setScheduler(new RunnerScheduler() { 47 | private final ExecutorService fService = Executors 48 | .newCachedThreadPool(); 49 | 50 | // private final ExecutorService fService = 51 | // Executors.newFixedThreadPool(10); 52 | 53 | // Schedule a child statement to run 54 | public void schedule(Runnable childStatement) { 55 | this.fService.submit(childStatement); 56 | } 57 | 58 | // Override to implement any behavior that must occur after all 59 | // children have been scheduled 60 | public void finished() { 61 | try { 62 | this.fService.shutdown(); 63 | this.fService.awaitTermination(9223372036854775807L, 64 | TimeUnit.NANOSECONDS); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(System.err); 67 | } 68 | } 69 | }); 70 | } 71 | return runner; 72 | } 73 | 74 | public ConcurrentSuite(final Class klass) throws InitializationError { 75 | // 调用父类ClasspathSuite构造函数 76 | // AllDefaultPossibilitiesBuilder根据不同的测试类定义(@RunWith的信息)返回Runner,使用职责链模式 77 | super(klass, new AllDefaultPossibilitiesBuilder(true) { 78 | @Override 79 | public Runner runnerForClass(Class testClass) throws Throwable { 80 | List builders = Arrays 81 | .asList(new RunnerBuilder[] { 82 | // 创建Runner, 工厂类, 83 | // 自定义自己的Runner,找出注解为@Ignore,并输出@Ignore的类和方法名 84 | new RunnerBuilder() { 85 | @Override 86 | public Runner runnerForClass( 87 | Class testClass) 88 | throws Throwable { 89 | // 获取类的所有方法 90 | Method[] methods = testClass 91 | .getMethods(); 92 | 93 | // 如果类有@Ignore,则只输出类名,因为Junit最后计算结果时,会把@Ignore类记为1个用例, 94 | // 不是计算类下面的测试方法数(实验验证过) 95 | // 否则,遍历方法,如果方法有@Ignore,则输出该方法 96 | if (testClass 97 | .isAnnotationPresent(Ignore.class)) { 98 | 99 | System.out.println("Ignore: " 100 | + testClass.getName()); 101 | 102 | } else { 103 | for (Method method : methods) { 104 | if (method 105 | .isAnnotationPresent(Ignore.class)) { 106 | System.out.println("Ignore: " 107 | + testClass 108 | .getName() 109 | + "." 110 | + method.getName()); 111 | } 112 | } 113 | } 114 | return null; 115 | } 116 | }, ignoredBuilder(), annotatedBuilder(), 117 | suiteMethodBuilder(), junit3Builder(), 118 | junit4Builder() }); 119 | for (RunnerBuilder each : builders) { 120 | // 根据不同的测试类定义(@RunWith的信息)返回Runner 121 | Runner runner = each.safeRunnerForClass(testClass); 122 | if (runner != null) 123 | // 方法级别,多线程执行 124 | // return MulThread(runner); 125 | return runner; 126 | } 127 | return null; 128 | } 129 | }); 130 | 131 | // 类级别,多线程执行 132 | setScheduler(new RunnerScheduler() { 133 | private final ExecutorService fService = Executors 134 | .newCachedThreadPool(); 135 | 136 | public void schedule(Runnable paramRunnable) { 137 | // TODO Auto-generated method stub 138 | fService.submit(paramRunnable); 139 | } 140 | 141 | public void finished() { 142 | // TODO Auto-generated method stub 143 | try { 144 | fService.shutdown(); 145 | fService.awaitTermination(Long.MAX_VALUE, 146 | TimeUnit.NANOSECONDS); 147 | } catch (InterruptedException e) { 148 | e.printStackTrace(System.err); 149 | } 150 | } 151 | // 152 | // // ExecutorService executorService = 153 | // Executors.newFixedThreadPool( 154 | // // klass.isAnnotationPresent(Concurrent.class) ? 155 | // // klass.getAnnotation(Concurrent.class).threads() : 156 | // // (int) (Runtime.getRuntime().availableProcessors() * 1.5), 157 | // // new NamedThreadFactory(klass.getSimpleName())); 158 | // // CompletionService completionService = new 159 | // // ExecutorCompletionService(executorService); 160 | // // Queue> tasks = new LinkedList>(); 161 | // // 162 | // // @Override 163 | // // public void schedule(Runnable childStatement) { 164 | // // tasks.offer(completionService.submit(childStatement, null)); 165 | // // } 166 | // // 167 | // // @Override 168 | // // public void finished() { 169 | // // try { 170 | // // while (!tasks.isEmpty()) 171 | // // tasks.remove(completionService.take()); 172 | // // } catch (InterruptedException e) { 173 | // // Thread.currentThread().interrupt(); 174 | // // } finally { 175 | // // while (!tasks.isEmpty()) 176 | // // tasks.poll().cancel(true); 177 | // // executorService.shutdownNow(); 178 | // // } 179 | // 180 | }); 181 | } 182 | 183 | // static final class NamedThreadFactory implements ThreadFactory { 184 | // static final AtomicInteger poolNumber = new AtomicInteger(1); 185 | // final AtomicInteger threadNumber = new AtomicInteger(1); 186 | // final ThreadGroup group; 187 | // 188 | // NamedThreadFactory(String poolName) { 189 | // group = new ThreadGroup(poolName + "-" 190 | // + poolNumber.getAndIncrement()); 191 | // } 192 | // 193 | // @Override 194 | // public Thread newThread(Runnable r) { 195 | // System.out.println(group.getName() + "-thread-"); 196 | // 197 | // return new Thread(group, r, group.getName() + "-thread-" 198 | // + threadNumber.getAndIncrement(), 0); 199 | // } 200 | // } 201 | 202 | } -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/Retry.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/Retry.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/Retry.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | import com.weibo.global.ParseProperties; 9 | 10 | // 重试次数,默认2 11 | // 方法会覆盖类,子类会覆盖父类 12 | 13 | // 重试默认值改用配置文件global.properties中 retry 字段指定 14 | @Retention(RetentionPolicy.RUNTIME) 15 | @Target({ElementType.METHOD,ElementType.TYPE}) 16 | public @interface Retry { 17 | int value() default 2; 18 | } 19 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/RetryRunner.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/RetryRunner.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/RetryRunner.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | 4 | 5 | import java.lang.annotation.Annotation; 6 | 7 | import junit.framework.AssertionFailedError; 8 | 9 | import org.junit.Ignore; 10 | import org.junit.internal.AssumptionViolatedException; 11 | import org.junit.internal.runners.model.EachTestNotifier; 12 | import org.junit.runner.Description; 13 | import org.junit.runner.notification.RunNotifier; 14 | import org.junit.runner.notification.StoppedByUserException; 15 | import org.junit.runners.BlockJUnit4ClassRunner; 16 | import org.junit.runners.model.FrameworkMethod; 17 | import org.junit.runners.model.InitializationError; 18 | import org.junit.runners.model.MultipleFailureException; 19 | import org.junit.runners.model.Statement; 20 | 21 | import com.weibo.global.ParseProperties; 22 | 23 | /** 24 | * 自定义runner, 运行中重试 25 | * @author hugang 26 | * 27 | */ 28 | public class RetryRunner extends BlockJUnit4ClassRunner { 29 | 30 | private int retryTime; 31 | private int now = 0; 32 | 33 | public RetryRunner(Class klass) throws InitializationError { 34 | super(klass); 35 | } 36 | 37 | @Override 38 | protected void runChild(final FrameworkMethod method, RunNotifier notifier) { 39 | Description description = describeChild(method); 40 | if (method.getAnnotation(Ignore.class) != null) { 41 | notifier.fireTestIgnored(description); 42 | } else 43 | try { 44 | if (shouldRetry(method)) { // 需要重试,走重试逻辑 45 | runLeafRetry(methodBlock(method), description, notifier); 46 | } else { // 不需要重试,走原来逻辑 47 | runLeaf(methodBlock(method), description, notifier); 48 | } 49 | } catch (Exception e) { 50 | // TODO Auto-generated catch block 51 | e.printStackTrace(); 52 | } 53 | } 54 | 55 | private boolean shouldRetry(final FrameworkMethod method) throws Exception { 56 | Retry retry = null; 57 | // 类上有@Retry 58 | retry = getClassRetry(getTestClass().getJavaClass()); 59 | // 方法有@Retry 60 | Retry annotation = method.getAnnotation(Retry.class); 61 | // 方法的@Retry替换类的@Retry 62 | if (annotation != null) { 63 | retry = annotation; 64 | } 65 | if (retry != null) { 66 | if (retry.value() > 0) { 67 | // 之前根据注解@Retry, 获取重试次数 68 | // retryTime = retry.value(); 69 | // 现在更改为,根据global.properties中retry判断次数, 为空不重试, 其他值为默认重试次数 70 | String retryProperty = ParseProperties.getSystemProperty("retry"); 71 | if("".equals(retryProperty) || (1 == retry.value())){ 72 | retryTime = 1; 73 | }else{ 74 | retryTime = Integer.parseInt(retryProperty); 75 | } 76 | // System.out.println("test property get retry: " + retryTime); 77 | } else { 78 | // retry.value()<=0时,为1 79 | retryTime = 1; 80 | } 81 | now = 0; 82 | return true; 83 | } 84 | return false; 85 | } 86 | 87 | private Retry getClassRetry(Class mClass) { 88 | if (mClass == null || mClass == Object.class) { 89 | return null; 90 | } 91 | Retry retry = null; 92 | Annotation[] annotations = mClass.getAnnotations(); 93 | for (Annotation annotation : annotations) { 94 | if (annotation instanceof Retry) { 95 | retry = (Retry) annotation; 96 | break; 97 | } 98 | } 99 | // 判断父类 100 | if (null == retry) { 101 | retry = getClassRetry(mClass.getSuperclass()); 102 | } 103 | return retry; 104 | } 105 | 106 | protected final void runLeafRetry(Statement statement, 107 | Description description, RunNotifier notifier) { 108 | EachTestNotifier eachNotifier = new EachTestNotifier(notifier, 109 | description); 110 | eachNotifier.fireTestStarted(); 111 | try { 112 | retryRun(statement); 113 | // 标记成功用例信息 114 | System.out.println("SuccessCase: " + description); 115 | } catch (AssumptionViolatedException e) { 116 | eachNotifier.addFailedAssumption(e); 117 | } catch (Throwable e) { 118 | eachNotifier.addFailure(e); 119 | } finally { 120 | eachNotifier.fireTestFinished(); 121 | } 122 | } 123 | 124 | private void retryRun(Statement statement) throws Throwable { 125 | try { 126 | now++; 127 | statement.evaluate(); 128 | 129 | } catch (AssertionFailedError e) { 130 | if (now < retryTime) { 131 | retryRun(statement); 132 | } else { 133 | throw e; 134 | } 135 | } catch (MultipleFailureException e) { 136 | if (now < retryTime) { 137 | retryRun(statement); 138 | } else { 139 | throw e; 140 | } 141 | } catch (AssertionError e) { 142 | // assertThat断言失败,抛AssertionError 143 | if (now < retryTime) { 144 | retryRun(statement); 145 | } else { 146 | throw e; 147 | } 148 | } catch (Throwable e) { 149 | // Throwable 所有异常 150 | if (now < retryTime) { 151 | retryRun(statement); 152 | } else { 153 | throw e; 154 | } 155 | } 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ThreadRunner$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ThreadRunner$1.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ThreadRunner$Test.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ThreadRunner$Test.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ThreadRunner.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/runner/ThreadRunner.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/runner/ThreadRunner.java: -------------------------------------------------------------------------------- 1 | package com.weibo.runner; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.concurrent.ExecutorService; 5 | import java.util.concurrent.Executors; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import org.junit.runner.notification.RunNotifier; 9 | import org.junit.runners.BlockJUnit4ClassRunner; 10 | import org.junit.runners.model.FrameworkMethod; 11 | import org.junit.runners.model.InitializationError; 12 | import org.junit.runners.model.Statement; 13 | 14 | /** 15 | * Runs all tests in parallel and waits for them to complete. 16 | * Up to {@link #maxThreads} will be run at once. 17 | * 自定义runner: 单个测试类,方法并发执行 18 | * @hugang 19 | * 20 | */ 21 | public class ThreadRunner extends BlockJUnit4ClassRunner { 22 | 23 | private AtomicInteger numThreads; 24 | 25 | public static int maxThreads = 25; 26 | 27 | public ThreadRunner(Class klass) throws InitializationError { 28 | super(klass); 29 | // TODO Auto-generated constructor stub 30 | numThreads = new AtomicInteger(0); 31 | } 32 | 33 | protected void runChild(final FrameworkMethod method, final RunNotifier notifier) { 34 | while(numThreads.get() > maxThreads){ 35 | try{ 36 | Thread.sleep(1000); 37 | }catch(InterruptedException e){ 38 | e.printStackTrace(); 39 | return; 40 | } 41 | } 42 | 43 | numThreads.incrementAndGet(); 44 | new Thread(new Test(method, notifier)).start(); 45 | } 46 | 47 | protected Statement childrenInvoker(final RunNotifier notifier){ 48 | return new Statement(){ 49 | 50 | @Override 51 | public void evaluate() throws Throwable { 52 | // TODO Auto-generated method stub 53 | ThreadRunner.super.childrenInvoker(notifier).evaluate(); 54 | while(numThreads.get() > 0){ 55 | Thread.sleep(1000); 56 | } 57 | } 58 | 59 | }; 60 | } 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | class Test implements Runnable{ 69 | private final FrameworkMethod method; 70 | private final RunNotifier notifier; 71 | 72 | public Test(FrameworkMethod method, RunNotifier notifier){ 73 | this.method = method; 74 | this.notifier = notifier; 75 | } 76 | 77 | 78 | public void run() { 79 | ThreadRunner.super.runChild(method, notifier); 80 | // TODO Auto-generated method stub 81 | numThreads.decrementAndGet(); 82 | 83 | } 84 | 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /target/test-classes/com/weibo/userpool/JdbcUtil.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/target/test-classes/com/weibo/userpool/JdbcUtil.class -------------------------------------------------------------------------------- /target/test-classes/com/weibo/userpool/JdbcUtil.java: -------------------------------------------------------------------------------- 1 | package com.weibo.userpool; 2 | 3 | import java.beans.PropertyVetoException; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | import java.sql.Connection; 7 | import java.sql.ResultSet; 8 | import java.sql.SQLException; 9 | import java.sql.Statement; 10 | import java.util.Properties; 11 | 12 | import org.apache.commons.dbutils.DbUtils; 13 | 14 | import com.mchange.v2.c3p0.ComboPooledDataSource; 15 | 16 | /** 17 | * 18 | * 19 | * jdbc 使用C3PO连接池 获得Connection 20 | * @author hugang 21 | * 22 | */ 23 | public class JdbcUtil { 24 | private static Properties enc; 25 | private static InputStream in; 26 | private static ComboPooledDataSource ds = new ComboPooledDataSource(); 27 | static { 28 | try { 29 | enc = new Properties(); 30 | in = JdbcUtil.class.getResourceAsStream("../../../c3p0.properties"); 31 | enc.load(in); 32 | } catch (Exception e) { 33 | throw new ExceptionInInitializerError(e); 34 | } 35 | finally { 36 | try { 37 | in.close(); 38 | } catch (IOException e) { 39 | // TODO Auto-generated catch block 40 | e.printStackTrace(); 41 | } 42 | } 43 | } 44 | 45 | static { 46 | try { 47 | ds.setDriverClass(enc.getProperty("c3p0.driverClass")); 48 | } catch (PropertyVetoException e) { 49 | // TODO Auto-generated catch block 50 | e.printStackTrace(); 51 | } 52 | ds.setUser(enc.getProperty("c3p0.user")); 53 | ds.setPassword(enc.getProperty("c3p0.password")); 54 | ds.setJdbcUrl(enc.getProperty("c3p0.jdbcUrl")); 55 | } 56 | 57 | public static Connection getConnection() { 58 | 59 | try { 60 | 61 | return ds.getConnection(); 62 | 63 | } catch (SQLException e) { 64 | // TODO Auto-generated catch block 65 | e.printStackTrace(); 66 | } 67 | return null; 68 | } 69 | 70 | public static void close(ResultSet rs, Statement st, Connection con) { 71 | DbUtils.closeQuietly(rs); 72 | DbUtils.closeQuietly(st); 73 | DbUtils.closeQuietly(con); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /target/test-classes/global.properties: -------------------------------------------------------------------------------- 1 | # appkey 2 | source= 3 | 4 | 5 | # web server ip:port 6 | host= 7 | port= 8 | 9 | # run failed cases times(default value) 10 | retry=1 11 | -------------------------------------------------------------------------------- /target/test-classes/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug 2 | 3 | log4j.logger.error=error,errorfile 4 | log4j.logger.info=debug,infofile 5 | log4j.logger.testlog=info,file 6 | log4j.logger.caselog=debug,casefile 7 | 8 | log4j.appender.casefile=org.apache.log4j.DailyRollingFileAppender 9 | log4j.appender.casefile.DatePattern='.'yyyyMMdd-HH 10 | log4j.appender.casefile.File=./logs/execute.log 11 | log4j.appender.casefile.Append=true 12 | log4j.appender.casefile.layout=org.apache.log4j.PatternLayout 13 | log4j.appender.casefile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 14 | 15 | log4j.appender.infofile=org.apache.log4j.DailyRollingFileAppender 16 | log4j.appender.infofile.DatePattern='.'yyyyMMdd-HH 17 | log4j.appender.infofile.File=./logs/info.log 18 | log4j.appender.infofile.Append=true 19 | log4j.appender.infofile.Threshold=DEBUG 20 | log4j.appender.infofile.layout=org.apache.log4j.PatternLayout 21 | log4j.appender.infofile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 22 | 23 | log4j.appender.errorfile=org.apache.log4j.DailyRollingFileAppender 24 | log4j.appender.errorfile.DatePattern='.'yyyyMMdd-HH 25 | log4j.appender.errorfile.File=./logs/error.log 26 | log4j.appender.errorfile.Append=true 27 | log4j.appender.errorfile.Threshold=ERROR 28 | log4j.appender.errorfile.layout=org.apache.log4j.PatternLayout 29 | log4j.appender.errorfile.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 30 | 31 | log4j.appender.file=org.apache.log4j.DailyRollingFileAppender 32 | log4j.appender.file.DatePattern='.'yyyyMMdd-HH 33 | log4j.appender.file.File=./logs/test.log 34 | log4j.appender.file.Append=true 35 | log4j.appender.file.Threshold=DEBUG 36 | log4j.appender.file.layout=org.apache.log4j.PatternLayout 37 | log4j.appender.file.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss} [%p] %m%n 38 | 39 | 40 | -------------------------------------------------------------------------------- /test-output/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neven7/WeTest/af1b3d35ed270d01a34656fc8dc9421e0590a5ad/test-output/.DS_Store --------------------------------------------------------------------------------