Blog

Performance testing a Vaadin application: Part 4 Gatling

By  
Anastasia Smirnova
·
On Jan 12, 2021 3:40:37 PM
·

4-gatling

Gatling is a free, open-source performance testing tool. It was first released 2012 and has since gained in popularity. In addition to its free tools, Gatling offers a wide range of (commercial) professional services. Gatling is mainly implemented with the Scala programming language (as opposed to Java). In contrast to JMeter’s XML-based test scripts, Gatling creates scripts in Scala, which makes it more convenient for editing scripts with independent IDEs. Another benefit over JMeter, is that Gatling has better built-in support for WebSocket communication.

Note this is the fourth post in our Performance testing a Vaadin application blog series. For an introduction to the subject, see Part 1. Performance testing a Vaadin application, see Part 2. Apache JMeter, see Part 3.

Building a test script

The free Gatling distribution contains two different tools:

  • Recorder is a recording tool with a user interface, which allows you to easily set up a test script recording. 
  • Command line program that allows you to execute recorded test scripts. 


Building a test script starts with recording user interaction with a browser. Configure Gatling recorder to function as a proxy between a browser and a server, by defining the Listening port and setting Recorder mode to HTTP Proxy.

image2-Nov-10-2020-11-45-29-15-AM

You can also configure other recording parameters, such as a test name, location, and a list of static files that should not be recorded. When focusing on testing the application’s logic, it’s pretty common to blacklist static files, such JavaScript, CSS, and PNG files. We use the following parameters and the default set of blacklisted file extensions in our script example:

image1-Nov-10-2020-11-45-20-51-AM

Select Start to start the recording.  Gatling opens a new view, which shows recorded requests and responses, and allows you to stop and save. 

Adjusting the test script

Once you have recorded interactions of a user with the system under test (SUT), captured requests are saved into the specified scala file (set in the first screen). 

You can use any IDE or text editor to make the test script adjustments. These environments are known to work: Eclipse-based http://scala-ide.org/, Intellij IDEA with Scala plugin, or Scala metals with your favorite code editor (VS Code, Atom, etc.)

Let’s take a look at the structure of the recorded test script. The first part of the script is the imports and the class definition. 

 

import scala.concurrent.duration._

import io.gatling.core.Predef._

import io.gatling.http.Predef._

import io.gatling.jdbc.Predef._




class YourTestsName extends Simulation {

 

Then, there is a protocol definition and several header declarations.

val httpProtocol = http

.baseUrl("http://localhost:8080")

.acceptHeader("*/*")

.acceptEncodingHeader("gzip, deflate")

.acceptLanguageHeader("en-US,en;q=0.5")

.userAgentHeader("Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0")



val headers_1 = Map(

"Accept" ->

 

Finally, the test itself consists of a functional sequence of requests with delays between them.

val scn = scenario("YourTestsName")

.exec(http("request_0")

 .get("/")

 .headers(headers_0))

.pause(291 milliseconds)

.exec(http("request_2")

 .get("/offline-page.html")

 .headers(headers_2)

 .check(bodyBytes.is(RawFileBody("YourTestsName_0002_response.txt"))))

.exec(http("request_3")

 .post("/?v-r=uidl&v-uiId=0")

 .headers(headers_3)

 .body(RawFileBody("YourTestsName_0003_request.txt"))

 .check(bodyBytes.is(RawFileBody("YourTestsName_0003_response.txt"))))

.pause(120 milliseconds)

 

Recorded requests and responses are saved separately. Each request in the sequence starts with .exec, followed by the protocol (here http), followed by the request type with the URL There is also optionally a request body and HTTP header.

To make the script executable without errors, you need to extract the token from the first server response and substitute it for every request that follows. As the token is in UUID format, a regular expression can be applied to the first request to  retrieve the token. Since Gatling does not have a UI, this has to be done within the Scala code using a post request check function and a regular expression.

val scn = scenario("YourTestsName")

.exec(http("request_0")

 .get("/")

 .headers(headers_0)

 .check(regex("""Vaadin-Security-Key":\s?"([^"]*)""").saveAs("seckey"))

)

 

The extracted token can be used in subsequent requests using reference syntax similar to JMeter’s ${secKey}.

You also need to remove the response body content checks from the script:

.check(bodyBytes.is(RawFileBody("YourTestsName_0002_response.txt")))

 

Be careful not to remove too many parenthesis. As an alternative, you could have unchecked the Save & check response bodies? check box when configuring the recorder. But, saving these does help you to write regular expressions for node ids, if you want to make the test more stable for future changes. 

These are the only required steps to replay the script. However, it’s vulnerable to any changes made in the UI and even adding a label that is not used by a test could break it. For this reason, we suggest you also extract (in the same way) the synchronization tokens (syncId and clientId), as well as the node values of the most-used elements in the script. 

Setting up test parameters

You can define the number of users, and the ramp up time at the end of the test script like the following. Here 100 users are injected to the test scenario scn during 60 seconds and the HTTP Protocol is used.

setUp(scn.inject(rampUsers(100) during (60 seconds))).protocols(httpProtocol)

 

You can take a look at a fully configured Gatling test script by downloading our Bakery demo project: Bakery Full Stack Starter. It contains examples of regular expression extractors for extracting csrfToken, clientId, syncId, and multiple node ids. There is also an example of Maven integration of the test script where you can easily parameterize for instance the number of users and ramp up time.

What is next? 

To mimic a production environment as closely as possible, it’s often necessary to pass dynamic data to the test. For example, this could mean that a random value from a combobox should be selected. Each component has its own logic (for example, a physical position defines the selected key), but it’s essential to instruct Gatling to generate data randomly or select it from the passed values. You can read more about this at Use dynamic data with Feeders and Checks.