Starting with Gatling …

Md. Yusuf Ansari
5 min readNov 27, 2020

--

Gatling is a Scala based open source performance testing framework which facilitates tester to record scenario, edit and run performance scripts.

Its architecture is based on advanced stack Akka, which helps it to be highly efficient and hence simulate high number of virtual users on a single machine.

Install Gatling and run the sample scripts

It comes with a some prewritten scripts. Now let’s run it and see its magic….

  • Goto the <Gatling_home>/bin and run the gatling.sh script
  • Choose any of the prewritten scripts by giving its number and voila.

Features

  • Work on any OS
  • GUI based scenario recorder
  • Detailed and beautiful dashboard
  • Highly performant

Due to its advanced and better architecture unlike one thread per user, it can simulate multiple users per thread. As a result it is highly efficient in using CPU and RAM.

  • Tests are created as code by using highly readable DSL and Scala
  • Capability to integrate with Version Management Tool
  • Capability to integrate with CI/CD platforms

What is Gatling Recorder

Gatling Recorder helps to generate simulation or scripts by acting as a proxy between client and server or by using HTTP archive file.

Two Modes of recording

  • HTTP Proxy
  • HAR Converter

Now Let’s execute a scenario to access homepage of a website and generate a Gatling script using the HAR converter

  • Open the website (say, http://cheeze-flight-booker.herokuapp.com/)
  • Open Chrome Dev tools and tick on preserve log checkbox and then clear the existing logs
  • Now Refresh the page and see some action happening on the developer tool console
  • Right click and select Save all as HAR with content to save the HAR file
  • Open Recorder UI, change the mode to HAR converter, add the HAR file, give a Class Name or Package Name of your choice and mention the desired/output location where you want to store the script and click on Start.
  • Press OK to finally generate the script at the desired location.

Gatling scripts are divided into four parts —

  1. HTTP protocol configuration
  2. Headers definition
  3. Scenario definition
  4. Simulation definition

Enough with the theory, time for some action!

Let’s setup a development environment and play around with the script generated with the Recorder UI and understand the Gatling script structure.

HTTP protocol configuration

This will define your base URL that you will be running your tests against. Also, you can define some other configurations such as user agent, language header, connection and so on.

We will add some imports and extend the class with Simulation. We have set our baseURL to http://cheeze-flight-booker.herokuapp.com. So, every time we run a request, it will use our baseURL followed by other configurations such as acceptHeader, acceptEncodingHeader, acceptLanguageHeader, connection and userAgentHeader.

We have also added SilentResources, this will prevent all the resources or request to appear in the report which are not need.

val httpProtocol = http
.baseUrl("http://cheeze-flight-booker.herokuapp.com")
.inferHtmlResources()
.acceptHeader("image/avif,image/webp,image/apng,image/*,*/*;q=0.8")
.acceptEncodingHeader("gzip, deflate")
.acceptLanguageHeader("en-US,en;q=0.9")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36")
.silentResources //SilentResources

Header Definition

This provides the headers for each request that will be sent to the server. This is relevant because the headers also add a bit of load to the server you are testing.

The headers are generated automatically if you are using a Gatling recorder. (In case of API, the user know the headers being passed and can pass it in multiple different fashion as depicted here).

We will pass these headers variables in the scenario definition wherever required.

val headers_0 = Map(
"Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Upgrade-Insecure-Requests" -> "1")

val headers_1 = Map("Pragma" -> "no-cache")

Scenario definition

The core of your test! A Scenario is a group of actions (GET, POST, etc.) that will be executed in order to simulate a user interaction with your application.

In this step, we will clear the browser cache and cookies before scenario execution, so that every virtual user acts as fresh user. This will result in proper load data and hence increase the load on server as much as possible.

We will also add checks on status code and each element present on the page.

val scn = scenario("Access Home Page") //Starting of a scenario//Clear browser cache and cookie
.exec(flushHttpCache)
.exec(flushSessionCookies)
.exec(flushCookieJar)
//Starting of scenario execution and making a GET request to access the HomePage
.exec(http("HomePage")
.get("/")
.headers(headers_0) //Adding Headers to our execution
.resources(http("request_1")
.get("/favicon.ico")
.headers(headers_1))
//Checks to verify status code and Page Elements .check(status.in(200,201,202,304))
.check(status.not(404))
.check(css("h1:contains('Flights')").exists)
.check(substring("from").find.exists)
.check(substring("to").find.exists)
.check(substring("date").find.exists)
.check(substring("passengers").find.exists)
.check(css("input[value='search']").exists))

We can also print the Response body for a session

.check(bodyString.saveAs("BODY"))) 
.exec{
session =>
println
(session("BODY").as[String])
session
}
//This will print the response body in our console which can be used later for debugging purpose.

or, we can also print any variable which we are passing as feeders for a particular scenario.

val randomEmailFeeder = Iterator.continually(Map("randomEmail" -> (Random.alphanumeric.take(20).mkString + "@ggmail.com")))
val randomNameFeeder = Iterator.continually(Map("randomName" -> (Random.alphanumeric.filter(_.isLetter).take(5).mkString.toLowerCase)))
//Passing Feeders/Data to execute flight booking for multiple users. .feed(randomEmailFeeder)
.feed(randomNameFeeder)
.exec(http("BookFlights")
.post("/bookings")
.headers(headers_12)

.formParam("booking[passengers_attributes][0][name]", "${randomName}")
.formParam("booking[passengers_attributes][0][email]", "${randomEmail}"))
.exec{
session =>
println(session("randomName").as[String])
session
}

Simulation definition

This defines the load (amount of users) that will concurrently execute your scenario for a period of time.

This is where we will define the load injected to the server and also add Assertions to verify some statistics.

We will also add assertions to verify the statics such as max response time and successful request percentage.
1st assertion — The cumulative response time of all the requests in the simulation should be less than 1000

2nd assertion — successful request percentage should be 100%

setUp(scn.inject(rampUsers(1000) during (15 seconds))).protocols(httpProtocol)
.assertions(
global.responseTime.max.lt(1000),
global.successfulRequests.percent.is(100)
)

This will inject 1000 users distributed evenly on a time window of 15 seconds for a particular scenario.

Once the script has finished running you will get a detailed report along with the statistics like pass and fail of each request, response time, std deviation, response time percentile, along with the assertion response.

You will also get a link to PDF format of the report.

Curious to see the report, run the script using the following command:

mvn gatling:test -Dgatling.simulationClass=GatlingPractice

OR

Just right click on Engine under Scala directory and click on Run ‘Engine’ and follow the steps from the terminal.

--

--