zoukankan      html  css  js  c++  java
  • 使用Groovy构建自己的脚本环境

    场景

    在进行Web服务端开发的时候,发布前通常需要测试一遍。对于一个大一点的项目,最好的办法是写个自动化测试程序。
    以Groovy为例,写测试代码之前通常的有如下几个操作

    1. 引用相关的类库
    2. import相关的类
    3. 对库不熟悉的时候你很可能得先把库的文档好好看一遍

    对于你来说,你需要的可能仅仅是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 + '
    '
    					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 += ("	File:${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 "	excepted:${ex.excepted}
    	actual:${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
    
  • 相关阅读:
    <自动化测试>之<使用unittest Python测试框架进行参数化测试>
    <自动化测试>之<unittest框架使用1>
    <自动化测试>之<selenium API 查找元素操作底层方法>
    <自动化测试>之<selenium API 用法2>
    <自动化测试>之<Selenium API 的用法1>
    <Jmeter入门不放弃>之<3.两种常见录制脚本的方法>
    <Jmeter入门不放弃>之<2.常用功能>
    <Jmeter入门不放弃>之<1.认识jmeter>
    <自动化测试>之<SeleniumIDE使用详解 >
    sql 注入get与post模式语句
  • 原文地址:https://www.cnblogs.com/kason/p/4871378.html
Copyright © 2011-2022 走看看