Performance testing with Gatling - recorded simulation explanation
Current post is part of Performance testing with Gatling series in which Gatling performance testing tool is explained in details.
Code samples are available in GitHub sample-performance-with-gatling repository.
Application under test
For current tutorial application from Build a RESTful stub server with Dropwizard post is used. It is a pretty simple application. One feature is Products web application where you can search for products, open one and see its details. The other features used in this post is Persons REST service, where you can get or save person via JSON.Record simulation
Coding simulations from scratch can be difficult and tricky, so it is always a good idea to record the scenario and then modify it. How to record can be found in Performance testing with Gatling – record and playback post. The recording that was done on the application under test for current tutorial produced following simulation files, which can be found in com.automationrhapsody.gatling.simulations.original package of GitHub project. There are two simulations being recorded. ProductSimulation which tests web application and PersonSImulation testing REST service.ProductSimulation explained
Below is a recorded code for product simulation:package com.automationrhapsody.gatling.simulations.original
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class ProductSimulation extends Simulation {
val httpProtocol = http
.baseURL("http://localhost:9000")
.inferHtmlResources()
val uri1 = "http://localhost:9000/products"
val scn = scenario("RecordedSimulation")
.exec(http("request_0")
.get("/products"))
.pause(11)
.exec(http("request_1")
.get("/products?q=SearchString&action=search-results"))
.pause(8)
.exec(http("request_2")
.get("/products?action=details&id=1"))
.pause(6)
.exec(http("request_3")
.get("/products"))
setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}
Simulation is performing following steps:
- Open /products URI on http://localhost:9000 URL.
- Wait 11 seconds.
- Search for "SearchString".
- Wait 8 seconds.
- Open product with id=1 from search results.
- Wait 6 seconds.
- Go to home page - /products
Variable uri1 is defined but is not actually used anywhere, so it is redundant.
A scenario is defined with scenario(“RecordedSimulation”), this method accepts the name of the scenario, “RecordedSimulation” in the current case. A scenario is a building block of a simulation. One simulation should have at least one scenario. See more about scenarios on Gatling Scenario page.
With exec() method are added actual actions to get executed. In most of the cases, the action is an HTTP GET or POST request. In current example GET request is done with http(“request_0”) .get(“/products”), where “request_0” is the name of the HTTP Request. A name is used to identify request in the results file. So it is good to have a unique name for different requests. The “/products” is the URI GET request will open. See more about HTTP requests on Gatling HTTP Request page.
Once scenario and protocol have been defined those need to be assembled into a Simulation. Simulation class should extend Gatling’s io.gatling.core.Simulation class. This gives access to setUp() method which is configuring the simulation. setUp method takes a scenario with injected users in it scn.inject(atOnceUsers(1)). In this case, one used is injected at simulation start. There are different inject patterns that can be used. More about simulations setup can be found in Gatling Simulation setup page.
PersonSimulation explained
Below is recorded code for person simulation:package com.automationrhapsody.gatling.simulations.original
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class PersonSimulation extends Simulation {
val httpProtocol = http
.baseURL("http://localhost:9000")
.inferHtmlResources()
val headers_0 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml",
"Upgrade-Insecure-Requests" -> "1")
val headers_1 = Map(
"Origin" -> "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop",
"Postman-Token" -> "9577054e-c4a3-117f-74ab-e84a2be473e0")
val headers_2 = Map(
"Origin" -> "chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop",
"Postman-Token" -> "639b36ea-aff3-1b85-618e-c696734afc6e")
val uri1 = "http://localhost:9000/person"
val scn = scenario("RecordedSimulation")
.exec(http("request_0")
.get("/person/all")
.headers(headers_0))
.pause(9)
.exec(http("request_1")
.post("/person/save")
.headers(headers_1)
.body(RawFileBody("RecordedSimulation_0001_request.txt")))
.pause(3)
.exec(http("request_2")
.post("/person/save")
.headers(headers_2)
.body(RawFileBody("RecordedSimulation_0002_request.txt")))
setUp(scn.inject(atOnceUsers(1))).protocols(httpProtocol)
}
In short, scenario is following:
- Invoke /person/all REST service on http://localhost:9000 URL.
- Wait 9 seconds.
- Save person by POST request to /person/save and RecordedSimulation_0001_request.txt JSON body.
- Wait 3 seconds.
- Save again person by POST request to /person/save and RecordedSimulation_0002_request.txt JSON body.
If you have paid attention to all the readings here and to GitHub project you may have noticed that Gatling Maven plugin defaults say: <bodiesFolder>src/test/resources/bodies</bodiesFolder>, but the request is actually in src/test/resources folder of the project.