Overview

Getting started with Selenium based tests on the Flood platform is easy if you are using our simple examples as templates for your existing scripts. We get a lot of customer support requests asking what specific code needs to be added in order for existing Selenium tests to be run successfully so we thought it would be good to describe this a bit further.

This guide will go through exactly what is needed to ensure your Selenium scripts are set up with the correct structure, variables and libraries to make them work on Flood.

Libraries

Below is a typical list of imported libraries that would be included in a Selenium / WebDriver script along with some specialised Java utility libraries that you can use to add more intelligence to your script.

import java.net.URL;
import java.util.concurrent.TimeUnit;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.WebDriverException;

import org.openqa.selenium.JavascriptExecutor;

import org.openqa.selenium.remote.Augmenter;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

import org.openqa.selenium.support.ui.Select;

import io.flood.selenium.FloodSump;

import java.util.List;
import java.util.Random;

The key library for Flood is the following line:

import io.flood.selenium.FloodSump;

This mandatory library is called the FloodSump - Flood's reporting engine which retrieves statistics such as response times to be displayed on our dashboard when you are running performance tests.

The Selenium / Java class structure

The next component of a Selenium / Flood script is to setup a Public Java class as well as using the standard static Main function to enclose all your test steps.

public class SeleniumTest  {
  public static void main(String[] args) throws Exception { ... }

Here we have a public class called SeleniumTest. It can be called anything you like and should generally relate to what the test case needs to achieve. This class must also be called the same name as the java file itself (e.g. this file would need to be called SeleniumTest.java) otherwise an exception will occur once you try to run the test.

Inside the standard Java main function - Flood requires the following in order to function correctly:

  • WebDriver - this needs to be defined for every Selenium WebDriver test as it is used by every test step that needs to interact with page components. It is defined, for example by the following statement:
WebDriver driver = new RemoteWebDriver(new URL("http://" + System.getenv("WEBDRIVER_HOST") + ":" + System.getenv("WEBDRIVER_PORT") + "/wd/hub"), DesiredCapabilities.chrome());
  • FloodSump - this is the Tricentis Flood reporting engine as previously mentioned. A new instance is created before the main iterations loop:
/* Create a new instance of the Flood agent */
FloodSump flood = new FloodSump();
  • Flood.started() - this indicates to the Flood nodes that pre-conditions for setting up this test have been successful and we are about to start the test.
    /* Inform Flood the test has started */
    flood.started();

Iterating for a Performance Test

Selenium tests are built for functional testing and one of the key points for converting them into a performance test scenario is to include the concept of iterations. The purpose of including iterations in a Selenium test is simply to run the entire test a number of times.

So we already have a class structure setup - now this is what it looks like with iterations included:

public class SeleniumTest  {
  public static void main(String[] args) throws Exception {

  int iterations = 0;

  ...

    /* It's up to you to control iterations programatically. */
    while( iterations < 100 ) {
      try {
 
      ...

      } catch (WebDriverException e) {
        String[] lines = e.getMessage().split("\\r?\\n");
        System.err.println("Webdriver exception: " + lines[0]);
        flood.failed_transaction(driver);
      } catch(InterruptedException e) {
        Thread.currentThread().interrupt();
        String[] lines = e.getMessage().split("\\r?\\n");
        System.err.println("Browser terminated early: " + lines[0]);
      } catch(Exception e) {
        String[] lines = e.getMessage().split("\\r?\\n");
        System.err.println("Other exception: " + lines[0]);
      } finally {
        iterations++;
      }
    }

    ...

  }
}


So firstly, we set the iterations variable to an initial value of 0. It is important that this be done before the iterations loop is defined further down the script, otherwise you will keep setting it to 0 at every iteration and the script will infinitely execute.

The iterations loop is defined as a standard while loop.

while( iterations < 100 ) { ... }

Try ... Catch ... Finally

The try ... catch ... finally block also plays an important role within the iterations loop as it contains all the test steps relevant to your whole test scenario.

It also contains important exception handling code just in case errors related to WebDriver, thread interruption and other generic exceptions are encountered during the test. These exceptions are handled and logged by the Flood Selenium infrastructure and displayed as part of the test execution logs for every test.

Inside the try ... block - all your test case steps belong here. 

while( iterations < 20 ) {
      try {

        driver.get("https://flooded.io");
        flood.passed_transaction(driver, "Website loaded successfully.", 200, 200.0);

        WebElement loginBtn = driver.findElement(By.xpath("//*[@id='main-signin-home']/header/div[2]/div[1]/button[3]"));
        loginBtn.click();

        iterations++;

        /* Good idea to introduce some form of pacing / think time into your scripts */
        Thread.sleep(4000);

      } catch (WebDriverException e) { ...

So we have a small amount of steps within the try ... block. All we are doing here is navigating to the https://flooded.io site and clicking on the Login button.
Your script will most likely have a lot more steps because this is just for demonstration purposes.

Also notice that at the end of the test steps - we increment the iterations variable with:

iterations++;

This is essential as it allows us to progress to the last iteration and therefore the completion of the test.

The Thread.sleep statement is also recommended to include at the end of the test steps as it allows some Real-world Wait Time™ to be added in between iterations.

Debugging

For debugging purposes it is a great idea to write out variables or messages to the System output log, just like this:

System.out.println("Hello World - This is the front page");

This will help in debugging during a test and especially helpful if you are dynamically retrieving parameters or values from the page that will be used elsewhere in the script.

Cleaning Up

The last piece of the puzzle is to let the Flood Selenium node(s) know when the test has finished. This is achieved with two commands that are placed after the try ... catch ... finally block.

  • driver.quit() - This the Selenium WebDriver specific command to essentially cleanup all the resources and ensure a clean shutdown of the loaded driver.
  • flood.finished() - This statement notifies the Flood infrastructure that the test has finished and any post test cleanup activities can be initiated.
driver.quit();

/* Inform Flood the test has finished */
flood.finished();

And We're Done

So at the end of all these steps - we have created a Selenium WebDriver scenario that contains all the essential Flood code to get you up and flooding.

The completed code example for this guide is available here: https://gist.github.com/jrizio/fdf5ad342f57f3fec3c3fc2a450db992

If you found this advanced guide helpful please rate it! This gives The Flood team valuable feedback for what guides our customers are interested in.

Also, if you have any further questions please don't hesitate to ask one of our friendly Customer Success Engineers over at https://help.flood.io

Happy Flooding!

Did this answer your question?