Gatling 编写用户类执行动作
gatling通过
ScenarioBuilder
类来配置用户类执行动作细节:
通过调用 scenario 方法来生成并返回一个ScenarioBuilder类对象,每调用一次scenari方法,在gatling相当于定义了一个新的用户群:
val scn = scenario("blog request") // 括号内为定义的场景名字
通过调用ScenarioBuilder类里的exec方法去配置访问http的操作:
exec(http("get login").get("/login"))
// 这里在之前声明了val httpProtocol = http.baseUrl("http://localhost:4311")
// 所以这里相当于访问 http://localhost:4311/login
可以多次调用exec方法实现一个场景的多步操作):
注意:执行顺序是由编写顺序决定的,如下面代码是先执行完get("/login")的操作后才执行get("/")最后到get("/edit")
val scn = scenario("blog request")
.exec(http("get login").get("/login"))
.exec(http("get index").get("/"))
.exec(http("get edit").get("/edit"))
上面所定义的 “get login”, "get index"和 "get edit"会在gatling执行时标注在每步执行的细节中:
(这里存在一个重定向是因为自己写的网站有这步操作所以出现了 Redirect 操作,可忽略)
以上的写法只会执行一次,若想重复执行一次操作多次,则需要计数/计时器:
- 计数器
repeat(times,counterName)
times:循环次数
counterName:计数器名称 可选参数 可以用来当当前循环下标值使用 从0开始 - 计时器
during(duration, counterName, exitASAP)
duration:时长 默认单位秒 可以加单位milliseconds 表示毫秒
counterName:计数器名称 可选参数 很少使用
exitASAP:默认为true 简单的可以认为当这个为false的时候循环直接跳出 可在循环中进行控制是否继续
计数/计时器在程序中的使用:
注意:当使用了during或者repeat方法时,必须将exec用大括号括在其中,且exec不能写成.exec
val scn = scenario("blog request")
.during(10){
exec(http("get login").get("/login"))
}
.pause(2) // 暂停执行两秒 用于模拟等待时间
.exec(http("get index").get("/"))
.repeat(1000){
exec(http("get edit").get("/edit"))
}
post请求的方式(get请求没什么好说的就不展开了):
val scn = scenario("blog request")
exec(http("post login").post("/login")
//.formParam("name","node") 这里是直接请求表单
//.formParam("password","passWord")
// 下面是通过body去请求表单 效果等同于上面两句
.body(StringBody("{\"name\":\"node\",\"password\":\"passWord\"}")).asJson
参数化操作(gatling有多种参数化方式,这里只研究了列表和csv导入的方式):
列表方法:
val mapNameFeeder = Array(
Map("name" -> "node_1"),
Map("name" -> "node_2"),
Map("name" -> "node_3")).random // random 随机取值 如果想按循序循环用 circular
// 要用feed声明要读取的数组 否则${name}会找不到值 而且要在执行的exec前声明
val scn = scenario("blog request").feed(mapNameFeeder)
.exec(http("post login").post("/login")
.formParam("name", "${name}") // 动态参数name的写法 "${name}" 要带双引号
.formParam("password", 1234))
csv导入方法(csv文件必须要放在gatling文件夹下的 \user-files\resources 中):
val csvNameFeeder = csv("test.csv").random //csv的文件名
val scn = scenario("blog request").feed(csvNameFeeder)
.exec(http("post login").post("/login")
.formParam("name", "${name}")
.formParam("password", 1234))
csv文件test的内容(最终post操作效果和上面的列表完全一样):
每一个用户群里的操作都是按编写顺序执行的,若想测试同时执行的动作,可以通过定义多个用户群来实现:
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class test extends Simulation {
val httpProtocol = http.baseUrl("http://localhost:4311")
val scn1 = scenario("blog request 1")
.during(10){
exec(http("get index").get("/"))
}
val scn2 = scenario("blog request 2")
.during(10){
exec(http("get edit").get("/edit"))
}
// 通过inject来设定注入用户
// 定义需要启动的用户群,同时配置scn1,scn2,则两个用户群都会同时进行操作
setUp(
scn1.inject(atOnceUsers(10)),
scn2.inject(atOnceUsers(10))
).protocols(httpProtocol)
}
可以将exec里定义的操作代码单独包装起来,方便管理和复用且逻辑清晰(推荐):
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class test extends Simulation {
val httpProtocol = http.baseUrl("http://localhost:4311")
// 包装登入的操作
object Login {
val login =
exec(http("get index").get("/"))
.pause(2)
.exec(http("get login").get("/login"))
.pause(1)
.exec(http("post login").post("/login")
.body(StringBody("{\"name\":\"node\", \"password\":\"passWord\"}")).asJson)
}
// 包装写博客的操作
object Edit {
val edit =
exec(http("get edit").get("/edit"))
.pause(1)
.exec(http("post edit").post("/edit")
.body(StringBody("{\"title\":\"title\", \"content\":\"test\"}")).asJson)
}
// 执行顺序还是 按顺序执行完login里的操作 再按顺序执行edit里的操作
val scn = scenario("login and edit").exec(Login.login, Edit.edit)
setUp(scn.inject(atOnceUsers(10)).protocols(httpProtocol))
}
后续待补充……