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.
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"?--> %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx false ${TARGET}/gatling_additional-${TIMESTAMP}.log %d{HH:mm:ss.SSS} [%-5level] %logger{15} - %msg%n%rEx false <!-- Uncomment for logging ALL HTTP request and responses --> <!-- <logger name="io.gatling.http.ahc" 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" /> --> |
5. Results and reports
Here is a snapshot of the results of the simulation run
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.
There you go a detailed blog on how to implement Gatling for your application. Lets help build applications that performs better and faster…
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.
how can i integrate the reports to jenkins?
Hi,
We have not tried this yet, but you can try the following
http://gatling.io/docs/2.0.1/extensions/jenkins_plugin.html
https://wiki.jenkins-ci.org/display/JENKINS/Gatling+Plugin
Hi,
How to handle ViewState on ASPX.net pages ?
Hi,
Can you be more specific about the issue you are facing?
Thanks
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.
Hi Ravikiran,
Can u please post the exceptions.
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.
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
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)
I don’t know for sure. Sorry.
I think this link will help: http://gatling.io/docs/2.1.3/http/http_check.html#http-response-body . This line may help you:
substring(“foo”) // same as substring(“foo”).find.exists
Sometimes, when the page takes a while to load, we end up doing a .check(status.is(200)) and a .pause() before trying to parse the HTML response.
Hi
I was completely new to gatling and i have gone through the above example and have few doubts regarding Percentile calculation.What does response time 50th percentile actually mean?Is it
response time average of half of the requests which are processed in 50% of test time?
Hi Ganesh,
Here are some examples for response time percentile
For instance ,if response time 75% percentile = 1049 ms , 75% of requests response time is < 1049 ms and 25 % requests response time is > 1049 ms
& if response time 50% percentile = 775 ms , 50% of requests response time is < 775 ms and other 50% request response time is > 775 ms
Regards
Raji
Hi,
Can i know how to store the Gatling results in local DB (MYSQL workbench)?
Trying to use gatling.conf file for the same.
Hi,
We have not tried to log the performance test results on a DB & we have started using Locust for load testing.
However I made a quick search was able to learn that Gatling uses this result object
io.gatling.commons.stats.assertion.AssertionResult
to generate charts.If you can establish a connection with the DB running on your local host, Pls refer – https://alvinalexander.com/scala/how-to-connect-mysql-database-scala-jdbc-select-query on how to connect to the DB then you can use the
AssertionResult
object and store the results to a Table.i need to download source code for this project
Hi,
We do not have the project saved on any remote repository unfortunately. Any code we have is limited to the example snippets in the post.