DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Related

  • Keep Your Application Secrets Secret
  • Maximizing Efficiency With the Test Automation Pyramid: Leveraging API Tests for Optimal Results
  • Cypress.io — The Rising Future of Web Automation Testing
  • How To Check for JSON Insecure Deserialization (JID) Attacks With Java

Trending

  • AI Speaks for the World... But Whose Humanity Does It Learn From?
  • Four Essential Tips for Building a Robust REST API in Java
  • Event-Driven Microservices: How Kafka and RabbitMQ Power Scalable Systems
  • Distributed Consensus: Paxos vs. Raft and Modern Implementations
  1. DZone
  2. Coding
  3. Languages
  4. Page Object Model for Performance Testing With Gatling

Page Object Model for Performance Testing With Gatling

Gatling is a powerful open-source tool for performance/load testing; we take you through the POM design model to create and test a Gradle repository.

By 
Harsha Chandnani user avatar
Harsha Chandnani
·
Updated Dec. 16, 20 · Tutorial
Likes (4)
Comment
Save
Tweet
Share
13.5K Views

Join the DZone community and get the full member experience.

Join For Free

Performance Testing

It is one of the Non-Function testing techniques that test if and how SUT [System/Software Under Test] will perform under a load in terms of responsiveness, stability, scalability, reliability, and resource usage.

Many factors, like network, code quality, traffic spike, etc., could potentially hamper a system's performance. Perf testing helps to uncover these bottlenecks.

UI and API Performance Testing

There are 2 ways to load test the application. They are UI and API load tests.

UI load testing involves testing everything visible to users or the client-side. They evaluate the translation of data from the API to the UI and ensure that everything is happening quickly and accurately. These tests provide the best insight into the actual loading times experienced by users.

In API load tests, as the name suggests, we put the load on the application by hitting APIs directly and then checking how APIs are responding under various load conditions. 

Gatling: Performance Testing Tool

There are many performance testing tools available. I have used Gatling for this article.

It's is a quite famous and powerful open-source tool for performance/load testing and provides integration with CICD tools like Jenkins.

It offers great reporting and an easy to use recorder and script generator.

It provides default integration with build tools like Maven and Gradle.

Page Object Model for Performance Testing

We have used the POM [Page Object Model] with UI automation tools; however, the same pattern we can very well use in Gatling.

Consider an example of https://katalon-demo-cura.herokuapp.com/. Here we have a journey, i.e.,

  • Landing on the home page, 
  • Logging in,
  • Booking an appointment, 
  • Navigating to the History page to confirm if the appointment has been successfully made.
  • Logging out.

In the above example, I have shown just 1 journey, which traverses through multiple pages. On every page, there was a call to some API. We might need to use the same API differently to perform various other journeys, like with a different set of request parameters.

If we are using these same APIs in different journeys, then it leads to a lot of duplicate code.

An easy but effective way is the usage of POM in the above use case.

With POM, we will be extracting out the APIs page vise, and then these APIs can be called in various journeys or tests.

In this article, I have used IntelliJ as an editor and Gradle as a build tool.

Documentation for Gatling's Gradle plugin can be found here: https://gatling.io/docs/current/extensions/gradle_plugin/

Let's start with writing the code.

Step 1: Download Gatling: https://gatling.io/open-source/

Step 2: Set up the Scala plugin in IntelliJ: http://allaboutscala.com/tutorials/chapter-1-getting-familiar-intellij-ide/scala-environment-setup-install-scala-plugin-intellij/

Step 3: Create a new Gradle repository in IntelliJ as follows:

creating a new Gradle repository

Input GroupId and ArtifactId as shown below and then Finish:

Inputting GroupId and ArtifactID.

NOTE: We need to have Gradle already setup in our machines to get this set-up ready smoothly. I have used sdkman to get Gradle 6.3 on my machine.

Step 4: After the successful creation of the Gradle repository, open the build.gradle file and insert the below code in it:

Groovy
 




xxxxxxxxxx
1
11


 
1
plugins {
2
  // The following line allows to load io.gatling.gradle plugin and directly apply it
3
  id 'io.gatling.gradle' version '3.4.2'
4
}
5

          
6
gatling {
7
  // WARNING: options below only work when logback config file isn't provided
8
  logLevel = 'WARN' // logback root level
9
  logHttp = 'NONE' // set to 'ALL' for all HTTP traffic in TRACE, 'FAILURES' for failed HTTP traffic in DEBUG
10
}



Step 5: From the terminal window, run Gradle clean build to download all dependencies.

It will take some time to download the dependencies. After a successful Gradle build, our repository will look something like this:

Successfully built repository.

With Gatling's Gradle plugin, we get the folder structure displayed above, with some sample files available.

  • All the request payloads, CSV files for feeders, etc., can be kept inside the resources folder. 
  • All test simulations, any helpers, and Constant data files can be kept inside the scala folder. 

Step 6: Let's start creating page object classes.

  • Create 3 packages inside the Scala directory as
    • com.journeys
    • com.pageObjects
    • com.helper
  • Inside com.helper package create a scala class asConstants.scalawherein we will keep all our common URLs, username and common password, and common header information:
Scala
 




x


 
1
package com.helper
2

          
3
object ConstantsData{
4

          
5
  val BASE_URL = "https://katalon-demo-cura.herokuapp.com/"
6
  val ACCEPT_HEADER = "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"
7
  val ACCEPT_ENCODING_HEADER = "gzip, deflate, br"
8
  val ACCEPT_LANGUAGE_HEADER = "en-GB,en-US;q=0.9,en;q=0.8"
9
  val USER_AGENT_HEADER = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) " +
10
    "Chrome/87.0.4280.67 Safari/537.36"
11

          
12
  object URLS {
13
    val PROFILE = s"${BASE_URL}profile.php"
14
    val LOGIN = s"${BASE_URL}authenticate.php"
15
    val LOGOUT = s"${BASE_URL}authenticate.php?logout"
16
    val BOOK_APPOINTMENT = s"${BASE_URL}appointment.php"
17
    val HISTORY = s"${BASE_URL}history.php"
18
  }
19

          
20
  object SECRETS {
21
    val USER_NAME = "John Doe"
22
    val PASSWORD = "XXXXXXXXXXX"
23
  }
24
}


Code Explanation

  • BASE_URL is the main URL of our application.
  • In the URLS object, we have kept all the API ends points which start from BASE_URL.
  • InSECRETSI am keeping usernames and passwords so that they need to be in code. As an enhancement, we can take these secrets from a vault.
  • Our application under test has many headers. These various headers are stored in these variables.
  • Create 5 .scala files in com.pageObjectsas:
    • BasePagefor all the common code like header information.
    • LandingPage.scala
    • AuthenticatePage.scala
    • AppointmentPage.scala
    • HistoryPage.scala
    • BasePage.scalafor common header information.

LandingPage

Scala
 




x
11


 
1
package com.pageObjects
2

          
3
import io.gatling.core.Predef._
4
import io.gatling.http.Predef._
5
import com.helper.ConstantsData._
6

          
7
object LandingPage {
8
  val getlandingPage = http("Get Landing Page")
9
    .get(BASE_URL)
10
    .check(status.is(200))
11
}


Code Explanation

  • In LandingPage, we are landing onto the application's main page using BASE_URL and asserting that API should give a status code as 200.

AuthenticatePage

Scala
 




x


 
1
package com.pageObjects
2

          
3
import io.gatling.core.Predef._
4
import io.gatling.http.Predef._
5
import com.helper.ConstantsData._
6

          
7
object AuthenticatePage {
8

          
9
  val userName = SECRETS.USER_NAME
10
  val password = SECRETS.PASSWORD
11

          
12
  val getProfile = http("Get Profile")
13
    .get(URLS.PROFILE)
14
    .check(status.is(200))
15

          
16
  val login = http("Do Login")
17
    .post(URLS.LOGIN)
18
    .formParamSeq(
19
      Seq(
20
        ("username", userName),
21
        ("password", password)
22
      ))
23
    .check(status.is(200))
24

          
25
  val logout = http("Do Logout")
26
    .get(URLS.LOGOUT)
27
    .check(status.is(200))
28
}


Code Explanation

  • We have created 3 methods here in AuthenticatePage: to get the User's profile, to Login, and to Logout.
  • Since login call is a post-call that accepts form parameters in its request payload, I have used Gatling's method formParamSeq().
  • usernameand passwordwe are importing fromConstantsDatawhere the secrets are.
  • In all these 3 methods, respective URLs also we are getting from ConstantsData.

AppointmentPage

Scala
 




x


 
1
package com.pageObjects
2

          
3
import io.gatling.core.Predef._
4
import io.gatling.http.Predef._
5
import com.helper.ConstantsData._
6

          
7
object AppointmentPage {
8

          
9
  val bookAppointment = http("Book an appointment")
10
    .post(URLS.BOOK_APPOINTMENT)
11
    .formParamSeq(
12
      Seq(
13
        ("facility", "Tokyo+CURA+Healthcare+Center"),
14
        ("hospital_readmission", "Yes"),
15
        ("programs", "Medicaid"),
16
        ("visit_date", "21%2F01%2F2021"),
17
        ("comment", "My+new+appointment")
18
      ))
19
    .check(status.is(200))
20
}



Code Explanation

  • We have created 1 method here in AppointmentPage: to book an appointment.
  • Since this call again is a post-call that accepts form parameters in its request payload, I have used Gatling's methodformParamSeq().
  • InSeq()we need to pass the fields and their values.

HistoryPage

Scala
 




xxxxxxxxxx
1
11


 
1
package com.pageObjects
2

          
3
import io.gatling.core.Predef._
4
import io.gatling.http.Predef._
5
import com.helper.ConstantsData._
6

          
7
object history {
8

          
9
  val checkHistory = http("Check History")
10
    .get(URLS.HISTORY)
11
}



BasePage

Scala
 




xxxxxxxxxx
1
16


 
1
package com.pageObjects
2

          
3
import com.helper.ConstantsData._
4
import io.gatling.core.Predef._
5
import io.gatling.http.Predef._
6

          
7
object basePage {
8

          
9
  val httpProtocol = http
10
    .baseUrl(BASE_URL)
11
    .warmUp(BASE_URL)
12
    .acceptHeader(ACCEPT_HEADER)
13
    .acceptEncodingHeader(ACCEPT_ENCODING_HEADER)
14
    .acceptLanguageHeader(ACCEPT_LANGUAGE_HEADER)
15
    .userAgentHeader(USER_AGENT_HEADER)
16
}


Code Explanation

  • We have declared a variable ashttpProtocolhere which declares the baseUrl, warmUpurl and all the headers.
  • Under different header methods, we are passing respective headers, which we are importing again from ConstantsData.


Step 7: Let's write a journey test using these pages inside com.journeys.

  • Every test in the Gatling world is known as a Simulation, and it has to extend a Gatling's built-in class known as Simulation.
  • Our test will look like this:
Scala
 




xxxxxxxxxx
1
35


 
1
package com.journeys
2

          
3
import io.gatling.core.Predef._
4
import scala.concurrent.duration._
5
import com.helper.ConstantsData._
6
import com.pageObjects._
7

          
8
class MakeAnAppointment extends Simulation {
9

          
10
  object appointment {
11

          
12
    val myAppointment =
13
      exec(LandingPage.getlandingPage)
14
        .exec(AuthenticatePage.getProfile)
15
        .exec(AuthenticatePage.login)
16
        .exec(AppointmentPage.bookAppointment)
17
        .exec(HistoryPage.checkHistory)
18
        .exec(AuthenticatePage.logout)
19
  }
20

          
21
  val bookAnAppointment = scenario("Test appointment booking")
22
    .exec(appointment.myAppointment)
23

          
24
  setUp(
25
    bookAnAppointment.inject(
26
      rampUsers(50) during (50 seconds)
27
    )
28
  )
29
    .assertions(
30
      global.responseTime.max.lte(2000),
31
      forAll.failedRequests.count.lt(1)
32
    )
33
    .protocols(basePage.httpProtocol)
34

          
35
}



Code Explanation

  • There are 3 parts in the test
    • object appointmentwhich contains API calling in a sequence.
    • a variable asbookAnAppointmentwhich executes a scenario. This scenario name can be any user-relevant value as it gets displayed in the report.
    • asetUpthat does user injection followed by assertions.
  • I have kept the number of users as 50 with a ramp-up time of 50 seconds, i.e., in every 1 second, Gatling will create 1 virtual user.
  • Depending upon whether AUT is an Open Or Closed Model, we can consider the load injection behavior. Here since this application is an Open model, I have taken this load injection method:
rampUsers(10) during (5 seconds)


Step 8: Running the tests.

  • We need to specify the path of the test from the 'simulations' folder. 
Shell
 




x


 
1
./gradlew gatlingRun-com.journeys.MakeAnAppointment



Step 9: Checking Reports.

  • After successful execution, we can check out the reports inside the build/reports/Gatling folder by checking out the index.html file.
  • index.html file looks something like this:

index.html file example

In this report, we can check various parameters like:

  • The total number of users for every API. Every OK in Gatling is a success, and every KO means there is some failure.
  • How much time the APIs took to respond.
  • The number of requests per second.
  • The number of responses per second.

I hope all of you readers find this article useful!

Coming next: Post for running Gatling performance tests in Jenkins and Dockerised setup.

Gatling (software) Object model Object (computer science) Testing Scala (programming language) API Gradle application

Opinions expressed by DZone contributors are their own.

Related

  • Keep Your Application Secrets Secret
  • Maximizing Efficiency With the Test Automation Pyramid: Leveraging API Tests for Optimal Results
  • Cypress.io — The Rising Future of Web Automation Testing
  • How To Check for JSON Insecure Deserialization (JID) Attacks With Java

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!