Performance testing with
Gatling
Intro/Agenda
Performance testing overview
Gatling overview
Gatling test structure
Gatling API
Gatling Recorder
Gatling DSL
Gatling reports
Performance testing
Performance testing
Measure response time under workload
Load, Stress, Soak, Spike testing
Find bottlenecks
Satisfy impatient customers
Increase conversion rate
Sustain company reputation
Approach
1. Set proper goals
2. Choose tools
3. Try the tools
4. Implement scenarios
5. Prepare environments
6. Run and measure
Gatling overview
Gatling
e r
po w
i r e
F
Gatling
Thousands of concurrent users
Users are not threads, but actors
Asynchronous concurrency
Scala
Akka
Netty
Recorder (HTTP Proxy and HAR)
Extensions (Maven, Gradle, Jenkins)
1 thread = 1 user *
* http://www.slideshare.net/ZeroTurnaround/stephane-landelleblastyourappwithgatling
Blocking I/O *
* http://www.slideshare.net/ZeroTurnaround/stephane-landelleblastyourappwithgatling
Actors Model
Mathematical model used in parallel computing
Actor is autonomous computational unit
No shared resources, no shared state
Asynchronous message passing
Mailbox to buffer incoming messages
React on received messages
Gatling test structure
Building blocks
Gatling API
HTTP GET Request
Define
Variable Method of HTTP Request
constant
name Request object URI
variable
val myHttpGetRequest = http("Open home page").get("/home")
Create HTTP Request
Request object name
HTTP Protocol
Create HTTP URL is prepended
Application
Protocol to any HTTP
URL
object request
val myHttpProtocol = http.baseURL("http://localhost:81")
Scenario
Create Scenario Scenario Execute HTTP Already created
object name Request HTTP Request object
val myScenario = scenario("Browse Home").exec(myHttpGetRequest)
.pause(2).exec(myReq2)
Pause between Pause time Execute more
requests in seconds HTTP Requests
setUp
Gatling Already created
Scenario Number of
Simulation base HTTP Protocol
object method users
method object
setUp(myScenario.inject(atOnceUsers(10))).protocols(myHttpProtocol)
Already created Configure
Injection profile
Scenario object protocol
Simulation class
Import Gatling Gatling base
API classes simulation class
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class MySimulation extends Simulation {
Simulation
class name
Gatling simulation
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class MySimulation extends Simulation {
val myHttpProtocol = http.baseURL("http://localhost:81")
.inferHtmlResources()
val myHttpGetRequest = http("Open home page").get("/home")
val myLoginRequest = http("Open login page").get("/login")
val myScenario = scenario("Browse Home")
.exec(myHttpGetRequest).pause(2)
.exec(myLoginRequest)
setUp(myScenario.inject(atOnceUsers(10))).protocols(myHttpProtocol)
}
Gatling Recorder
Recorded simulation
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class RecordedSimulation extends Simulation {
val httpProtocol = http
.baseURL("http://localhost:9000")
.inferHtmlResources()
val scn = scenario("RecordedSimulation")
.exec(http("request_0")
.get("/products"))
.pause(5)
.exec(http("request_1")
.get("/products?q=SearchString"))
setUp(scn.inject(atOnceUsers(1)))
.protocols(httpProtocol)
}
Gatling DSL
Domain Specific Language
Gatling DSL
Feeders
csv, ssv, tsv, jsonFile, jsonUrl, jdbcFeeder
queue, random, circular
Checks
responseTimeInMillis, latencyInMillis, status, currentLocation
header, headerRegex
bodyString, bodyBytes, regex, xpath, jsonPath, css
Check actions
find, findAll, count, saveAs
is, not, exits, notExists, in, optional
Gatling DSL (2)
Execution control
doIf, doIfOrElse, doSwitch, doSwitchOrElse, randomSwitch
repeat, foreach, during, asLongAs, forever
tryMax, exitBlockOnFail, exitHereIfFailed
Assertions
responseTime, allRequests, requestsPerSec
min, max, mean, stdDev, percentile1, percentile2
lessThan, greaterThan, between, is, in, assert
Injection profiles
nothingFor, atOnceUsers, rampUsers over, rampUsers during
Session
A virtual users state
stores all simulation users data
Map[String, Any]
Write data
using Feeders
extract and save from response
programmatically with Session API
Read data
using Gatling Expression Language
programmatically with Session API
Gatling reports
ANY
STIONS?
Thank you!
Lyudmil Latinov
Senior Automation QA
Xoomworks Bulgaria
https://github.com/llatinov/sample-performance-with-gatling
Blog: AutomationRhapsody.com
www.qachallengeaccepted.com
Bonus slides
Offline bonus slides
CSV Feeder
Access CSV file Start over once Access in
Read CSV file
modifier name file is read random order
private val csvFeeder = csv("search_terms.csv").circular.random
search_terms.csv
CSV file content
search_term
prod
First line is header, used product1
as session variable name hello
searchTerm1
hello hello
Use CSV Feeder
Add Feeder to Already created Iterate
Scenario CSV Feeder scenario
object object forever
val scn = scenario("Search products").feed(csvFeeder).forever() {
exec(http("Search product").get("/products?q=${search_term}"))
}
Execute HTTP
HTTP GET Access CSV data by
Requests in
Request header with Gatling EL
body
HTTP POST Request
person.json Gatling EL
{ Create HTTP
parser replaces
"id": "${id}", Post Request Request URI
session
"firstName": "${first_name}", object
variables
"lastName": "${last_name}",
"email": "${email}"
}
val reqSavePerson = http("Save Person").post("/person/save")
.body(ElFileBody("person.json")).header("Content-Type", "application/json")
Add body to Read body file
Add
HTTP Post and parse with File
header
request Gatling EL name
field
Checks
Checks can be defined Add check to HTTP Response code
on HTTP Protocol level Protocol object is 200 OK
val myProtocol = http.baseURL("http://localhost:81").check(status.is(200))
val myRequest = http("Home").get("/home").check(regex("Hello, (*.?) (*.?)!"))
Usually check are Response body
Add check to HTTP
defined on HTTP matches regular
Request object
Request level expression
Save to Session
Access session data
HTTP GET Request
with Gatling EL
val reqSearch = http("Search product").get("/products?q=${search_term}")
.check(regex("Found ([\\d]{1,4}) products:").saveAs("numberOfProducts"))
Save regular
Check response body Name of session
expression matched
matches specific regex variable to save to
group
Manage Session variables
Access Session
Read variable from Session object
objectinside exec block
as String and convert to Integer
with lambda
val reqOpenProduct = exec(session => {
var prds = session("numberOfProducts").as[String].toInt Some test logic
var productId = Random.nextInt(prds) + 1
session.set("productId", productId) Create and return new
}).exec(http("Open").get("/products?id=${productId}")) Session object with
variable saved in it
Variable is accessible
Execute HTTP
only on second exec
Get request
block
Conditional execution
Conditions are calculated If Session variable
on Scenario object equals given value
val scnLogoutOrHome = scenario("Logout Or Home")
.doIfEqualsOrElse("${action}", "Logout") {
exec(http("Do logout").get("/logout")) Execute Requests
} { chain in case of TRUE
exec(http("Home page").get("/home"))
}
Execute Requests
chain in case of FALSE
Advanced setUp
Different scenarios
with different
injection profiles
setUp(scnSearch.inject(rampUsers(10) over 10.seconds),
scnOpenProduct.inject(atOnceUsers(10)))
Maximum duration
.protocols(myProtocol) in case of forever()
.maxDuration(10.minutes)
.assertions(
global.responseTime.max.lessThan(800), Assert each
global.successfulRequests.percent.greaterThan(99) response time is
) bellow 800ms
Assert 99% success
responses for the
Simulation