百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Gatling官网教程翻译之Advanced Tutorial

zhezhongyun 2024-12-30 08:13 56 浏览

高级教程

在这一部分,我们假设读者已经完成了前面Quickstart的学习部分。而且你已经有了一个基础的simulation。

我们在这一部分将通过一系列的重构,向读者介绍更多Gatling的高级用法和DSL结构。

回顾下已有的Simulation:

  1.  1 package computerdatabase 2 import io.gatling.core.Predef._ 3 import io.gatling.http.Predef._ 4 import scala.concurrent.duration._ 5 classBasicSimulationextendsSimulation{ 6 val httpConf = http 7 .baseURL("http://computer-database.gatling.io") 8 .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") 9 .doNotTrackHeader("1") 10 .acceptLanguageHeader("en-US,en;q=0.5") 11 .acceptEncodingHeader("gzip, deflate") 12 .userAgentHeader("Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0") 13 val scn = scenario("BasicSimulation") 14 .exec(http("request_1") 15 .get("/")) 16 .pause(5) 17 setUp( 18 scn.inject(atOnceUsers(1)) 19 ).protocols(httpConf) 20 }

Step 1. 将进程独立出来

现在,我们的simulation脚本,是一大整块的场景。

首先,我们得把它拆分成组合在一起的各个进程,就像Selenium里面的Page Object 模式一样(译者简单解释下Selenium的Page Object Pattern:核心就是实现页面与元素分离,方便扩展和维护)。这样做的好处是,你可以轻松地服用某些部分去完成复杂的操作,而不用牺牲程序的稳定性。

在我们的场景中,我们有三个彼此分开的进程(其实就是要测试的三个场景):

我们会把它们提取出来,放到对象里面。这里的对象,指的是Scala的单例;你可以把它们创建到指定的文件里面,或者和Simulation放到一起。

  1.  1 object Search{ 2 val search = exec(http("Home")// let's give proper names, as they are displayed in the reports 3 .get("/")) 4 .pause(7) 5 .exec(http("Search") 6 .get("/computers?f=macbook")) 7 .pause(2) 8 .exec(http("Select") 9 .get("/computers/6")) 10 .pause(3) 11 } 12 object Browse{ 13 val browse =??? 14 } 15 object Edit{ 16 val edit =??? 17 }

我们现在就可以用可重用的事务进程,重写我们的脚本:

  1. 1 val scn = scenario("Scenario Name").exec(Search.search,Browse.browse,Edit.edit)

Step 2. 配置虚拟用户(Vuser)

看看我们的脚本,只有一个虚拟用户(Vuser),你是在逗我吗?

怎么办,加呗!

我们定义两个用户群体:

普通用户:他们只能search和browse models

管理员用户:他们能search、browse和edit models

用脚本实现的场景是这样的:

  1. 1 val users = scenario("Users").exec(Search.search,Browse.browse) 2 val admins = scenario("Admins").exec(Search.search,Browse.browse,Edit.edit)

下面这段话就是用来设置虚拟用户的,里面的那个10:

  1. 1 setUp(users.inject(atOnceUsers(10)).protocols(httpConf))

这样,我们就设置了10个并发用户。我们就这10个用户,因为我们不想一下子就挂掉server。Server是人类的好朋友,慈悲点有好处的。

你要是有3000个并发用户的话,估计你也不想一下子就全都启动。因为,真实的用户行为也是逐渐地进行访问的(译者:一般的性能测试工具做不到同时起来那么多Vuser)。

Gatling提供一种叫做 rampUsers 的虚拟用户可以模拟这种行为。ramp user 就是指,被一点一点排着队启动的虚拟用户。

下面这么写就是设置了10个普通用户和2个管理用户,他们每人工作10秒钟,因为我们要善待服务器:

  1. 1 setUp( 2 users.inject(rampUsers(10) over (10 seconds)), 3 admins.inject(rampUsers(2) over (10 seconds)) 4 ).protocols(httpConf)

Step 3. 使用Feeder实现数据动态化

现在我们已经知道了如何创建一大堆不同权限的虚拟用户了。但有个问题,他们都在搜索一个model啊,太傻了,得让他们干点不同的事啊!

我们得弄点动态的数据,让我们的Vuser实现不同的场景,并以不同的方式结束。这就是我们为什么需要Feeder。

Feeder究竟是啥?其实Feeder就是你想用的动态数据源。一种最简单常见的Feeder就是CSV。我们下面就看看怎么用CSV存储数据:

首先,我们建一个叫做search.csv的文件,放在user-files/data文件夹下面。

这个文件里面就如下3行东西:

现在,我们就用上面的数据做一个动态的Feeder。

  1.  1 object Search{ 2 val feeder = csv("search.csv").random // 1, 2 3 val search = exec(http("Home") 4 .get("/")) 5 .pause(1) 6 .feed(feeder)// 3 7 .exec(http("Search") 8 .get("/computers?f=${searchCriterion}")// 4 9 .check(css("a:contains('${searchComputerName}')","href").saveAs("computerURL")))// 5 10 .pause(1) 11 .exec(http("Select") 12 .get("${computerURL}"))// 6 13 .pause(1) 14 }

解释下:

1. 首先,我们从search.csv里面定义了一个feeder,里面有两列:searchCriterion和searchComputerName;

2. 因为feeder的默认使用方式是线性的,用两次就用完了,然后就该挂球了。我们使用random去随机取值,来避免这种情况;

3. 每次调用的时候,searchCriterion和searchComputerName两个变量被随机取值;

4. 我们使用Gatling中的EL(表达式语言,就是${****}这种写法的东东)方式来参数化搜索;

5. 我们使用CSS selector的方式去定位HTML的返回值,这里的写法是超链接,然后把它存到用户会话中,也就是computerURL。你可以看到Scala三重引用的好处——你不必像很多其他语言那样,使用反斜杠\把你的正则表达式弄得乱七八糟;

6. 我们用这个已经定位的computerURL,就得到了一个确切的网址。

Step 4. 循环

我们发现,在browse这个进程中,我们有大量的操作都是通过页面循环,这样就带来了很多重复。我们使用了不同的请求参数发了4次相同的请求。

这就违反了DRY(别写重复代码)原则,下面我们来优化这点:

首先,我们把重复的exec抽出来,封装成一个函数。Simulation是一个典型的Scala类,所以你可以使用任何Scala的语法(译者特别讨厌作者无休止地安利Scala)。

  1. 1 object Browse{ 2 def gotoPage(page:Int)= exec(http("Page "+ page) 3 .get("/computers?p="+ page)) 4 .pause(1) 5 val browse = exec(gotoPage(0), gotoPage(1), gotoPage(2), gotoPage(3), gotoPage(4)) 6 }

上面的代码通过页面的号码访问,这就减少了代码重复。

但是下面这个写法更臭屁:

1 object Browse{
2 val browse = repeat(5,"n"){// 1
3 exec(http("Page ${n}")
4 .get("/computers?p=${n}"))// 2
5 .pause(1)
6 }
7 }

解释下:

1. 这里的repeat是一个runtime类封装好的循环方法,这里就是循环5次,然后保存到用户会话中;

2. 这里我们使用EL方法来实现访问第几页;

Step 5. check的使用和场景失败的处理

目前为止,我们一直在使用check来从html返回中校验一些数据。但其实check是可以检查网络状态码的。

check的默认值就是检查20X和304.

为了介绍Gatling的失败处理机制,我们使用check检查一个随机失败的脚本

  1. 1 import java.util.concurrent.ThreadLocalRandom// 1 2 val edit = exec(http("Form") 3 .get("/computers/new")) 4 .pause(1) 5 .exec(http("Post") 6 .post("/computers") 7 .check(status.is(session =>200+ThreadLocalRandom.current.nextInt(2))))// 2

解释下:

1. 我们先引用ThreadLocalRandom来生成随机值;

2. 我们用一个lambda函数去定义一个返回值。这里的lambda函数总返回200或者201。因为返回的状态码是200,所以当检查201的时候,就是check失败了;

管理这种随机失败的场景,我们需要使用两个叫做tryMax和exitHereIfFailed的东东,大致结构如下:

  1. 1 val tryMaxEdit = tryMax(2){// 1 2 exec(edit) 3 }.exitHereIfFailed // 2

解释下:

1. tryMax的意思是,如果执行多少次失败才算失败,比如例子中就是两次;

2. exitHereIfFailed的意思就是认定了以失败作为场景的check结果;

下载官方安装包后,这些代码都会在user-files/simulations里面,读者可以看得到。

就这些了,学会了就是Gatling高级用户了(译者觉得懂了这些其实才刚刚开始而已)!

相关推荐

Python入门学习记录之一:变量_python怎么用变量

写这个,主要是对自己学习python知识的一个总结,也是加深自己的印象。变量(英文:variable),也叫标识符。在python中,变量的命名规则有以下三点:>变量名只能包含字母、数字和下划线...

python变量命名规则——来自小白的总结

python是一个动态编译类编程语言,所以程序在运行前不需要如C语言的先行编译动作,因此也只有在程序运行过程中才能发现程序的问题。基于此,python的变量就有一定的命名规范。python作为当前热门...

Python入门学习教程:第 2 章 变量与数据类型

2.1什么是变量?在编程中,变量就像一个存放数据的容器,它可以存储各种信息,并且这些信息可以被读取和修改。想象一下,变量就如同我们生活中的盒子,你可以把东西放进去,也可以随时拿出来看看,甚至可以换成...

绘制学术论文中的“三线表”具体指导

在科研过程中,大家用到最多的可能就是“三线表”。“三线表”,一般主要由三条横线构成,当然在变量名栏里也可以拆分单元格,出现更多的线。更重要的是,“三线表”也是一种数据记录规范,以“三线表”形式记录的数...

Python基础语法知识--变量和数据类型

学习Python中的变量和数据类型至关重要,因为它们构成了Python编程的基石。以下是帮助您了解Python中的变量和数据类型的分步指南:1.变量:变量在Python中用于存储数据值。它们充...

一文搞懂 Python 中的所有标点符号

反引号`无任何作用。传说Python3中它被移除是因为和单引号字符'太相似。波浪号~(按位取反符号)~被称为取反或补码运算符。它放在我们想要取反的对象前面。如果放在一个整数n...

Python变量类型和运算符_python中变量的含义

别再被小名词坑哭了:Python新手常犯的那些隐蔽错误,我用同事的真实bug拆给你看我记得有一次和同事张姐一起追查一个看似随机崩溃的脚本,最后发现罪魁祸首竟然是她把变量命名成了list。说实话...

从零开始:深入剖析 Spring Boot3 中配置文件的加载顺序

在当今的互联网软件开发领域,SpringBoot无疑是最为热门和广泛应用的框架之一。它以其强大的功能、便捷的开发体验,极大地提升了开发效率,成为众多开发者构建Web应用程序的首选。而在Spr...

Python中下划线 ‘_’ 的用法,你知道几种

Python中下划线()是一个有特殊含义和用途的符号,它可以用来表示以下几种情况:1在解释器中,下划线(_)表示上一个表达式的值,可以用来进行快速计算或测试。例如:>>>2+...

解锁Shell编程:变量_shell $变量

引言:开启Shell编程大门Shell作为用户与Linux内核之间的桥梁,为我们提供了强大的命令行交互方式。它不仅能执行简单的文件操作、进程管理,还能通过编写脚本实现复杂的自动化任务。无论是...

一文学会Python的变量命名规则!_python的变量命名有哪些要求

目录1.变量的命名原则3.内置函数尽量不要做变量4.删除变量和垃圾回收机制5.结语1.变量的命名原则①由英文字母、_(下划线)、或中文开头②变量名称只能由英文字母、数字、下画线或中文字所组成。③英文字...

更可靠的Rust-语法篇-区分语句/表达式,略览if/loop/while/for

src/main.rs://函数定义fnadd(a:i32,b:i32)->i32{a+b//末尾表达式}fnmain(){leta:i3...

C++第五课:变量的命名规则_c++中变量的命名规则

变量的命名不是想怎么起就怎么起的,而是有一套固定的规则的。具体规则:1.名字要合法:变量名必须是由字母、数字或下划线组成。例如:a,a1,a_1。2.开头不能是数字。例如:可以a1,但不能起1a。3....

Rust编程-核心篇-不安全编程_rust安全性

Unsafe的必要性Rust的所有权系统和类型系统为我们提供了强大的安全保障,但在某些情况下,我们需要突破这些限制来:与C代码交互实现底层系统编程优化性能关键代码实现某些编译器无法验证的安全操作Rus...

探秘 Python 内存管理:背后的神奇机制

在编程的世界里,内存管理就如同幕后的精密操控者,确保程序的高效运行。Python作为一种广泛使用的编程语言,其内存管理机制既巧妙又复杂,为开发者们提供了便利的同时,也展现了强大的底层控制能力。一、P...