Run massively scalable performance tests on web, mobile, and APIs

Request a Demo
Nov. 29th, 2017

Create a Checkout Load Test Scenario with Gatling

 

Gatling is an open source load testing Scala application. Unlike Apache JMeter™, Gatling doesn’t have a GUI interface. So, when you want to simulate a given scenario, you do it by writing a Scala script. If you want to learn more about Gatling and the differences between Gatling and JMeter, click here.

 

In this blog post we will simulate a typical checkout scenario using Gatling. If you have an e-commerce site, this blog post is for you.

 

Creating a Gatling Script

 

Let’s look at the flow we want to automate. We are going to an example e-commerce website.

 

1. Imagine the user enters your website and types in “iphone” in the search bar:

 

gatling load test checkout scenario

 

The corresponding script for the iphone search:

 

val cart = scenario("Cart")
// HOME PAGE
.exec(http("get home page")
 .get("/")
 .headers(headers_0))

// search
.exec(http("search")
 .get("/index.php?route=product/search&search=Iphone")
 .headers(headers_0)
  .check(status.is(200)))

.exec(http("selectIphone")
 .get("http://" + uri2 + "/index.php?route=product/product&product_id=40&search=Iphone")
 .headers(headers_6)
 .check(status.is(200))
 .resources(http("iphonePage")
 .get("http://" + uri2 + "/index.php?route=product/product/review&product_id=40")
 .headers(headers_7))
 .check(status.is(200)))

 

2. The search returns the phones that are available on the website. The user picks up the one she or he likes, adds it to cart, and goes to checkout:

 

running gatling

 

gatling open source load testing

 

The script:

 

// add to cart
.exec(http("add to cart")
.post("http://opencart.abstracta.us/index.php?route=checkout/cart/add")
.headers(headers_10)
.formParam("quantity", "1")
.formParam("product_id", "40")
.resources(http("getCart")
.get("http://" + uri2 + "/index.php?route=common/cart/info")
.headers(headers_7))
 .check(status.is(200))

// checkout
.headers(headers_2)
.resources(http("checkoutPage")
.get("/index.php?route=checkout/checkout")
.headers(headers_0),
         http("showLogin")
.get("/index.php?route=checkout/login")
.headers(headers_14))
 .check(status.is(200)))


.exec(http("Login")
.post("/index.php?route=checkout/login/save")
.headers(headers_16)
.formParam("account", "register")
.formParam("account", "guest")
.formParam("", "Continue")
.formParam("email", "JohnLennon@abstracta.com.uy")
.formParam("password", "1234")
.formParam("", "Login")
.resources(http("checkout")
.get("/index.php?route=checkout/checkout")
.check(status.is(200))
.headers(headers_0),
         http("paymentAddress")
.get("/index.php?route=checkout/payment_address")
.check(status.is(200))
.headers(headers_14),
         http("country")
.get("/index.php?route=checkout/checkout/country&country_id=222")
.headers(headers_19))
.check(status.is(200)))

 

3. Once there, the user logs in, complete the billing information and places the order.

 

open source load testing tools, gatling

 

.exec(http("billingInfo")
.post("/index.php?route=checkout/payment_address/save")
.headers(headers_16)
.formParam("payment_address", "existing")
.formParam("address_id", "155")
.formParam("firstname", "")
.formParam("lastname", "")
.formParam("company", "")
.formParam("address_1", "")
.formParam("address_2", "")
.formParam("city", "")
.formParam("postcode", "")
.formParam("country_id", "222")
.formParam("zone_id", "")
.resources(http("shippingAddress")
.get("/index.php?route=checkout/shipping_address")
.check(status.is(200))
.headers(headers_14),
         http("request_22")
.get("/index.php?route=checkout/checkout/country&country_id=225")
.check(status.is(200))
.headers(headers_19),
         http("request_23")
.get("/index.php?route=checkout/payment_address")
.check(status.is(200))
.headers(headers_14),
         http("request_24")
.get("/index.php?route=checkout/checkout/country&country_id=225")
.check(status.is(200))
.headers(headers_2),
         http("request_26")
.post("/index.php?route=checkout/shipping_address/save")
.headers(headers_16)
.formParam("shipping_address", "existing")
.formParam("address_id", "155")
.formParam("firstname", "")
.formParam("lastname", "")
.formParam("company", "")
.formParam("address_1", "")
.formParam("address_2", "")
.formParam("city", "")
.formParam("postcode", "90200")
.formParam("country_id", "225")
.formParam("zone_id", "3696"),
         http("request_27")
.get("/index.php?route=checkout/shipping_method")
.check(status.is(200))
.headers(headers_14),
         http("request_28")
.get("/index.php?route=checkout/shipping_address")
.check(status.is(200))
.headers(headers_14),
         http("request_29")
.get("/index.php?route=checkout/checkout/country&country_id=225")
.check(status.is(200))
.headers(headers_19),
         http("request_30")
.get("/index.php?route=checkout/payment_address")
.check(status.is(200))
.headers(headers_14),
         http("request_31")
.get("/index.php?route=checkout/checkout/country&country_id=225")
.headers(headers_19))
.check(status.is(200)))

.exec(http("Shipping")
.post("/index.php?route=checkout/shipping_method/save")
.headers(headers_16)
.formParam("shipping_method", "flat.flat")
.formParam("comment", "")
.resources(http("request_33")
.get("/index.php?route=checkout/payment_method")
.headers(headers_14))
.check(status.is(200)))


.exec(http("Payment")
.post("/index.php?route=checkout/payment_method/save")
.headers(headers_16)
.formParam("payment_method", "cod")
.formParam("comment", "")
.formParam("agree", "1")
.resources(http("request_38")
.get("/index.php?route=checkout/confirm")
.headers(headers_14))
.check(status.is(200)))

.exec(http("confirmPayment")
.get("/index.php?route=extension/payment/cod/confirm&_=1506910033976")
.headers(headers_39)
.resources(http("request_40")
.get("http://" + uri2 + "/index.php?route=checkout/success"))
.check(status.is(200)))

.exec(http("request_42")
.get("http://" + uri2 + "/index.php?route=common/home")
.headers(headers_6)
.check(status.is(200)))

 

This is the complete script. It consists of all the parts we went through as well as the scenario simulation. You can copy and paste it, and start trying it out.

 

class Cart extends Simulation {
private val baseUrl = "https://opencart.abstracta.us"

val httpProtocol = http
 .baseURL(baseUrl)
 .inferHtmlResources()
 .acceptHeader("*/*")
 .acceptEncodingHeader("gzip, deflate")
 .acceptLanguageHeader("en-US,en;q=0.5")
 .userAgentHeader("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:55.0) Gecko/20100101 Firefox/55.0")

val headers_0 = Map(
 "Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
 "DNT" -> "1",
 "Upgrade-Insecure-Requests" -> "1")

val headers_1 = Map("DNT" -> "1")

val headers_2 = Map(
 "Accept-Encoding" -> "gzip, deflate",
 "Pragma" -> "no-cache")

val headers_6 = Map(
 "Accept" -> "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
 "Accept-Encoding" -> "gzip, deflate",
 "DNT" -> "1",
 "Upgrade-Insecure-Requests" -> "1")

val headers_7 = Map(
 "Accept" -> "text/html, */*; q=0.01",
 "Accept-Encoding" -> "gzip, deflate",
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")

val headers_8 = Map(
 "Accept-Encoding" -> "gzip, deflate",
 "DNT" -> "1")

val headers_10 = Map(
 "Accept" -> "application/json, text/javascript, */*; q=0.01",
 "Accept-Encoding" -> "gzip, deflate",
 "Content-Type" -> "application/x-www-form-urlencoded; charset=UTF-8",
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")

val headers_14 = Map(
 "Accept" -> "text/html, */*; q=0.01",
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")

val headers_16 = Map(
 "Accept" -> "application/json, text/javascript, */*; q=0.01",
 "Content-Type" -> "application/x-www-form-urlencoded; charset=UTF-8",
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")

val headers_19 = Map(
 "Accept" -> "application/json, text/javascript, */*; q=0.01",
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")

val headers_39 = Map(
 "DNT" -> "1",
 "X-Requested-With" -> "XMLHttpRequest")


   val uri2 = "opencart.abstracta.us"


val cart = scenario("Cart")
 // HOME PAGE
 .exec(http("get home page")
  .get("/")
  .headers(headers_0))

 // search
 .exec(http("search")
  .get("/index.php?route=product/search&search=Iphone")
  .headers(headers_0)
   .check(status.is(200)))

 .exec(http("selectIphone")
  .get("http://" + uri2 + "/index.php?route=product/product&product_id=40&search=Iphone")
  .headers(headers_6)
  .check(status.is(200))
  .resources(http("iphonePage")
  .get("http://" + uri2 + "/index.php?route=product/product/review&product_id=40")
  .headers(headers_7))
  .check(status.is(200)))

 // add to cart
 .exec(http("add to cart")
  .post("http://opencart.abstracta.us/index.php?route=checkout/cart/add")
  .headers(headers_10)
  .formParam("quantity", "1")
  .formParam("product_id", "40")
  .resources(http("getCart")
  .get("http://" + uri2 + "/index.php?route=common/cart/info")
  .headers(headers_7))
   .check(status.is(200))

 // checkout
  .headers(headers_2)
  .resources(http("checkoutPage")
  .get("/index.php?route=checkout/checkout")
  .headers(headers_0),
           http("showLogin")
  .get("/index.php?route=checkout/login")
  .headers(headers_14))
   .check(status.is(200)))


 .exec(http("Login")
  .post("/index.php?route=checkout/login/save")
  .headers(headers_16)
  .formParam("account", "register")
  .formParam("account", "guest")
  .formParam("", "Continue")
  .formParam("email", "JohnLennon@abstracta.com.uy")
  .formParam("password", "1234")
  .formParam("", "Login")
  .resources(http("checkout")
  .get("/index.php?route=checkout/checkout")
  .check(status.is(200))
  .headers(headers_0),
           http("paymentAddress")
  .get("/index.php?route=checkout/payment_address")
  .check(status.is(200))
  .headers(headers_14),
           http("country")
  .get("/index.php?route=checkout/checkout/country&country_id=222")
  .headers(headers_19))
  .check(status.is(200)))

 .exec(http("billingInfo")
  .post("/index.php?route=checkout/payment_address/save")
  .headers(headers_16)
  .formParam("payment_address", "existing")
  .formParam("address_id", "155")
  .formParam("firstname", "")
  .formParam("lastname", "")
  .formParam("company", "")
  .formParam("address_1", "")
  .formParam("address_2", "")
  .formParam("city", "")
  .formParam("postcode", "")
  .formParam("country_id", "222")
  .formParam("zone_id", "")
  .resources(http("shippingAddress")
  .get("/index.php?route=checkout/shipping_address")
  .check(status.is(200))
  .headers(headers_14),
           http("request_22")
  .get("/index.php?route=checkout/checkout/country&country_id=225")
  .check(status.is(200))
  .headers(headers_19),
           http("request_23")
  .get("/index.php?route=checkout/payment_address")
  .check(status.is(200))
  .headers(headers_14),
           http("request_24")
  .get("/index.php?route=checkout/checkout/country&country_id=225")
  .check(status.is(200))
  .headers(headers_2),
           http("request_26")
  .post("/index.php?route=checkout/shipping_address/save")
  .headers(headers_16)
  .formParam("shipping_address", "existing")
  .formParam("address_id", "155")
  .formParam("firstname", "")
  .formParam("lastname", "")
  .formParam("company", "")
  .formParam("address_1", "")
  .formParam("address_2", "")
  .formParam("city", "")
  .formParam("postcode", "90200")
  .formParam("country_id", "225")
  .formParam("zone_id", "3696"),
           http("request_27")
  .get("/index.php?route=checkout/shipping_method")
  .check(status.is(200))
  .headers(headers_14),
           http("request_28")
  .get("/index.php?route=checkout/shipping_address")
  .check(status.is(200))
  .headers(headers_14),
           http("request_29")
  .get("/index.php?route=checkout/checkout/country&country_id=225")
  .check(status.is(200))
  .headers(headers_19),
           http("request_30")
  .get("/index.php?route=checkout/payment_address")
  .check(status.is(200))
  .headers(headers_14),
           http("request_31")
  .get("/index.php?route=checkout/checkout/country&country_id=225")
  .headers(headers_19))
  .check(status.is(200)))

 .exec(http("Shipping")
  .post("/index.php?route=checkout/shipping_method/save")
  .headers(headers_16)
  .formParam("shipping_method", "flat.flat")
  .formParam("comment", "")
  .resources(http("request_33")
  .get("/index.php?route=checkout/payment_method")
  .headers(headers_14))
  .check(status.is(200)))


 .exec(http("Payment")
  .post("/index.php?route=checkout/payment_method/save")
  .headers(headers_16)
  .formParam("payment_method", "cod")
  .formParam("comment", "")
  .formParam("agree", "1")
  .resources(http("request_38")
  .get("/index.php?route=checkout/confirm")
  .headers(headers_14))
  .check(status.is(200)))

 .exec(http("confirmPayment")
  .get("/index.php?route=extension/payment/cod/confirm&_=1506910033976")
  .headers(headers_39)
  .resources(http("request_40")
  .get("http://" + uri2 + "/index.php?route=checkout/success"))
  .check(status.is(200)))

 .exec(http("request_42")
  .get("http://" + uri2 + "/index.php?route=common/home")
  .headers(headers_6)
  .check(status.is(200)))


setUp(
 cart
  .inject(rampUsers(10) over (2 minutes)).protocols(httpProtocol))
 .assertions(
  global.requestsPerSec.gt(10),
  global.responseTime.percentile3.lt(300),
  global.failedRequests.percent.lt(1)
 )
}

 

Gatling Script Pointers

 

1. Gatling automatically follow redirects in case of 301, 302, 303 or 307 response status codes. If you don’t want that to happen, you can change that by adding .disableFollowRedirect to the httpprotocol val part of the code.

 

2. Every response status code is easily checked with this line of code .check(status.is(200). If the response is 200, return true, otherwise return false and the assertion will fail.

 

3. Finally, in order to run a performance test, you need to decide how many users you are running, how they will behave (will they hit the page at the same time, will they load in a linear way, etc. ), and for how long the test will run. Gatling allows us to accomplish all of this in a very flexible way.

 

We can setup different scenarios right away, for example:

 

1. This single line of code will add 10 users all at the same time:

 

setUp(scenario1.inject(atOnceUsers(10)) .protocols(httpProtocol))

 

2. This other scenario, (used in the script) will ramp-up 10 users over a period of 2 minutes and also use global assertions:

 

setUp(cart.inject(rampUsers(10) over (2 minutes )).protocols(httpProtocol))
   	 .assertions(
   		 global.requestsPerSec.gt(10),
   		 global.responseTime.percentile3.lt(300),
   		 global.failedRequests.percent.lt(1)
   	 )
}

 

In this case, these assertions will check that the requests per seconds was greater than 10, the response time percentile 95 was less than 300 ms and that the percentage of failed request must be below 1%. If you want to know more about simulating differents scenarios in Gatling, please read this.

 

Gatling Test Results

 

Once the script has run, Gatling will generate a beautiful html report like this one:

 

Gatling load testing test results

 

You can see that the global assertion for the response time failed.

 

You also can also see statistics about the response time of all the requests.

 

choosing load testing tools

 

and the Response time Percentiles:

 

gatling load testing how to

 

That’s it! You now know how to run a checkout scenario load test in Gatling.

 

Run your Gatling tests with BlazeMeter! Get scalability, multiple geo-locations and advanced reporting. To learn more, request a demo. Or, put your URL in the box below and your test will start in minutes.

 

Click here to subscribe to our newsletter.

     
arrow Please enter a valid URL

Interested in writing for our Blog? Send us a pitch!