Performance Testing using Gatling

Problem: Common misconception that load testing is difficult.

Many testers think performance testing is tough. One of the common reason for it is the lack of knowledge of any performance testing tool. In this tutorial we will learn about Gatling which is an open source load testing framework based on Scala, Akka and Netty and arm our self for load testing.


Why this post?

One of our clients came in with a really late requirement of some level of performance testing to be done on their application. But due to time constraints we had to postpone it. We wanted to learn a tool using which we can implement a performance testing framework for any client really quickly. In the process of evaluating some tools we decided to get our hands dirty on exploring Gatling.
Performance testing is in general testing performed to determine how a system performs in terms of responsiveness and stability under a particular workload.


Overview

We will once again use Droptask as the application under test. For this tutorial we will build a small library of functions using Gatling and scala which can be then reused to write different performance tests.

1. Gatling Installation
2. About Droptask and the test case
3. Gatling implementation
4. Running the test
5. Results and reports


1. Gatling Installation

You can download the latest Gatling bundles as a .zip file from here

Unzip the downloaded bundle to a folder of your choice. In order to run Gatling, you need to have JDK installed in your machine. For more details on installing refer to this section

Once you download and unzipp the files you will find the following bat scripts

recorder.bat: A tool provided with Gatling that allows you to record your actions on a web application and export them as a Gatling scenario
gatling.bat: A script to choose and execute the Simulation.


2. About Droptask and the test case
We used DropTask as the application under test. DropTask is a free web based task and project management application that offers a visual approach towards managing daily workloads. For this tutorial, our test scenario would be

  • Login to DropTask
  • Get the account details
  • Create multiple tasks in an existing workspace

3. Gatling implementation
A Gatling simulation structure contains 4 different parts:

  • The HTTP protocol configuration: Here we can define the baseURL, which will be prepended to all the relative paths in the scenario definition. Also we can define some other configurations such as common headers, user agent etc, which will be added on each request.
  • The headers definition: Here we define the headers which can be used for each request that will be sent to the server.
  • The scenario definition: This is the main part of your test. It has a sequence of exec commands. Each exec command is used to execute a set of actions(GET, POST, etc.) that will be executed in order to simulate a user interaction with your application.
  • The simulation definition: This is usually the last part of the test script. This is where we define the load we want to inject to your server

To start of our performance testing on Droptask application, we used the recorder.bat to record the above mentioned test scenario. The resulting script created in the folder \gatling-charts-highcharts-bundle-2.1.4\user-files\simulations was one big file which was not modular, not easy to maintain and scale up. It contained certain unnecessary requests and biggest drawback was that the functions could not be reused again.

Hence we decided to write our own test using facade pattern. We wrote all the functions which can be reused in a Base file (DropTask_Base_Gatling.scala). The test (DropTask_CreateTask_Gatling.scala) could now import the functions it requires from base file. This way its much easier to maintain our tests and changes need to be only updated in Base file.

File 1: Gatling Test file

Here is the code for the test script.

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
 
class DropTaskTest extends Simulation {
 
	val createtask = scenario("DropTask_CreateTask")
     .exec(DropTaskBase.scn_login)
     .exec(DropTaskBase.scn_acctdetails)
     .exec(DropTaskBase.scn_clientId)
     .repeat(3){
     	feed(csv("names.csv").queue)
     .exec(DropTaskBase.scn_createtask)
     }
 
  setUp(
    createtask.inject(atOnceUsers(1))
  ).protocols(DropTaskBase.httpConf)
}

For our test the scenario would be login to Droptask application, get the account details, get the client id and then create task using the client and workspace id. To start, our test would need to have some basic imports. Then we define a scenario called “DropTask_CreateTask”. This scenario will execute a group of actions which are present in the base class. We will go over each of these functions later.

We will also repeat the create task 3 times to show you how repeat and feed can be incorporated in our test. The names for the task to be created will be read from a file “names.csv” using the feed call. Feeders are data sources containing all the values you want to use in your scenarios. There are several types of Feeders, the most simple being the CSV Feeder. You can find the contents of the names.csv file we used below.

The setUp method sets up the scenarios that will be launched in this Simulation. Next we inject one single user to scenario ‘createtask’. The httpConf is the HTTP configuration will be defined in the basefile . It has the baseURL that will be apprehended to all relative urls and common HTTP headers that will be sent with all the requests.

Note: We have just injected single user for our test as we did not want to increase the load on ‘DropTask’ server. In case you want to test with many user its better to test your own application.
The names.csv file

taskName
task1
task2
task3

You need to place the file in your \gatling-charts-highcharts-bundle-2.1.4\user-files\data\names.csv

File 2: Gatling Base file
The Base class will contain all the scenarios for actions which can be performed in the droptask app like login, get account details, get client Id, create task.
Here is the code for the base script

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
import com.typesafe.config._
import io.gatling.core.feeder._
 
object DropTaskBase {
 
  val conf = ConfigFactory.load("droptask_scala.properties")
  val user = conf.getString("username")
  val pass = conf.getString("password")
  val baseurl = conf.getString("Base_Url")
  val currenttime = System.currentTimeMillis()
 
  /** Urls for the droptask test */
  val url_login = "/login"
  val url_account = "/v1/account?"
  val url_client = "/v1/workspaces/"
  val url_task   = "/v1/tasks"
 
  val httpConf = http
		.baseURL(baseurl)
		.acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
		.acceptEncodingHeader("gzip, deflate")
		.acceptLanguageHeader("en-US,en;q=0.5")
		.connection("keep-alive")
		.contentTypeHeader("json")
		.userAgentHeader("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0")
 
  val headers_task = Map(
		"User-Agent"->"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:33.0) Gecko/20100101 Firefox/33.0", 
		"Accept-Encoding"-> "gzip, deflate",
    "X-Requested-With"->"XMLHttpRequest",
    "X-Client-Id"-> "${client_id}")
 
  val scn_login = scenario("Login")
    .exec(http("Login")
	.post(url_login)
	.formParam("email", user)
	.formParam("password", pass)
	.check(status.is(200)))
	.pause(8)
 
	val scn_acctdetails = scenario("AccountDetails")
   .exec(http("AccountDetails")
	.get(url_account + currenttime)
	.check(jsonPath("$.workspaces[?(@.name=='TestDropTask')]._id").saveAs("workspace_id")))
 
	val scn_clientId = scenario("ClientId")
    .exec(http("ClientId")
  	.get(url_client + "${workspace_id}")
  	.check(jsonPath("$.deltas[?(@.workspaceId=='${workspace_id}')].clientId").saveAs("client_id")))
  	.pause(2)
 
 	val scn_createtask = scenario("CreateTask")
  	  .exec(http("CreateTask")
  	  .post(url_task)
  	  .formParam("workspace","${workspace_id}")
  	  .formParam("title","${taskName}")
  	  .headers(headers_task)
  	  .check(status.is(201)))
 
}

Here is a brief explanation of each of the scenarios.

  • Login: In order to login to DropTask, a POST request to DropTask is made with your email and password as params. These are read from droptask_scala.properties file. The property file needs to be placed in following location \gatling-charts-highcharts-bundle-2.1.4\conf\droptask_scala.properties. Also, we use check() command to verify our response code

    Sample property file

    username=USERNAME
    password=PASSWORD
    Base_Url=https://www.droptask.com
    
  • Account details: A GET request is made with the current Unix time as a parameter in the request URL. The detailed JSON response has all the Account details, it is parsed to get the workspace_id for the workspace -‘TestDropTask’. We use the saveAs() command to store this data in a variable called “workspace_id”.
  • Client Id: A GET request is made for the workspace using the workspace_id got in step b. The response is parsed to get the ClientId which is used as part of headers for the next request.
  • Create task: Add the ClientId got in step c as the value for the header “X-Client-Id”. A POST request is made with the workspace_id and taskname as the params in order to create the new task in the existing workspace ‘TestDropTask’.

4. Running the test
When we run the gatling.bat script, the code gets compiled and the case “DropTaskTest” gets listed on the console. If there are any compilation errors the case will not be listed and you need to correct the code using the console logs. After this select the case number and run the test.
gatling run

You may need to update the logback.xml in order to configure the log level of Gatling. You can refer to this link to know more about configuration details for Gatling.

Here is the logback.xml we used:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
 
	<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
		<encoder>
			<pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
			<immediateFlush>false</immediateFlush>
		</encoder>
	</appender>
	 <property name="TARGET" value="target/gatling/results"/>
     <timestamp key="TIMESTAMP" datePattern="yyyyMMdd'T'HHmmss"/>
 
	<appender name="FILE" class="ch.qos.logback.core.FileAppender">
        <file>
            ${TARGET}/gatling_additional-${TIMESTAMP}.log
        </file>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx</pattern>
            <immediateFlush>false</immediateFlush>
		</encoder>
    </appender>
 
 
	<!-- Uncomment for logging ALL HTTP request and responses -->
	<!-- 	<logger name="io.gatling.http.ahc" level="TRACE" /> -->
	<logger name="io.gatling.http.response" level="TRACE" />
	<!-- Uncomment for logging ONLY FAILED HTTP request and responses -->
	<!-- 	<logger name="io.gatling.http.ahc" level="DEBUG" /> -->
	<!--    <logger name="io.gatling.http.response" level="DEBUG" /> -->
 
	<root level="TRACE">
		<appender-ref ref="CONSOLE" />
		<appender-ref ref="FILE" />
 
	</root>
 
</configuration>

5. Results and reports
Here is a snapshot of the results of the simulation run
gatling result

gatling_report

Gatling also provides elegant and meaningful reports with detailed graph of the tests you run as shown below. You can find it in the “results” folder of your test.

Gatling_Result1

Gatling_Result2

There you go a detailed blog on how to implement Gatling for your application. Lets help build applications that performs better and faster…


Vrushali Toshniwal
My journey as a tester started at Sun Microsystems (now Oracle). I was part of the testing and sustaining team for the Portal Server and Identity Management products. My first assignment was to test the Rewriter module. I enjoyed understanding the big picture, writing test cases, finding bugs and sometimes suggesting the fix too! I was hooked onto testing. Testing felt natural and intuitive to me. I am technically inclined and can write automation in Java, C++, Perl and Python. I am well versed with SilkTest, Selenium, Appium and Selendroid. I am a Computer Science graduate from BITS-Pilani. I love travelling and listening to music.

© 2013-2017, Vrushali Toshniwal. All rights reserved.

11 Comments

  1. rookie said:

    how can i integrate the reports to jenkins?

    September 29, 2015
    Reply
  2. ravikiran said:

    Hi
    Thanks for the post. When i tried i am getting exceptions. I was able to see the DropTeskTest but when i run i am getting exceptions.Can you please let me know why it is happing.

    April 19, 2016
    Reply
    • Shivahari P Shivahari P said:

      Hi Ravikiran,
      Can u please post the exceptions.

      April 20, 2016
      Reply
  3. ravikiran said:

    I was able to resolve the exceptions. But when i tried in reports i am getting Account details KO,ClientId KO,Create Task 3 K0. I was not able to generate the ok reports for all the three.

    Can you please tell me how to integrate the gatling into eclipse ide. I have integrated but i am getting Error: Could not find or load main class Recorder.

    It would be more grateful for me if you help me out.

    Thanks in advance.

    April 21, 2016
    Reply
    • Avinash Shetty Avinash Shetty said:

      Hi Ravikiran,
      If the tests had passed the report should look as we have posted in screenshot. Can you give more details on the results of the simulation run.
      I haven’t tried integrating gatling with eclipse ide so would not be able to help you there

      April 25, 2016
      Reply
  4. Anonymous said:

    Hi how do I verify if a page has been loaded using Gatling in the sense like how do I obtain the label data of the page
    I have used check(regex(“hi”))saveAs(“welcome”)
    But I’m getting not found(0).exit(0)

    August 5, 2016
    Reply

Leave a Reply

Your email address will not be published.