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

zhangyang · 2016年01月20日 · 最后由 测试小书童 回复于 2016年01月21日 · 2345 次阅读
本帖已被设为精华帖!

英文文档地址:
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 条回复 时间 点赞

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

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

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