Gatling是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载等测试,并分析和测量服务器的各种性能指标。Gatling主要用于测量基于HTTP的服务器,比如Web应用程序,RESTful服务等,除此之外它拥有以下特点:
支持Akka Actors 和 Async IO,从而能达到很高的性能
支持实时生成Html动态轻量报表,从而使报表更易阅读和进行数据分析
支持DSL脚本,从而使测试脚本更易开发与维护
支持录制并生成测试脚本,从而可以方便的生成测试脚本
支持导入HAR(Http Archive)并生成测试脚本
支持Maven,Eclipse,IntelliJ等,以便于开发
支持Jenkins,以便于进行持续集成
支持插件,从而可以扩展其功能,比如可以扩展对其他协议的支持
开源免费
Gatling适用的场景包括:测试需求经常改变,测试脚本需要经常维护;测试环境的客户机性能不强,但又希望发挥硬件的极限性能;能对测试脚本进行很好的版本管理,并通过CI进行持续的性能测试;希望测试结果轻量易读等。
其他详解:http://www.infoq.com/cn/articles/new-generation-server-testing-tool-gatling/
使用安装
最新版本2.0.1
sbt构建 "io.gatling.highcharts" % "gatling-charts-highcharts" % "2.0.1"(GutHub应保存构建模板)
安装相对来说比较简单,根据自己系统下载相应的zip包,解压至安装目录,配置系统环境变量GATLING_HOME(WIN)
配置好环境变量后,在目录bin下有gatling.bat or gatling.sh运行脚本,运行成功后会提示用户选择测试脚本
运行成功后,会在/$gatling/results生成本次测试数据:曲线图、请求响应时间等方便查看结果统计。
使用技巧:
目前使用Gatling 1.5.6版本居多,但与2.0.1版本变化有明显差别,加入DSL等特性,具体详细
参见: http://gatling.io/docs/2.0.1/project/migration_guides/1.5.x-to-2.0.html#x-to-2-0
api doc: http://gatling.io/docs/2.0.1/
Gatling DSL:http://gatling.io/docs/2.1.4/cheat-sheet.html
使用中遇到的问题:
Q:如何对请求追加请求参数
A:对于scala来说可以用queryParamMap(Map[String,Any])来对请求方便的增加请求参数(get请求可以将map转换为K=V 的String),当然还有单个传参queryParam(String,String)等,可参考:query-parameters
Q:需要对请求后的结果进行检测或校验
A:使用check 如 check(status.is(200)),check(regex(""""<.*>""").findAll.exsits)
Q: 怎么对请求后响应的结果进行操作?操作如:将结果set到session中?
A: 上例子会更明白些,案例说明:获取用户喜欢的所有topics根据每个topic的id请求相应id的推荐
val ranking = scenario("just test userLike")
.exec(http("userLikeTopic").get("user/general_men/like.json").queryParamMap(params)
.check(status.is(200), jsonPath("$.datas[*]").ofType[Map[String,Any]]//jsonPath
.findAll.saveAs("likeTopics"))).foreach("${likeTopics}", "topics") {
exec(session => {
val topics = session("topics").as[Map[String, Any]]
session.set("cid", topics("cid"))
})
.pause(2, 5)
.exec(http("ranking") get ("topic/${cid}/rankings.json") queryParamMap (params)//可以更换为page请求
}
//设置一个用户请求 设置大于1时,是指N个用户并发访问,当然Gatling也提供了另外一种配置来解决,"多用户但并不同时并发访问" inject(rampUsers(n) over (n times))
setUp(ranking.inject(atOnceUsers(1)).protocols(httpConf))
Q:请求api时会有分页的操作,如何使用Gatling来实现分页的测试功能
A:Gatling 提供了Loop statements repeat函数,来看下这个函数的定义
repeat(times,counterName){chain}
//times 可以是Int值,指向Session("${}")的EL字符串,或者是一个表达式Expression[Int]
//counterName 可选,可用来标记当前循环计数器的名称。需要注意的是默认开始是0
官方给的小样例: 1- repeat(20){chain}//循环20次 2- repeat("${page}"){chain} //从session属性中取出page的值循环 3- repeat(session => session("page").as[Int]) //同2
有了这个函数就可以简单的实现分页测试,但是程序往往不会设计像这样,如我的项目中使用了字符串、Int值、时间戳来控制分页请求,显然这样的功能是不能满足,对此我们只需要借助repeat函数来控制外层(预期的循环次数)
使用Gatling为我们提供Conditional statements 中 提供的
def doIfOrElse(condition: Expression[Boolean])(thenNext: ChainBuilder)(elseNext: ChainBuilder): B = doIf(condition, thenNext, Some(elseNext))
修改后为
def buildPaging(actionTitle: String, thenUrl: String, attributeKey: String = "last_pos", loopTimes: Int = 5) = {
loopWithCondition(session => !session.contains(attributeKey), loopTimes) {
exec(http(actionTitle) get thenUrl check(status.is(200), jsonPath("$.last_pos").saveAs(attributeKey)))//偷懒 jsonPath可以作为一个参数传入
} {
exec(http(actionTitle) get (thenUrl + "&start=${" + attributeKey + "}") check(status.is(200), jsonPath("$.last_pos").saveAs(attributeKey)))
}.exec(session => session.remove(attributeKey)).pause(50.milli)
}
def loopWithCondition(condition: Expression[Boolean], times: Int)(thenNext: ChainBuilder)(elseNext: ChainBuilder) =
repeat(times)(doIfOrElse(condition)(thenNext)(elseNext))
后续整理中...