UnRAVL简介和简单使用

UnRAVL 简介

什么是UnRAVL

UnRAVL 是一种通过编写JSON,来验证REST格式API的开源免费的自动化测试框架。
  
  github地址:https://github.com/sassoftware/unravl

JSON文件内容

通过UnRAVL定义的一些关键字(语法)来编写JSON文件,这个JSON文件的描述可以包括HTTP method,URL,HTTP Headers ,Request Body,认证AUT等。其中HTTP method 包括GET,POST,PUT,DELETE,HEAD,PATCH,为必须包括项,URL也为必须,而其它三个均为可选项目。

Paste_Image.png

UnRAVL 脚本语法

如下是从github上直接复制得到的关于UnRAVL脚本的JSON语法,如果想了解更多可以点击描述中的链接查看每个语法更详细的说明。

Syntax element. Description
{ An UnRAVL test script is a JSON object which begins with an open brace
"name" : "test name", The name of this test
"doc" : "a comment", More detailed comments/description
"template" : "template-name", Inheritance of tests via templates
"env" : {env-bindings}, Assign variables in the environment
"preconditions" : [assertions], Assert preconditions are true before calling the API
"if" : condition, Conditionally execute the test if condition is true
"headers" : {request-headers} Names/values of request headers to pass to the API
"auth" : {authentication}, Use authentication to call the API
method : "URL", The HTTP method GET, POST, PUT, DELETE, HEAD, PATCH and target URL
"body" : {body-specification} The request body (text, JSON, binary)
"bind" : [api-bindings] Bind (extract) values from the response
"assert: [assertions] Validate the response with assertions
} End of the JSON object

以下是个人对其中几个常用语法的简单认识:


Paste_Image.png

例子

编写GET请求,并对返回值做校验

  {
    "name": "Google Everest Elevation setup",
    "env": {
      "locations": "27.988056,86.925278",
      "sensor": "false",
      "url": "http://maps.googleapis.com/maps/api/elevation/json?locations={locations}&sensor={sensor}"
    },
    "doc": "Save the response to assertJson.json",
    "GET": "{url}",
    "bind": [
      {
        "doc": "save a json file"
      },
      {
        "json": "@reponseBody.json"
      },
      {
        "doc": "jsonpath"
      },
      {
        "jsonPath": {
          "actualElevation": "$.results[0].elevation",
          "actuallat": "$.results[0].location.lat",
          "actuallng": "$.results[0].location.lng"
        }
      }
    ],
    "assert": [
      {
        "status": 200
      },
      {
        "groovy": "status == 200"
      },
      {
        "headers": {
          "Content-Type": "application/json; *charset=UTF-8"
        }
      },
      {
        "json": "@assertJson.json"
      },
      "actualElevation==8815.7158203125",
      "actuallat != 0",
      "actuallng > 0",
      "actuallat != null"
    ]
  }

接口返回json:

{
  "results" : [ {
    "elevation" : 8815.7158203125,
    "location" : {
      "lat" : 27.988056,
      "lng" : 86.925278
    },
    "resolution" : 152.7032318115234
  } ],
  "status" : "OK"
}

解释:

  1. name: 用于定义该API或者Case的描述。
  2. env: 里面定义了三个变量,locations,sensor,url,其中url中还通过{locations}{sensor}来获取同样evn里面的两个变量值,最后拼接成一个完整的接口地址。
  3. doc: 因JSON文件本身不提供像其他编程语言的注释功能,所以doc关键字的提供在这里就是起到注释作用。
  4. GET: GET就是表示HTTP请求方法是GET,上面已经提到UnRAVL提供了GET外的多种请求方式,GET的对应的值{url}则表示从env中获取url对应的值地址。
    bind:里面包含多块,其中doc一样是注解作用;
      "json": "@reponseBody.json",则表示把response的body用json文件保存到该用例json文件同级目录底下;  
      jsonPath 里面则是在解析请求返回的json。
  5. assert:关键字用于做校验,这个例子尽可能的列出多种校验方式,
      其中"status": 200 表示校验请求的状态码是否为200;
      "groovy": "status == 200"则表示通过groovy语音来校验状态码(UnRAVL支持groovy和JavaScript语法);
      "headers": { "Content-Type": "application/json; *charset=UTF-8" } 表示校验接口返回的headers是否有Content-Type值为application/json; *charset=UTF-8;
      "json": "@assertJson.json"则表示response body直接跟外部文件assertJson.json对比,对比整个json文件是否一致;
      最后"actuallat != 0"等则是把bind的中jsonPath解析的结果和预期值做对比。

POST 请求

{
  "name" : "POST a hello message to httpbin",
  "env" : {
    "data1" : {
      "greeting" : "Hello, httpbin, from UnRAVL"
    }
  },
  "POST" : "http://www.httpbin.org/post",
  "headers" : {
    "Content-Type" : "text/plain",
    "Accept" : "text/plain",
    "Agent" : "UnRAVL"
  },
  "body" : {
    "json" : "data1"
  },
  "bind" : [
    {
      "json" : "@-"
    },
    {
      "groovy" : {
        "actualJson" : "responseBody.json",
        "headersJson" : "responseBody.headers"
      }
    }
  ],
  "assert" : [
    "data1 == actualJson",
    "headersJson['Accept'].textValue() == 'text/plain'",
    "headersJson['Content-Type'].textValue() == 'text/plain'",
    "headersJson['Agent'].textValue() == 'UnRAVL'"
  ]
}

接口请求返回结果:

{
  "args" : { },
  "data" : "{\"greeting\":\"Hello, httpbin, from UnRAVL\"}",
  "files" : { },
  "form" : { },
  "headers" : {
    "Accept" : "text/plain",
    "Accept-Encoding" : "gzip,deflate",
    "Agent" : "UnRAVL",
    "Content-Length" : "42",
    "Content-Type" : "text/plain",
    "Host" : "www.httpbin.org",
    "User-Agent" : "Apache-HttpClient/4.5 (Java/1.8.0_101)"
  },
  "json" : {
    "greeting" : "Hello, httpbin, from UnRAVL"
  },
  "origin" : "59.60.10.35",
  "url" : "http://www.httpbin.org/post"
}
{
  "args" : { },
  "data" : "{\"greeting\":\"Hello, httpbin, from UnRAVL\"}",
  "files" : { },
  "form" : { },
  "headers" : {
    "Accept" : "text/plain",
    "Accept-Encoding" : "gzip,deflate",
    "Agent" : "UnRAVL",
    "Content-Length" : "42",
    "Content-Type" : "text/plain",
    "Host" : "www.httpbin.org",
    "User-Agent" : "Apache-HttpClient/4.5 (Java/1.8.0_101)"
  },
  "json" : {
    "greeting" : "Hello, httpbin, from UnRAVL"
  },
  "origin" : "59.60.10.35",
  "url" : "http://www.httpbin.org/post"
}

解释:

  1. POST:表示HTTP 请求方式。
  2. heasers: 设置请求的headers值。
  3. body: 设置请求的body值,例子中获取evn中的data1的值。
  4. bind: 通过groovy关键字,表示使用groovy脚本,"responseBody.json" 获取接口请求返回的json中的叫“json”key的value值 , "responseBody.headers" 获取接口请求返回的json中的key名叫“headers”的value值。
  5. assert: 校验结果。 其中"data1 == actualJson", 用于校验接口返回的值是否与预期一致。 "headersJson['Accept'].textValue() == 'text/plain'",用于再具体解析请求返回的Json中的“headers” key中key为“Accept”的值是否为“text/plain”。

使用template

[
  {
    "name": "Google Everest Elevation setup",
    "env": {
      "url": "http://maps.googleapis.com/maps/api/elevation/json?locations=27.988056,86.925278&sensor=false"
    },
    "doc": "Save the response to GoogleEverestElevation.json",
    "GET": "{url}",
    "assert": [
      {
        "json": "@assertJson.json"
      }
    ]
  },
  {
    "name": "ThisIsATemplate.template",
    "doc": "Template which invokes the GET and asserts the response equals the contents of assertJson.json",
    "GET": "{url}",
    "assert": {
      "json": "@assertJson.json"
    }
  },
  {
    "name": "GoogleEverestElevation GET 3 use template",
    "template": "ThisIsATemplate.template"
  }
]

解释:

  1. 第一个{}内是一个完整的GET请求,并对接口返回跟assertJson.json文件做对比。
  2. 第二个name取名比较特殊:ThisIsATemplate.template这个名以.template为结尾则表示这个模块是一个template,template名为ThisIsATemplate。 模块的作用类似编程语言的公共方法,例如这个模块完成了GET请求的发起和对response整个json和assertJson.json文件的校验。
  3. 第三个name开始则表示新的Case,这个case里面"template": "ThisIsATemplate.template",则表示这个Case调用上面的template,这样这个case虽然这有name和template两个关键字但是同样完成从了GET请求的发起和结果跟外部json文件的校验。

运行

当我们编写好我们的接口Json文件后,就得考虑怎么把他们运行起来,UnRAVL 提供了多种的运行方式。

通过GUI运行

UnRAVL 提供了GUI界面来运行和调试Case。想要通过GUI方式来运行需要先下载UnRAVL包(https://github.com/sassoftware/unravl/releases),找到unravl-1.2.1.zip(目前最新版),并下载解压。得到如下目录:

Paste_Image.png

其中doc是官方帮助文档,lib是依赖的jar包。
双击打开bin文件,根据自己系统双击运行unravl.bat或者unravl.sh文件便可以打开如下GUI界面。

Paste_Image.png

  关于GUI界面的更多使用说明,可以在doc文件夹中的UI.md文件查看,或者访问https://github.com/sassoftware/unravl/blob/master/doc/ui/UI.md 查看更多
  GUI工具便于平时写Json脚本时边编写边调试使用,但是他每次只能运行一个Json文件,所以不方便我们做自动化。

通过命令行运行

除了通过GUI工具,还可以通过命令行来运行脚本,运行方式也较为简单,在下载好GUI工具包解压后,打开控制台进入到bin目录,运行:unravl.bat D:\unravl\script\getDemo.json,后面跟上需要被执行的Json文件便可。

Paste_Image.png

这种方式也是非常不方便,不建议使用。

通过Junit运行

Junit运行是比较推荐的方式,他可以批量运行多个Json,可以指定运行某个文件夹底下的所有Json文件,也可以很好的跟Jenkins结合,并生成Junit测试报告。
  想通过这种方式运行,我们需要把UnRAVL项目搭建起来,可以直接GitHub上下载工程,也可以把UnRAVL相关包引入到Java工程中。
  再新建好UnRAVL项目后,新建个java类,并添加junit的@Test方法,具体代码如下:

import com.sas.unravl.assertions.JUnitWrapper;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;

public class RunScripts {

    static Map<String, Object> env() {
        Map<String, Object> env = new HashMap<String, Object>();
        return env;
    }

    @Test
    public void runScript1() {
        //  运行当个json文件
        JUnitWrapper.runScriptFiles(env(), "src/test/scripts/demo/asd.json");
    }

    @Test
    public void runFailingScripts() {
        //  运行fail文件夹下的所有json文件
        JUnitWrapper.runScriptsInDirectory(env(), "src/test/scripts/fail");
    }
}

全局变量

UnRAVL 没有全局变量的概念,但是我们平时测试又需要用到,简单说一处修改所有引用生效,例如接口需要不同的环境。 UnRAVL 提供了另一种解决方法,不过编写一个Case这里需要涉及3个json文件。
  第一个Json文件evn.json,我们用于设置“全局变量”,例如下:

{
  "name": "set environment",
  "doc": "This script is called by ../parts.son",
  "env": {
    "URL": "http://www.qa.org/post",
    "greeting":"Hello, httpbin, from UnRAVL"
  }
}

第二个Json文件caseTest.json,就是我们正常的一个Case的Json,例如下:

{
  "name": "assert environment set by env.json.",
  "doc": "This script is called by ../parts.son",
  "POST":"{URL}",
  "body":"{\"greeting\" : \"{greeting}\"}"
}

我们发现这个caseTest.json文件的POST和greeting都是取变量的,而该json却都没定义这两个参数,evn.json文件却定义了这两个变量,那两个不同的json文件如何传递变量呢?这时我们就需要用到第三个json文件。
  第三个Json文件,parts.json,具体内容如下:

[
  "@src/test/scripts/demo/env.json",
  "@src/test/scripts/demo/caseTest.json"
]

其实第三个json文件只放如需要关联的json文件。并在运行时,运行该第三个json文件便可。

与Jenkins结合

当通过Junit方式运行脚本,我们就很容易和Jenkins结合,从而达到自动构建或者每日构建等。

Jenkins Job 配置

  1. 新建一个自由风格的job


    new job
  2. 源码管理
      根据自己实际情况选择一种源码管理,例如我选用的是git,那么我只需要配置下git的一些账号密码等就可以。

源码管理
  1. 构建
      因为工程是 maven 工程,所以可以直接添加maven的构建方式(Invoke top-level Maven targets),并在Goals 中配置“clean test”,其余均可以默认
maven构建
  1. 测试报告
      Jenkins 提供了 Junit的测试报告,我们只需要在配置中的构建后操作添加Publish JUnit test result report,并设置build后生成的.xml的路径,便可。
junit report
  1. 等等
      Jenkins 还提供了如每日构建,构建失败发邮件等等的功能,可以根据自己需要配置。

简单分析

优点

  1. 简单的接口编写json文件比较容易
  2. 可以走流程
  3. 开源
  4. 扩展性良好

不足

  1. 无法与数据库交互
  2. 与拥有UI界面的自动化测试工具相比,上手难度较大
  3. 复杂接口不容易编写
  4. 小众
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,590评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,729评论 6 342
  • 博客已迁移,该文章也是我16年那会写的了,经过几年Postman已经有不少变化,最近换团队为了推广这个工具,我对P...
    博客已迁移I米阳阅读 45,664评论 29 92
  • 黄土岗义工站建立于2016年7月15号,是麻城义工联分站,在去年7月麻城洪灾我们麻城义工参加了整个麻城各乡镇的救灾...
    冷月魅世阅读 819评论 1 3
  • 记得很早看过一部影片《色即是空》,好像是韩国出的,表面看起来有点色,但从另外一个角度看,世间彩色的吸引,不止是一个...
    张永刚阅读 647评论 0 1