Software Performance Testing - Gatling测试脚本编写 梦里梦外; 2022-11-25 13:24 146阅读 0赞 分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!请点击[http://www.captainbed.net][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]]`对象中取出一个值,这样才能实现动态参数的需求。 [http_www.captainbed.net]: http://www.captainbed.net/troubleshooter
还没有评论,来说两句吧...