🎉 🎂 🍰 TesterHome 创立 6 周年纪念日 🍰 🎂 🎉

移动性能测试 Gatling 文档翻译 (二)-Advanced Tutorial

hobbs · 2016年01月20日 · 最后由 lose 回复于 2016年01月21日 · 1063 次阅读
本帖已被设为精华帖!

英文文档地址:
http://gatling.io/docs/2.1.7/advanced_tutorial.html#advanced-tutorial

Advance Tutorial

在这部分,我们假设你已经阅读完 QuickStart 部分并且已经有了一个可用的基础simulation。我们将应用一系列的重构来介绍更多gatling的高级特性和DSL结构。

第一步:隔离过程

目前,我们的Simulation是一个大的场景。所以首先我们把它分割为独立的业务流程,类似于Selenium的PageObject模式。

这样你就可以轻松地复用一些部分并构建复杂行为。

在我们的示例scenario中有3个独立的过程:

  • Search: 通过名字搜索记录
  • Browse: 浏览搜索结果列表
  • Edit: 编辑给定的记录

我们将这些操作提取出来并存储在单独的对象中,对象是单个本地Scala文件。你可以在专用文件中创建它们,或者直接在同一个Simulation文件中创建它们。

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 = ???
}

我们现在可以使用可复用的业务流程来重写我们的scenario:

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

第二步:配置虚拟用户

所以,我们现在可以对我们的服务器进行加压测试了,用多少个用户呢? 一个!--- 显然,我们需要增加用户的数量。

我们定义两种常见用户:

  • 普通用户:他们可以搜索和浏览计算机类型记录;
  • 管理员用户:他们可以搜索、浏览和编辑计算机类型记录。

翻译成场景如下:

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

你只需要像下面这样配置Simulation就可以增加模拟用户的数量:

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

在这我们只设置10个用户,因为我们不希望淹没我们的测试用Web应用程序。请善待我们的服务器,不要让它崩溃。

如果要模拟3000个用户,你可能不希望他们在同一时间开始。事实上,真正的场景更可能是用户在逐渐地增加。

Gatling提供 rampUsers 来实现此行为。ramp的值表明在整个过程中用户将被线性地启动。

在我们的场景中我们使用10个普通用户和2个管理员用户,我们将在10秒内启动它们。

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

第三步:使用动态数据

我们设定我们模拟运行了一堆的用户,但他们都在搜索相同的记录。如果我们能让每个用户搜索不同的记录不是更好?

我们需要使用动态数据来使所有的用户不必执行完全相同的行为。这就需要Feeders.

Feeders是一个数据源,包含所有你想要在scenarios中使用的数据。

Feeders有几种类型,最简单的是CSV:这也是我们在测试中使用的类型。

首先创建一个名叫search.csv的文件并放置在 user-files/data 文件夹中。

这个文件包含下面几行内容:

searchCriterion,searchComputerName
Macbook,MacBook Pro
eee,ASUS Eee PC 1005PE

下面让我们在文件中使用它们:

object Search {

val feeder = csv("search.csv").random // 1, 2

val search = exec(http("Home")
.get("/"))
.pause(1)
.feed(feeder) // 3
.exec(http("Search")
.get("/computers?f=${searchCriterion}") // 4
.check(css("a:contains('${searchComputerName}')", "href").saveAs("computerURL"))) // 5
.pause(1)
.exec(http("Select")
.get("${computerURL}")) // 6
.pause(1)
}

代码解释:
1.首先我们创建了一个包含如下内容的csv 文件:searchCriterion,searchComputerName.
2.由于默认的feeder策略是队列,所以我们在测试中显式指定随机策略来避免feeder中的数据不够用。
3.每当一个用户的行为需要数据时,从feeder文件中随机取一条数据,这样这个用户就有了两个新的session 属性:searchCriterion,searchComputerName.
4.我们通过Gatling的EL使用session 数据来参数化搜索.
5.我们使用带EL的CSS选择器来捕捉HTML response的一部分,并将其以computerURL的名称保存在用户session中。
6.我们使用之前保存的超链接来获得一个特定的页面。

注意:
有关Feeders的详细信息,请查看 Feeder reference page.
有关HTTP Checks 的详细信息,请查看 Checks reference page.

第四步:循环

在浏览页面的过程中我们有大量的重复。使用不同参数值的相同请求有4次,我们能否改变这种情况来避免违反DRY原则?

首先我们重复执行的部分抽象为方法。事实上,Simulation 是纯 Scala类,所以如果需要,我们可以使用编程语言的所有特性。

object Browse {

def gotoPage(page: Int) = exec(http("Page " + page)
.get("/computers?p=" + page))
.pause(1)

val browse = exec(gotoPage(0), gotoPage(1), gotoPage(2), gotoPage(3), gotoPage(4))
}

现在,我们可以调用这个方法并传递所需的页码。但是仍然有重复,所以是时候介绍另一个内建的结构了。
object Browse {

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

代码解释:
1.repeat 内建方法是一个运行时的循环解决办法。它接受重复次数和保存在用户Session中的计数器名称
2.当我们指定计数器的名称时,我们可以在Gatling EL中使用它并访问第N个page.

备注:
有关循环的更多信息,请查看 Loops reference page.

第五步:检查和故障管理

直到现在我们也只是使用 check 来解析html response中的一些数据并保存到session中。事实上 check 也可以用来检查response的属性。

默认情况下Gatling 检查 http response 状态是否是 20X 或 304.

为了演示故障管理,我们将随机地介绍对失败情况的一次检查:

import java.util.concurrent.ThreadLocalRandom // 1

val edit = exec(http("Form")
.get("/computers/new"))
.pause(1)
.exec(http("Post")
.post("/computers")
.check(status.is(session => 200 + ThreadLocalRandom.current.nextInt(2)))) // 2

代码解释:
1.首先 import ThreadLocalRandom,生成随机值。
2.对已经定制了 lambda 的情况进行检查。 每次用户执行请求是随机返回 200 或201.当 response 状态是200时,检查随机失效。

为了处理随机失败我们使用 tryMaxexitHereIfFailed 结构,如下:

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

代码解释:
1.tryMax 执行指定代码块 n 次。这里我们最大执行两次
2.如果全部失败,则用户退出整个场景

备注:
有关 conditional blocks 的更多信息,请查看 Conditional Statements reference page.

本文档的相关文档可以在 user-files/simulations 文件夹下找到。

共收到 2 条回复 时间 点赞

感谢分享。国内现在这方面的资料很少,真是十分感谢。

持续关注,谢谢分享~可有做个高并发测试?

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册