使用Groovy构建自己的脚本环境
2015-10-12 13:22
225 查看
场景
在进行Web服务端开发的时候,发布前通常需要测试一遍。对于一个大一点的项目,最好的办法是写个自动化测试程序。以Groovy为例,写测试代码之前通常的有如下几个操作
引用相关的类库
import相关的类
对库不熟悉的时候你很可能得先把库的文档好好看一遍
对于你来说,你需要的可能仅仅是post,get等几个简单的操作而已,而上面的操作更是可能占用你整个开发过程的大部分时间。
Orz....项目进度没跟上,又要加班了。。。。
要是有一种语言,本身自带post,get这样的函数那该多好啊,测试程序哗啦哗啦就写完了!
解决方案
通过Groovy构建一个脚本环境,自带post,get这些常用的函数效果
再也不用手动引用库了,再也不用手动import类了,再也不用复习好长好长的文档了,写测试脚本再也腰不疼、腿不麻了!原理
groovy本身是一个强大的脚本引擎,同时也是高度可定制化的。在groovy编译脚本的时候,可以为脚本指定一个基类,这个基类的所有方法和属性都可以直接在脚本引用。
实现
首先,先新建一个工程,这里用gradle作为构建工具,取工程名为httpbatch。
新建
build.gradle
apply plugin: 'groovy' apply plugin: 'eclipse' apply plugin: 'application' mainClassName = 'com.kasonyang.httpbatch.Application' repositories { mavenCentral() } dependencies { compile 'org.codehaus.groovy:groovy-all:2.3.10' compile 'org.apache.httpcomponents:httpclient:4.5' }
工程引用了apache的httpclient组件,并指定主类为
com.kasonyang.httpbatch.Application
生成Eclipse工程
$ gradle eclipse
然后我们就可以使用Eclipse导入工程了。
创建主类Application.groovy
package com.kasonyang.httpbatch import com.kasonyang.httpbatch.test.TestException import org.codehaus.groovy.control.CompilerConfiguration class Application { static void printUsage(){ println """ usage : httpbatch file #execute a file or httpbatch -s #enter shell mode """ } static void main(String[] args) { if(args.length<1){ printUsage() return } def reader,scriptStr = '' switch(args[0]){ case '-s': print ">" reader = System.in reader.eachLine {it-> scriptStr += it + '\n' if(it == ''){ runScript(scriptStr) scriptStr = '' }//else{ print '>' //} } break default: def file = new File(args[0]) runScript(file) break } } private static String getExceptionStack(Exception ex,String clsName){ String msg = "" for(stack in ex.stackTrace){ if(stack.className == clsName){ def fileName = stack.fileName def lineNumber = stack.lineNumber.toString() msg += ("\tFile:${fileName}(${lineNumber})") } } msg } private static runScript(def it){ def config = new CompilerConfiguration() config.scriptBaseClass = 'com.kasonyang.httpbatch.HttpBatchScript' def shell = new GroovyShell(config) def scriptClass try{ //shell.evaluate(file) def script = shell.parse(it) scriptClass = script.class.name def stateReturn = script.run() //System.out.println(stateReturn) }catch(TestException ex){ println "test fail:" println getExceptionStack(ex,scriptClass) println "\texcepted:${ex.excepted}\n\tactual:${ex.actual}" }catch(Exception ex){ println ex.message println getExceptionStack(ex,scriptClass) }catch(RuntimeException ex){ println ex.message println getExceptionStack(ex,scriptClass) } } }
Application指定了脚本的基类为
com.kasonyang.httpbatch.HttpBatchScript,这个类就是主题的主体。
先上代码
package com.kasonyang.httpbatch import com.kasonyang.httpbatch.test.TestException import com.kasonyang.httprequest.HttpRequest import com.kasonyang.httprequest.HttpResponse import groovy.lang.Binding import groovy.lang.Script; abstract class HttpBatchScript extends Script { private http = new HttpRequest(); HttpResponse $$ Closure beforeGo,beforePost,afterGo,afterPost Closure testFail private String base = '' private String path = '' private String trimPath(String path,boolean left=true,boolean right=true){ int start =(left && path.startsWith('/')) ? 1 : 0; int end = (right && path.endsWith('/')) ? path.length()-1 : path.length(); path.substring(start,end) } private def getUri(uri){ base + (base?'/':'') + path + (path?'/':'') + trimPath(uri,true,false) } def base(){ this.base = '' } /** * set the base path of request * @param path the base path * @return */ def base(String path){ this.base = trimPath(path) } def enter(){ this.path = '' } /** * enter a directory in base * @param path * @return */ def enter(String path){ this.path = trimPath(path) } /** * submit a get request * @param uri the request uri * @param params the query params * @param callback call after request * @return */ HttpResponse go(String uri,Map params,Closure callback){ def httpGet = http.createGet(getUri(uri),params) this.beforeGo?.call(httpGet) def response = http.execute(httpGet) this.$$ = response if(callback) callback.call() this.afterGo?.call(response) return this.$$ } HttpResponse go(String uri,Closure callback){ return go(uri,[:],callback) } HttpResponse go(String uri,Map params){ return go(uri,params,null) } HttpResponse go(String uri){ return this.go(uri,null) } /** * submit a post request * @param uri the request uri * @param params the post params * @param callback call after request * @return */ HttpResponse post(String uri,Map params,Closure callback){ def httpPost = http.createPost(getUri(uri),params) this.beforePost?.call(httpPost) def response = http.execute(httpPost) this.$$ = response if(callback) callback.call() this.afterPost?.call(response) return this.$$ } HttpResponse post(String uri,Closure callback){ return post(uri,[:],callback) } HttpResponse post(String uri,Map params){ return post(uri,params,null) } HttpResponse post(String uri){ return this.post(uri,null) } /** * set the beforeGo callback,which whill be call before every get request * @param callback */ void beforeGo(Closure callback){ this.beforeGo = callback } /** * set the beforePost callback,which whill be call before every post request * @param callback */ void beforePost(Closure callback){ this.beforePost = callback } /** * set the callback,which whill be call when test fail * @param cb */ void testFail(Closure cb){ this.testFail = cb } /** * set the callback,which whill be call after every get request * @param callback */ void afterGo(Closure callback){ this.afterGo = callback } /** * set the callback,which whill be call after every post request * @param callback */ void afterPost(Closure callback){ this.afterPost = callback } /** * test whether it is true * @param value */ void testTrue(Object value){ testEquals(true,value) } /** * test whether actual equals the excepted * @param excepted * @param actual */ void testEquals(Object excepted,Object actual){ if(excepted != actual){ def ex = new TestException(excepted,actual) if(this.testFail){ testFail(ex) }else{ throw ex } } } /** * test whether it is null * @param value */ void testNull(Object value){ testEquals(null,value) } }
这个类主要定义了一个public属性
$$还有几个public方法,也就是post、go,和一些其它可能需要用到的函数。
因为get方法在groovy里有特殊意义,这里使用go方法名代替了get。
提示:这里使用了另外两个类,HttpRequest和HttpResponse,是自定义的两个Class,由于篇幅的原因,这里就不再贴代码了,具体实现可前往Github查看。
我已经把全部源码放到了Github,感兴趣的可以前往查看。
地址:https://github.com/kasonyang/httpbatch
构建项目
$ gradle installDist
程序被输出到
build/install/httpbatch目录下,将
bin目录添加到环境变量
PATH中。
使用
创建脚本文件 "example.hb"go "YOU_URL"//对你要测试的URL提交get请求 testEquals 200,$$.statusCode//状态码为 200? def text = $$.text //get the response as text def json = $$.json//get the response as json println text //output the response //这里添加你的测试逻辑代码 println "Test successfully!"
执行脚本文件
$ httpbatch example.hb
相关文章推荐
- HDU_5463 Clarke and minecraft
- HDU 4296 Buildings
- HDU 5033 Building(模拟凸包建立过程)
- 软件内存泄露的原因
- 区间最小值
- 配置tftp服务以及开发板中通过tftp下载文件
- POJ 1274 The Perfect Stall 水二分匹配
- Log日志打印工具
- HDU 5420 Victor and Proposition
- json jar 包的几种字符串转换
- Oracle数据库新创建实例会遇到的有关监听的问题
- oracle查询总成绩前十的学生信息sql
- Android WebService
- win7下IIS配置MVC项目
- Java基础:创建String对象时,String s=new String("abc")和String s="abc"的区别
- mp3 音频 音乐 tag ID3 ID3V1 ID3V2 标签 读取信息 获得图片 jpeg bmp 图片转换等
- Linux 常用命令(转)
- 当好职场“空降兵”
- 非常基本的SQL 内外连接
- iOS使用xib自定义uiview