Windows下的Gatling学习笔记第三季

本帖已被设为精华帖!,

浅谈架构

用面向对象的脚本去触发性能测试,你一定不会想要像第一季那样去一个一个录制脚本,然后排成一排挨着跑。这样做的最大坏处是代码无复用——你要么会做重复的录制操作,亦或是重复编写代码。这是可维护性的最大敌人。
在官方的文档http://gatling.io/docs/2.1.7/advanced_tutorial.html 这个页面的Step01和Step02处提供了很好的思路。代码如下:

object Search {

val search = exec(http("Home") // let's give proper names, as they are displayed in the reports
.get("/"))
.pause(7)
.exec(http("Search")
.get("/computers?f=macbook"))
.pause(2)
.exec(http("Select")
.get("/computers/6"))
.pause(3)
}

object Browse {

val browse = ???
}

object Edit {

val edit = ???
}
val users = scenario("Users").exec(Search.search, Browse.browse)
val admins = scenario("Admins").exec(Search.search, Browse.browse, Edit.edit)
setUp(
users.inject(rampUsers(10) over (10 seconds)),
admins.inject(rampUsers(2) over (10 seconds))
).protocols(httpConf)

1) 可以看到有三个操作Search, Browse和Edit被封装为了object. 关于scala的伴生对象object,官网上有一句话的准确定义: Objects are native Scala singletons. 实际上object就理解为一个static类就可以了,里面的成员可以直接调用——调用Search.search也就直接执行定义好的search系列请求。
2) 定义了两种类型的用户。在这里users和admins实际上是抽象的,只是定义出某种类型的用户具有什么样的功能,只有灵魂,没有肉体。普通user不能编辑,只能搜索和浏览,admin多了编辑功能。
3) setUp中为users和admins注入了具体的用户,现在用户变得有血有肉,不再只是灵魂——10秒钟内产生10个普通用户和管理员。

类似于demo,如果我们要对门户网站作测试,可以将针对页面的操作一起封装为object,方便维护,就像PageObject一样。
仍旧用新浪作为例子。我们设定一大波小学生要到新浪首页玩儿。为了显得真实一些,把这些小学生分为三种类型:一部分是库昊球迷,喜欢NBA,所以他们访问到首页后,直接进入NBA频道;一部分是阿法狗的棋迷,热爱科技,所以到达首页后直接进入科技频道;剩下的漫无目的,属于题主这种从小就很蠢的没想法没目标没理想没未来的小学生,所以就随便搜搜什么看看,来到首页后使用搜索功能。

大致可以确定的是,现在起码是有4种类型的操作可以封装:访问首页,访问NBA频道,访问科技频道,搜索。我们可以把访问到首页的脚本放置在包的根目录下,即sina.Access.scala,因为这个用户行为比较特殊——它几乎是所有连续 性行为的起点;然后把后三者封装到sina.pages.HomePage.scala中,因为这些操作都是在首页执行的。我们要做如下的事情:
#1. 首先要分别单独录制这几种操作,均放在根目录下,看看脚本。
#2. 改造脚本,将这些原子操作全部存储到object中
#3.客户端直接执行封装到object中的操作,实现代码复用

首先先录制进入NBA频道的操作
Windows下的Gatling学习笔记第三季
注意进入首页并完全加载后,清除掉已录制的所有请求,再点击进入该频道,仅保留此时开始请求以生成脚本,目的是录制单独的进入该频道的操作。
Windows下的Gatling学习笔记第三季
Windows下的Gatling学习笔记第三季
录制完成后,先把脚本晾在一边,继续完成其他几个操作的录制。
Windows下的Gatling学习笔记第三季
现在我们实行改造,先将Access.scala进行改造,存储为object

Access.scala

package sina

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

class Access extends Simulation {

val httpProtocol = http
.baseURL("http://www.sina.com.cn")
.inferHtmlResources(BlackList(""".*\.css""", """.*\.js""", """.*\.ico"""), WhiteList())

val headers_0 = Map("Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")

val headers_4 = Map("Accept" -> "*/*")

val headers_284 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Pragma" -> "no-cache")

//为简洁省略掉其他uri
val uri05 = "http://www.sina.com.cn"
......

val scn = scenario("HomePage")
.exec(http("request_0")
.get(uri05 + "/")
.headers(headers_0)
.resources(http("request_1")
.get("http://" + uri45 + "/hm.gif?cc=0&ck=1&cl=24-bit&ds=1360x768&ep=77626%2C77626&et=3&fl=20.0&ja=0&ln=zh-CN&lo=0&lt=1457426038&nv=0&rnd=227026994&si=dd4738b5fb302cb062ef19107df5d2e4&st=4&su=http%3A%2F%2Fofflintab.firefoxchina.cn%2F%3Fcachebust%3D20150714&v=1.1.22&lv=2"),
http("request_2")
.get(uri13 + "/data.html?1457426259080")
//为简洁省略大量request
.resources(http("request_351")
.get(uri61 + "/i3/160760139309563749/TB2fRfMhXXXXXatXXXXXXXXXXXX_!!43606076-0-saturn_solar.jpg_200x200.jpg")))

setUp(scn.inject(rampUsers(10) over (10 seconds))).protocols(httpProtocol)
}

我们只是封装页面,说明要做什么操作,而执行这些操作的的工作放在后面专门的client脚本中执行。所以需要把操作装到一个object中,并在其中定义一个access操作。
1). 修改Access为object
2). 去掉httpProtocol。
3).定义一个access变量,指定所发送的请求.
4). 去掉setUp的代码

修改后的代码如下:
Access.scala

package sina

import scala.concurrent.duration._

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._

**object Access {**

**/* val httpProtocol = http
.baseURL("http://www.sina.com.cn")
.inferHtmlResources(BlackList(""".*\.css""", """.*\.js""", """.*\.ico"""), WhiteList()) */
**

val headers_0 = Map("Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")

val headers_4 = Map("Accept" -> "*/*")

val headers_284 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Pragma" -> "no-cache")

//为简洁省略掉其他uri
val uri05 = "http://www.sina.com.cn"
......

**val access= exec(http("request_0")**
.get(uri05 + "/")
.headers(headers_0)
.resources(http("request_1")
.get("http://" + uri45 + "/hm.gif?cc=0&ck=1&cl=24-bit&ds=1360x768&ep=77626%2C77626&et=3&fl=20.0&ja=0&ln=zh-CN&lo=0&lt=1457426038&nv=0&rnd=227026994&si=dd4738b5fb302cb062ef19107df5d2e4&st=4&su=http%3A%2F%2Fofflintab.firefoxchina.cn%2F%3Fcachebust%3D20150714&v=1.1.22&lv=2"),
http("request_2")
.get(uri13 + "/data.html?1457426259080")
//为简洁省略大量request
.resources(http("request_351")
.get(uri61 + "/i3/160760139309563749/TB2fRfMhXXXXXatXXXXXXXXXXXX_!!43606076-0-saturn_solar.jpg_200x200.jpg")))

**/* setUp(scn.inject(rampUsers(10) over (10 seconds))).protocols(httpProtocol)*/**
}

按照同样的方法,把另外三个脚本中的请求均封装到新建立的HomePage.scala中
Windows下的Gatling学习笔记第三季
接下来专门建立一个脚本文件,放到sina.clients包下,取名为TestSina.scala,代码如下:
Windows下的Gatling学习笔记第三季
编译成功:
Windows下的Gatling学习笔记第三季
运行:
Windows下的Gatling学习笔记第三季
结果:
Windows下的Gatling学习笔记第三季

Note
#1 本文只是浅谈架构,提出其中一种思路(当然可以有其他很多思路),忽略了一些细节。例如每一个频道,baseUrl均不一样。要进行严谨的测试,需要仔细的修改和审核每一个脚本,保证最后发出请求的合理性。
#2 工具本身的意义远没有背后蕴含的测试思路和方法重要。对于性能测试的测试思路,结果分析方法等希望有路过的大神多多交流,大家共同学习。

* 注:本文来自网络投稿,不代表本站立场,如若侵犯版权,请及时知会删除