Software Performance Testing - Gatling测试脚本编写

分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击http://www.captainbed.net

脚本示例

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._

class BaiduSimulation extends Simulation {
  // 设置请求的根路径
  val httpConf = http.baseURL("https://www.baidu.com")

  // 运行100秒 during 默认单位秒,如果要用微秒 during(100 millisecond)
  val scn = scenario("BaiduSimulation").during(100){
    exec(http("baidu_home").get("/"))
  }

  // 设置线程数
  setUp(scn.inject(atOnceUsers(10)).protocols(httpConf))
}

脚本编写

Gatling脚本的编写主要包含下面三个步骤:

  • http head配置
  • Scenario执行细节
  • setUp组装

这里以百度为例,进行第一个GET请求测试脚本的编写,类必须继承自Simulation。

1、配置下head,只是简单的请求下百度首页,所以只定义下请求的base url,采用默认的http配置即可

// 设置请求的根路径
val httpConf = http.baseURL("https://www.baidu.com")

2、声明Scenario,指定请求动作

val scn = scenario("BaiduSimulation").exec(http("baidu_home").get("/"))

scenario里的参数:scenario name
exec()里的参数就是我们的执行动作,http(“本次请求的名称”).get(“本次http get请求的地址”)

3、设置并发数并组装

// 设置线程数
setUp(scn.inject(atOnceUsers(10)).protocols(httpConf))

atOnceUsers:立马启动的用户数,可以理解为并发数

这样我们一个简单的脚本就完成了。

高级教程

Injection – 注入

注入方法用来定义虚拟用户的操作

setUp(
  scn.inject(
    nothingFor(4 seconds), // 1
    atOnceUsers(10), // 2
    rampUsers(10) over(5 seconds), // 3
    constantUsersPerSec(20) during(15 seconds), // 4
    constantUsersPerSec(20) during(15 seconds) randomized, // 5
    rampUsersPerSec(10) to 20 during(10 minutes), // 6
    rampUsersPerSec(10) to 20 during(10 minutes) randomized, // 7
    splitUsers(1000) into(rampUsers(10) over(10 seconds)) separatedBy(10 seconds), // 8
    splitUsers(1000) into(rampUsers(10) over(10 seconds)) separatedBy atOnceUsers(30), // 9
    heavisideUsers(1000) over(20 seconds) // 10
  ).protocols(httpConf)
)

nothingFor(duration):设置一段停止的时间

  1. atOnceUsers(nbUsers):立即注入一定数量的虚拟用户

  2. rampUsers(nbUsers) over(duration):在指定时间内,设置一定数量逐步注入的虚拟用户

  3. constantUsersPerSec(rate) during(duration):定义一个在每秒钟恒定的并发用户数,持续指定的时间

  4. constantUsersPerSec(rate) during(duration) randomized:定义一个在每秒钟围绕指定并发数随机增减的并发,持续指定时间

  5. rampUsersPerSec(rate1) to (rate2) during(duration):定义一个并发数区间,运行指定时间,并发增长的周期是一个规律的值

  6. rampUsersPerSec(rate1) to(rate2) during(duration) randomized:定义一个并发数区间,运行指定时间,并发增长的周期是一个随机的值

  7. heavisideUsers(nbUsers) over(duration):定义一个持续的并发,围绕和海维赛德函数平滑逼近的增长量,持续指定时间(译者解释下海维赛德函数,H(x)当x>0时返回1,x<0时返回0,x=0时返回0.5。实际操作时,并发数是一个成平滑抛物线形的曲线)

  8. splitUsers(nbUsers) into(injectionStep) separatedBy(duration):定义一个周期,执行injectionStep里面的注入,将nbUsers的请求平均分配

  9. splitUsers(nbUsers) into(injectionStep1) separatedBy(injectionStep2):使用injectionStep2的注入作为周期,分隔injectionStep1的注入,直到用户数达到nbUsers

循环

 可以使用以下两种方式:

1、repeat

/*
repeat(times,counterName)
times:循环次数
counterName:计数器名称,可选参数,可以用来当当前循环下标值使用,从0开始
*/
val scn = scenario("BaiduSimulation").repeat(100){
    exec(http("baidu_home").get("/"))
}

2、during

/*
during(duration, counterName, exitASAP)
duration:时长,默认单位秒,可以加单位milliseconds,表示毫秒
counterName:计数器名称,可选。很少使用
exitASAP:默认为true,简单的可以认为当这个为false的时候循环直接跳出,可在
循环中进行控制是否继续
*/
// 运行100秒,during默认单位为秒,如果要用微秒使用during(100 millisecond)
val scn = scenario("BaiduSimulation").during(100){
    exec(http("baidu_home").get("/"))
}

POST请求

JSON方式

import io.gatling.core.Predef._
import io.gatling.core.scenario.Simulation
import io.gatling.http.Predef._

class JsonSimulation extends Simulation {
val httpConf = http.baseURL("http://127.0.0.1:7001/tst")

// 注意这里,设置提交内容type
val headers_json = Map("Content-Type" -> "application/json")
val scn = scenario("json scenario")
    .exec(http("test_json") //http请求name
    .post("/order/get") //post url
    .headers(headers_json) //设置body数据格式
    //将json参数用StringBody包起,并作为参数传递给function body()
    .body(StringBody("{\"orderNo\":201519828113}")))
setUp(scn.inject(atOnceUsers(10))).protocols(httpConf)
}

Form方式

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

class FormSimulation extends Simulation {
val httpConf = http.baseURL("http://computer-database.gatling.io")

// 注意这里,设置提交内容type
val contentType = Map("Content-Type" -> "application/x-www-form-urlencoded")

// 声明scenario
val scn = scenario("form Scenario")
    .exec(http("form_test") //http请求name
    .post("/computers") //post地址,真正发起的地址会拼上上面的baseUrl http://computer-database.gatling.io/computers
    .headers(contentType)
    .formParam("name", "Beautiful Computer") //form表单的property name = name, value=Beautiful Computer
    .formParam("introduced", "2012-05-30")
    .formParam("discontinued", "")
    .formParam("company", "37"))
setUp(scn.inject(atOnceUsers(1)).protocols(httpConf))
}

RawFileBody

import io.gatling.core.Predef._
import io.gatling.core.scenario.Simulation
import io.gatling.http.Predef._

class JsonSimulation extends Simulation {
val httpConf = http.baseURL("http://127.0.0.1:7001/tst")

// 注意这里,设置提交内容type
val headers_json = Map("Content-Type" -> "application/json")
val scn = scenario("json scenario")
    .exec(http("test_json") //http请求name
    .post("/order/get") //post url
    .headers(headers_json) //设置body数据格式
    //将json参数用StringBody包起,并作为参数传递给function body()
    .body(RawFileBody("request.txt"))
setUp(scn.inject(atOnceUsers(10))).protocols(httpConf)
}

txt的文件内容为JSON数据,存放在目录/resources/bodies下。

Feed动态参数

Gatling对参数的处理称为Feeder【供料器】,支持主要有:

数组

val feeder = Array(
Map("foo" -> "foo1", "bar" -> "bar1"),
Map("foo" -> "foo2", "bar" -> "bar2"),
Map("foo" -> "foo3", "bar" -> "bar3"))

CSV文件

val csvFeeder = csv("foo.csv") //文件路径在 %Gatling_Home%/user-files/data/ 下

JSON文件

val jsonFileFeeder = jsonFile("foo.json")
// json的形式:
[
{
    "id":19434,
    "foo":1
},
{
    "id":19435,
    "foo":2
}
]

JDBC数据

jdbcFeeder("databaseUrl", "username", "password", "SELECT * FROM users")

Redis

可参看官方文档http://gatling.io/docs/2.1.7/session/feeder.html#feeder

使用示例:

import io.gatling.core.Predef._
import io.gatling.core.scenario.Simulation
import io.gatling.http.Predef._
import scala.concurrent.duration._

/**
* region请求接口测试
*/
class DynamicTest extends Simulation {
val httpConf = http.baseURL("http://127.0.0.1:7001/test")
// 地区feeder
val regionFeeder = csv("region.csv").random
// 数组形式
val mapTypeFeeder = Array(
    Map("type" -> ""),
    Map("type" -> "id_to_name"),
    Map("type" -> "name_to_id")).random
// 设置请求地址
val regionRequest =
    exec(http("region_map").get("/region/map/get"))
    // 加载mapType feeder
    .feed(mapTypeFeeder)
    // 执行请求,feeder里key=type,在下面可以直接使用${type}
    .exec(http("province_map").get("/region/provinces?mType=${type}"))
    // 加载地区feeder
    .feed(regionFeeder)
    // region.csv里title含有provinceId和cityId,所以请求中直接引用${cityId}/${provinceId}
    .exec(http("county_map").get("/region/countties/map?mType=${type}&cityId=${cityId}&provinceId=${provinceId}"))

// 声明scenario name = dynamic_test
val scn = scenario("dynamic_test")
        .exec(during(180){ regionRequest
        })
// 在2秒内平滑启动150个线程(这里线程数需要评估)
setUp(scn.inject(rampUsers(150) over (2 seconds)).protocols(httpConf))
}

注意:通过下面的代码只会第一次调用生成一个随机数,后面调用不变。

exec(http("Random id browse")
        .get("/articles/" + scala.util.Random.nextInt(100))
        .check(status.is(200))

Gatling的官方文档解释是:由于DSL会预编译,在整个执行过程中是静态的。因此Random在运行过程中就已经静态化了,不会再执行。应改为使用Feeder实现,Feeder是Gatling用于实现注入动态参数或变量的。

val randomIdFeeder =
    Iterator.continually(Map("id" ->
        (scala.util.Random.nextInt(100))))

feed(randomIdFeeder)
    .exec(http("Random id browse")
        .get("/articles/${id}"))
        .check(status.is(200))

feed()在每次执行时都会从Iterator[Map[String, T]]对象中取出一个值,这样才能实现动态参数的需求。

猜你喜欢

转载自blog.csdn.net/chimomo/article/details/107897846