Wilson Mar bio photo

Wilson Mar

Hello. Hire me!

Email me Calendar Skype call 310 320-7878

LinkedIn Twitter Gitter Google+ Youtube

Github Stackoverflow Pinterest

Load test sooner by updating NeoLoad scripts from Selenium

Overview

This article provides “newbies” a hands-on way to (on Macs and Windows machines) install and use Selenium and NeoLoad together in order to include performance testing during software development.

This makes for easier/faster way to software development such that load testing is performed alongside software development and then included as part of System Demos at the end of each Agile sprint.

Why this software?

Selenium automates functional testing by emulating signals from keyboards and mice. Selenium controls (automates) the keyboard and mouse, emulating human end-users.

This technology makes use of Selenium to control the keyboard and mouse while NeoLoad listens to the network traffic and updates its “user paths” (automation scripts) to emulate that network traffic.

After some editing, Neoload scripts are run on load generators that take the place of many real clients in order to impose a simulated load on web servers and the infrastructure around it (database, Web server, network components, etc.). During “load test” runs, user response times and other statistics are captured by additional monitoring software.

All this is not yet fulfill the complete vision where tests are automatically and fully created with the application code, But this does foster additional speed and agility we haven’t had before now to verify if existing scripts are still working.

Workflow

Here is how to do it, step-by-step: CAUTION: Work in progress!

  1. Get files from my GitHub using a Git client.
  2. Obtain an instance of all the components in the Google cloud, install on your own machine from a Docker image or as individual components.
  3. Run sample files to understand how everything works.
  4. Learn to organize user actions as transaction names in the sample app, sequenced under “run type” sequences.
  5. Create or reuse a NeoLoad starter script with an object recognition framework and data variation logic.
  6. Configure NeoLoad to be re-generated by Selenium.
  7. Run from a Jenkins job.

    The above can be done once before a sprint, leveraging assets from other projects.

    As UI elements are created incrementally during a Sprint:

  8. Update the Selenium script of new actions and transactions for NeoLoad.
  9. Verify the Selenium script runs well (is functional).
  10. Edit the Selenium script to add code to NeoLoad transactions.
  11. Update the existing NeoLoad script by running the Selenium script.
  12. Edit the NeoLoad script to add correlations and verifications of new objects.
  13. Reuse my samples to test your own app.


User image on Google Cloud

If you are working on a Chromebook laptop or on a laptop that Corporate Security has locked down, instantiate a Dockerized server image in the Google Container Engine public cloud.

Create image

  1. Create a Google account if you don’t already have one. Login to it.
  2. Create a project in the Google Dashboard. (lower case letters). Google assigns a project name such as “temporal-loop-94520”.
  3. Under the COMPUTE section, select Container Engine, Container clusters.

    googlecloud-20170806-469x275-7k

  4. If it appears, click “Enable API”. Deploying takes several minutes.
  5. Click Create Container cluster.
  6. Edit the name of your cluster.
  7. Select a zone nearest to you (such as us-central1-f).
  8. Leave the Cluster size at 1.
  9. Click Create.

    Google Cloud Platform Console

    If you do not have permissions to install stuff,

  10. Go to the Google Cloud Platform Console for your project at
    https://console.cloud.google.com/home/dashboard

    google-cloud-shell-803x46-6k

  11. Click the “>_” icon for the Google Cloud Shell.
  12. Click “START CLOUD SHELL”.
  13. Copy the Project ID assigned by Google (such as “temporal-loop-94520”).
  14. Manually type the Google Cloud commands below.

    CLI on your workstation

    This is a good option if you’ll be working with Google Cloud instances so frequently that automation is a time-saver.

  15. Install Python 2.7 in the environment you’ll be using to issue Google Cloud commands.
  16. Install the Google Cloud SDK, which includes the gcloud command-line tool.
  17. Pick your operating system and follow the instructions.

    Alternately, on a Mac, a Homebrew package of it is available:

    brew tap caskroom/cask brew cask install google-cloud-sdk

  18. Use gcloud to install kubectl, the Kubernetes command-line tool:

    gcloud components install kubectl

  19. Follow the documentation to initialize gcloud with credentialed accounts on your local environment:

    gcloud init

  20. Log in to your Google user account when prompted.
  21. Click “Allow” to grant permission to access Google Cloud Platform resources.
  22. Select a project.

    PROTIP: Although there is a way to set a default compute/zone, (such as gcloud config set compute/zone us-central1-b) we do not recommend it because you will likely change it and need to be aware of what it is to avoi rogue instances eating your wallet.

    Local Google Cloud Command file

  23. In a text editor, construct a command file you’ll use again, such as:
    java-selenium-neoload-v1-start.sh

  24. Copy the Project ID assigned by Google (such as “temporal-loop-94520”).
  25. Copy the commands below and save it in a file.
  26. On a Mac, construct a command to enable running:

    chmod +X java-selenium-neoload-v1-start.sh

  27. Run the command file:

    ./java-selenium-neoload-v1-start.sh

    Google Cloud Commands

  28. Copy the Project ID assigned by Google (such as “temporal-loop-94520”).
  29. Paste the value as you construct your version on these commands:

    gcloud config set project temporal-loop-94520
    gcloud config set compute/zone us-central1-f
    gcloud config set containter/cluster cluster-1
    gcloud beta container get-credentials
    kubectl run webserver --image=java-selenium-neoload-windows-v1
    kubectl get rc
    

    NOTE: Even if this server crashes, Google will bring it up automatically.

    The image=java-selenium-neoload-windows-v1 above refers to the Docker image described next.

    This sample is in the GitHub repo

  30. Install Bash for Windows to execute the sample above in Windows.
  31. Run the script.

    NOTE: This cannot currently be done on the AWS EC2 (Amazon Web Services Elastic Compute Cloud).

    • https://www.youtube.com/watch?v=Yji-nfuUvIo

Docker image

The easiet way with work with this is to use Docker to download a single image which contains all the installers already run.

In a Terminal window:

Docker Pull

  1. If you have Docker installed on your machine (and it has enough memory, CPU power, disk space), bring up an image that contins the image

    docker pull ???/java-selenium-neoload-windows-v1

    Alternately:

    docker pull ???/java-selenium-neoload-linux-v1

    TODO: Dockerize an image and put it in Docker Hub!

  2. Navigate to the folder that contains the demo code. In our case:

    cd /gits/wilsonmar/Java-Selenium-NeoLoad

  3. Pull down the latest version of the demo code, which may have been updated since the Docker image was put together:

    git pull

    TODO: Instead, use a shell script to do the above, and more.

    NeoLoad License

    NeoLoad licenses require renewal every year.

  4. Request one from http://go.neotys.com/NeoLoad-Free-Edition-Download.html

  5. Save the file from your email.

    Docker Pull

  6. Run Maven install.

    mvn install

Install locally

I’m working now to have a similar script using PowerShell.

But if you have a Mac, you can try my single line installer to get these directly on your own machine:

  1. Git client (to pull from GitHub)
  2. A Sample app to test (Ushahidi, JPetStore, JPetClinic, etc.)
  3. Java Development Kit
  4. Maven to build Java after processing the pom.xml file of dependencies
  5. Selenium Build automation for Mac installs:
    1. Selenium Web Driver
    2. Google Chrome browser
    3. ChromeDriver
    4. GeckoDriver is loaded directly by Selenium scripts
    5. Firefox browser
    6. Eclipse or IntelliJ IDE (which has JUnit built-in)

    SikuliX install adds :

    1. OpenCV to recognize images
    2. Tesseract to recognize text
  6. NeoLoad 6.0 Install
  7. NeoLoad NLWebDriver (added manually or via Maven)
  8. NeoLoad Monitoring

All these are free open source software (FOSS), except NeoLoad which provides a free license for up to 50 simultaneous virtual users.


Get from GitHub

  1. Change to or create a folder where Git will create a folder on your local hard drive:

    cd ~/gits/wilsonmar

    You need to substitute “wilsonmar” here with your own account name if you forked the repo.

  2. Get the repo onto your local hard drive (using this command which wraps into two lines):

    git clone https://github.com/wilsonmar/Java-Selenium-NeoLoad --depth=1

    --depth=1 specifies the depth of history downloaded, with 1 if you only want the latest version and no back versions. This saves some disk space.

  3. Dive into the folder created by git clone:

    cd Java-Selenium-NeoLoad

    The folder contains a pom.xml file for processing by Maven.

    Maven clean install

  4. Use a text editor to view the pom.xml file.

    NeoLoad’s documentation states that NeoLoad integration has been tested on Selenium versions 2.53.0 and 3.0.1.

    NOTE: The version of the Selenium Proxy for Maven is 2.0.6.

    <dependencies>
      <dependency>
     <groupId>com.neotys.selenium</groupId>
     <artifactId>neotys-selenium-proxy</artifactId>
     <version>2.0.6</version>
      </dependency>
      <dependency>
     <groupId>org.seleniumhq.selenium</groupId>
     <artifactId>selenium-java</artifactId>
     <version>2.0.6</version>
      </dependency>
    </dependencies>
    

    NOTE: Projects not built using Maven would need to add the Selenium proxy JAR (with dependencies available for download) on the Neotys Labs page.

  5. Have Maven download dependencies specified in the app’s pom.xml file:

    mvn clean install

    Maven creates a target folder.

    ???

    NeoLoad NLWebDriver

    (added manually or via Maven)

    The wrapper NLWebDriver provided by Neotys enables Selenium scripts into NeoLoad User Paths.

    It can be used without any interaction with NeoLoad. Therefore it doesn’t impact existing functional tests.

Sample Code on Sample Apps

There are several sample apps.

Setting the server up is beyond the scope of this article.

Ushahidi sample web app

  1. Click the URL below:

    http://ushahidi.demo.neotys.com

    This URL is within code examples within Neotys on-line documentation at:
    https://www.neotys.com/documents/doc/neoload/latest/en/html/#8266.htm

    Landing

    neoload-ushahidi-974x722-517k.png Click on image for a full-screen pop-up

    According to Wikipedia: this app was initially released in 2009 as open source on GitHub to “crowdsource” reports from local citizens about voter intimidation and fraud.

    Dots on the map shown shows the location of each observation reported around the world.

    The word for “testimony” or “witness” in the Swahili language is “Ushahidi”, and thus the Ushahidi platform used to build the app shown.

    The current implementation is not complete:

    • Do not Click “Provide Feedback” at the bottom of the screen. A 404 page appears.
    • “Get Alerts” is not clicked within scripts because the response is “This module is not available”.
    • There are no “Official & mainstream news” to view.

    • TODO: How to reset the data is unknown.
    • Reduce the width of the browser and note that the app is NOT “responsive” to different widths.

    NewAccount

  2. Click the “Login” link at the top of the page.

  3. Click “Create an Account”.

    http://ushahidi.demo.neotys.com/login/?newaccount

  4. Fill the information. Consider user data from a file, etc.
  5. Click “Sign Up”.

    ForgetPassword

  6. Click the “Login” link at the too of the page.

  7. Click “Forget Password”.

    NOTE: In the HTML, the value for name “form_auth_token” is sent, not the email address. This is an example of why a value needs to be captured in the HTML so that it can be passed back to the server. Such work is called “correlation” of data. An example of HTML containing a form_auth_token value is:

    <form action="http://ushahidi.demo.neotys.com/login" method="post" id="header_nav_userforgot_form">
    <input type="hidden" name="form_auth_token" value="4cab5f2d740c2761e64b867c2b0180578e666517ff17f790fd72d25ed41a3495"  />
    

    This value is obtained between left and right boundries:

    • The left boundry is form_auth_token\" value=\"
    • The right boundry is \"

    Login

  8. Click the “Login” link at the too of the page.

    neoload-ushahidi-login-167x215-5k

    Clicking Login within this app does not involve additional communication with the server.

    NewItem

  9. Click “How to Report” on the upper-right corner of the map for the different mechanisms of reporting. The URL is http://ushahidi.demo.neotys.com/reports/submit/

    neoload-ushahidi-howtoreport-195x81-19k

  10. Click “By filing this form on our website”.

    Alternately, the form can also be reached by clicking the “SUBMIT A REPORT” menu item.

    Or the form can also be reached by clicking the “SUBMIT A REPORT” orange button at the upper right corner.

    neoload-ushahidi-newitem-918x801-297k.png Click on image for a full-screen pop-up

    QUESTION: How many files are downloaded initially? What is the size of each?

    QUESTION: How many files are downloaded on the second iteration? (Is the cache populated)

  11. Right-click any white space on the page and select “Inspect Element” for the HTML.

    • There are iehacks css files for IE 6, 7, and 8.
    • Text in HTML are not minified and not packaged together.

  12. Type in “Selenium title” in the field to the left of the blue SEARCH button. That is the text added in the sample script.
  13. Click the button.

    List (Report)

  14. Click the “REPORTS” menu item.

    neoload-usahadi1-report-922x588 Click on image for a full-screen pop-up

    NOTE: Categories of observations currently are Cyclone, Avalanche, Wildfire.

    The total number of reports in the database can be a factor in response time.

    QUESTION: How much quicker would response time be if less observations are shown in the report? Although not relevant here since there is no way to change it, the number of reports listed per page can be a factor in response time as well.

    So capture the number of reports in the HTML coming back from the server.

    TODO: Where to save the number of reports in the page?

    Plan of Transactions by Run Type

    Functional of the app arranged by typical load testing run types:

    1. “Landing” (map display)
    2. “Menus”
    3. “NewAccount” - to stress database adds
    4. “LogInOut” - to stress authentication services
    5. “ForgotPassword” - to stress the email interface
    6. “NewItem” - “Submit a New Report” in the app at http://ushahidi.demo.neotys.com/reports/submit/
    7. “Search” -
    8. “List” -

    Transaction Naming

    Response times associated with transaction names from several scripts can be later combined together, so it’s a good idea to use transaction names that are unique, such as:

    Usahidi1-Landing-Home

    The NeoLoad 6 User Path (script) (in default neoload_projects folder) is simply:

    Usahidi1_NL6

    • WARNING: No dashes are accepted in NeoLoad project names.
    • NeoLoad requires a conversion of scripts from the prior release (e.g., from 5 to 6).

    The Selenium 4 script folder is simply:

    Usahidi1_SL4

Export Selenium for NeoLoad

NOTE: After editing Selenium Java test scripts, the Java project must be exported to a “Runnable JAR file” so that it can be launched by NeoLoad.

To define a launch configuration that contains the test class to execute:

import org.junit.runner.JUnitCore;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
    
@RunWith(Suite.class)
    
@Suite.SuiteClasses({
   HomeTest.class,
   ReportTest.class
})
    
public class EndUserExperienceTestSuite {
  public static void main(String[] args) throws Exception {
         JUnitCore.main(EndUserExperienceTestSuite.class.getName()); // EndUserExperience only?
  }
}
  1. Enter a project name, specify the directory where to save the JAR file:

    in the /custom-resources folder of your NeoLoad project

    in the /extlib directory of your NeoLoad installation for multi-project usage

  2. Click Finish.

Invoke from Eclipse

Even though there is some controversy about include them in version control, the folder has a .settings folder containing two files that provide consistent Eclipse IDE settings:

org.eclipse.jdt.core.prefs sets the Java version used by the Eclipse Formatter. It is set in Eclipse via project | Properties | Java Code Style | Formatter page. Enable project specific settings.

org.eclipse.m2e.core.prefs where “m2e” is Maven to Eclipse. It is set in Eclipse via Project | Properties | Java Compiler.

See Eclipse IDE for use of keyboard shortcut keys.

Invoke by Maven

The Selenium driver can be invoked as a Maven task.

  1. Launch all tests using a command:

    mvn -Dnl.selenium.proxy.mode=Design\
    -Dnl.design.api.url=http://ushahidi.demo.neotys.com/ \
    clean test
    

    The response ends with output such as:

    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD SUCCESS
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2.157 s
    [INFO] Finished at: 2017-08-06T11:43:30-04:00
    [INFO] Final Memory: 12M/197M
    [INFO] ------------------------------------------------------------------------
    

    Maven Surefire plugin

    To launch only a subset of unit tests, add and use the Maven surefire plugin.

  2. First, include this in your pom.xml :

    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-surefire-plugin</artifactId>
    <version>2.19.1</version>
     <dependencies>
      <dependency>
         <groupId>org.apache.maven.surefire</groupId>
         <artifactId>surefire-junit47</artifactId>
    <version>2.19.1</version>
      </dependency>
     </dependencies>
    </plugin>
    
  3. Launch a test run using this command. For example, the asterisk in this launches only test classes that end with (for example) “PerfTest” as in files ending with “PerfTest.java”:

    mvn -Dnl.selenium.proxy.mode=Design -Dnl.design.api.url=http://ushahidi.demo.neotys.com/ -Dtest=*PerfTest clean test
    

    Having tests named this way is a Maven convention.

    The tests of course must have been defined within the test repository of your Maven project.

Eclipse Tools

Plugins from the Eclipse Marketplace and IntelliJ:

  • Inifitest automatically re-runs tests after detecting changes, for continuous testing.

  • EclEmma or Cobertura for identifying code coverage.

NeoLoad Starter script

In the GitHub repository is the NeoLoad starter script with an object recognition framework and data variation logic:

  1. Invoke NeoLoadGUI version 6.
  2. Within NeoLoadGUI open the sample User Path:

    Ushahidi1.???

    PROTIP: The User Path name begins with the application name with a number designating the app’s release.

    Run Configuration

  3. Go to Run Configuration

    [image here]

  4. Set the mode, use the nl.selenium.proxy.mode property as a VM option or a program argument. Example:

    -Dnl.selenium.proxy.mode=Design

    This is one of three modes to use the NeoLoad wrapper:

    • “NoApi” - This is the default mode. In this mode, there is no interaction with NeoLoad.
    • “Design” - a User Path is automatically created or updated through the Design API.
    • “EndUserExperience” - Selenium time measurements are sent to NeoLoad through the Data Exchange API.

Selenium Sample Code

URL supplied from caller

Regular Java programs have a Main class the Java compiler uses as the “entry point” to begin execution.

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

The args (arguments) string is how the program receives arguments given to execute the program.

   JUnitCore.main(Ushadidi1-junit4.class.getName());            

### Command arguments

https://www.neotys.com/documents/doc/neoload/latest/en/html/#8278.htm
describes additional information to feed into Selenium include:

The NeoLoad license API key:

   -Dnl.api.key="32l234234abacdeeeffffgg2235523"

Operating system (Windows, Linux, Mac OS):

   "-Dnl.os=Mac OS"

The URL under test:

   -Dnl.design.api.url=http://localhost:7400/Design/v1/Service.svc/

Turn on debugging:

   -Dnl.debug=true

### Suites

import org.junit.runner.JUnitCore;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
    
@RunWith(Suite.class)
    
@Suite.SuiteClasses({
   HomeTest.class,
   ReportTest.class
})
    
public class EndUserExperienceTestSuite {
  public static void main(String[] args) throws Exception {
         JUnitCore.main(EndUserExperienceTestSuite.class.getName()); // EndUserExperience only?
  }
}

TIP: The structure of suites is illustrated by the following diagram from the 2h 37m Unit Testing In Java With JUnit video class released 10 May 2013 on Pluralsight.

junit-suite-579x411-67k

### Categories

import org.junit.experimental.categories.Category;
import org.junit.experimental.categories.Categories;
import org.junit.experimental.categories.Categories.IncludeCategory;

@RunWith(Categories.class)
@IncludeCategory(UTestGood.class)

@Test
@Category(UTestGood.class)
public class HelloTest {
   ...   
}    

TIP: The structure of suites is illustrated by the following diagram from the 2h 37m Unit Testing In Java With JUnit video class released 10 May 2013 on Pluralsight.

junit-category-584x434-98k

### Parametized Tests

### JUnit Annotations

In the sample code are annotations for the Java compiler to process:

  • @Rule
  • @BeforeClass
  • @Test
  • @AfterClass

First of all, annotations, in general, make code easier to understand by making it is more obvious what the code is supposed to do. The Java compiler may warn if a method does not actually do what the annotation says.

Annotations are also like a “magic spell” that applies additional generic code around the method under the annotation, such as logging statements. Thus, annotations minimize coding.

To see the basic structure of code behind an annotation, see
https://github.com/ajitsing/JavaCustomAnnotations which provides a simple example to create a custom annotation. Basically, it uses Java Introspection features.

Additional code added are defined within classes imported at the top of the code.

import org.junit.Rule;
import org.junit.rules.TestName;
import org.junit.BeforeClass;
import org.junit.AfterClass;

Annotations here are introduced with version 4 of JUnit.
https://github.com/junit-team/junit4/wiki/Rules
explains that the @TestName Rule makes the current test name available inside test methods. The page begins by saying “Rules allow very flexible addition or redefinition of the behavior of each test method in a test class. Testers can reuse or extend one of the provided Rules below, or write their own.”

JUnit rules can intercept then:

NOTE: @BeforeClass (@BeforeAll in Junit5) is used instead of @Before so that it is executed only once before the entire test fixture, thus sharing the same computationally expensive setup code. @Before is executed before every @Test. Between @BeforeClass and @AfterClass, various @Tests are not executed in the sequence in the source code.

This is “Inversion of Control” introduced in version 4 of JUnit. Junit Rules work on the principle of AOP (aspect oriented programming).

JUnit wraps your test method in a Statement object so statement.Execute() runs your test. Then instead of calling statement.Execute() directly to run your test, JUnit passes the Statement to a TestRule with the @Rule annotation. The TestRule’s “apply” function returns a new Statement given the Statement with your test. The new Statement’s Execute() method can call the test Statement’s execute method (or not, or call it multiple times), and do whatever it wants before and after. Now JUnit has a new Statement that does more than just run the test, and it can again pass that to any more rules before finally calling Execute.

  • https://stackoverflow.com/questions/13489388/how-does-junit-rule-work

### @BeforeClass NeoLoad

Under the @BeforeClass is code to invoke NeoLoad and open the NeoLoad project designated by providing to JUnit the “driver” variable containing a path. There are two ways to do that.

One is to specify null for the currently opened NeoLoad project with a hard-coded NeoLoad User Path (script) file name.

   final String projectPath = null;
   driver = NLWebDriverFactory.newNLWebDriver(webDriver, "steve", projectPath);
   

Alternately, a hard-coded .nlp file path:

   final String projectPath = "C:\\Users\\anouvel\\Documents\\NeoLoad Projects\\v5.3\\Sample_Project\\Sample_Project.nlp";
   driver = NLWebDriverFactory.newNLWebDriver(webDriver, testName.getMethodName(), projectPath);
   

The getMethodName() function is within the class defined under the @Rule annotation

   @Rule
   public TestName testName = new TestName();
   

It, in turn references classes imported from:

   import org.junit.rules.TestName;
   

Using wrapper code allows quick and easy integration with existing Selenium test cases with minimal changes to existing code. Page load times and any error messages are sent to NeoLoad as external data.

### Timeout Rule

To specify a particular test taking a maximum time of one second (in milliseconds):

@Test(timeout=1000)
   

To specify timeouts generically by adding this line:

   driver.manage().timeouts().implicitlyWait(5, TimeUnit.SECONDS);
   

### Expect an Exception

To specify that test code is expected to throw an exception:

@Test(expected=Exception.class)

The @ErrorCollector rule collects several errors for display all at once rather than immediately.

### @Ignore

PROTIP: The test program is executed from top to bottom.

To skip a test, add under @Test the @Ignore annotation.

But this is rather static code.

To define code that can select which tests are run at run-time, we can vary the value of the “RunType” argument when invoking the test program.

### Test Structure

As UI elements are created incrementally during a Sprint, add them to the java program.

TIP: To make this easier, add an extra level of functions in a Selenium framework described by John Sonmez in his 3h46m Creating an Automated Testing Framework With Selenium video class released on 26 Sep 2013 on Pluralsight.

### @ClassRule

@ClassRule annotations define custom rules that add functional before or after a test runs.

### NeoLoad Transactions

driver.startTransaction("Home Page");
   

CAUTION: The transaction name should match transactions named within NeoLoad scripts Selenium updates.

### Object in HTML

To find the object associated with a menu item text to click on:

   driver.findElement(By.partialLinkText("SUBMIT A REPORT")).click();
   

After you find the “class=” name by looking at the HTML returned from the server, specify it so Selenium can click on it. For example:

<div class="submit-incident clearingfix"><a href="http://ushahidi.demo.neotys.com/reports/submit">Submit a Report</a></div>
   

is activated by this Java code:

    driver.findElement(By.className("submit-incident")).click();
   

### Select by CSS Selector

If you need to specify a selector in the CSS such as this, where class=”report_row” is repeated:

<div class="report_row">
          <input name="submit" type="submit" value="Submit" class="btn_submit" /> 
   

use this example:

    driver.findElement(By.cssSelector("div.report_row > input[name=\"submit\"]")).click();
   

### Landing Page

The landing page may be used by every transaction that needs to begin from that page.

   String baseUrl = "http://ushahidi.demo.neotys.com";
     driver.startTransaction("Home Page");
     driver.get(baseUrl);
   

### Page Pattern

PROTIP: To make it easier/faster to edit the Java file, use a more “modular” approach to structuring lines of code. Instead of each test directly interacting with HTML elements, adopt the “Page Pattern” of coding:

selenium-page-pattern-736x40-59k

### Start NeoLoad Transactions

Transactions are defined to begin and stop specific time counters.

In this example, transactions can be added with the startTransaction method when creating or updating User Paths.

driver.startTransaction("home");
driver.get("http://ushahidi.demo.neotys.com/");

Whenever the mode is not set to “Design”, calls to startTransaction are ignored.

### Parametization

In order to identify

User data from a file

How quickly can new users can be added into a system?

That question is answered by load testing of the New Account UX.

Database Admin

Occassionally, the database would need to be cleared (reset). This is done by re-initializing the database.

Before that, the database may be archived.

The database can be optionally re-established from archives.


Monitoring

User Experience Measurements

Regarding user experience measurements, the navigation library is available in the browsers listed here.

Measurement of the time elapsed on the end-user side is enabled by the W3C Navigation Timing library at https://www.w3.org/TR/navigation-timing which on July 2017 is supported by leading modern internet browsers.

Methods of the Selenium wrapper

To specify the scenarios you want to update, launch tests with Maven without specifying particular options or use the Design option and several dedicated methods on top of the Selenium driver

  • NLWebDriver(Selenium webdriver,Name of the NeoLoad User Path, path to the NL project);

  • NLWebDriver is the constructor of the NeoLoad webdriver. This constructor allows you to specify the project that is to be updated with the new/updated User Path.

    ``` final FirefoxDriver webDriver = new FirefoxDriver(addProxyCapabilitiesIfNecessary(new DesiredCapabilities())); // projectPath used to open NeoLoad project, null to use the currently opened Project. final String projectPath = “C:\Users\apaul\projects\Sample_Project.nlp”; NLWebDriver driver = NLWebDriverFactory.newNLWebDriver(webDriver, “SeleniumUserPath”, projectPath); NLWebDriver(Selenium webdriver,Name of the NeoLoad User Path);

Project path is optional. If the project is not specified, the wrapper will use the currently opened project.

final FirefoxDriver webDriver = new FirefoxDriver(addProxyCapabilitiesIfNecessary(new DesiredCapabilities()));
&nbsp;   
NLWebDriver driver = NLWebDriverFactory.newNLWebDriver(webDriver, "SeleniumUserPath");
StartTransaction(Name of the current transaction);

This method sends all the Selenium HTTP/HTTPS traffic into a specific NeoLoad container.

This methods needs to be used before the Selenium actions related to a business transaction.

public void testGetAlerts() {
driver.startTransaction("home2");
driver.get("http://ushahidi.demo.neotys.com/");
driver.startTransaction("alerts");
driver.findElement(By.partialLinkText("GET ALERTS")).click();
}

UnitTest 1 Sample

The Selenium driver is started once and stopped at the end of the whole test.

Only one User Path is created or updated.

package com.selenium.test;
import static com.neotys.selenium.proxies.NLWebDriverFactory.addProxyCapabilitiesIfNecessary;
import java.io.File;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import com.neotys.selenium.proxies.NLWebDriver;
import com.neotys.selenium.proxies.NLWebDriverFactory;
public class UnitTest {
  private static final String CHROME_DRIVER_PATH = "C:\\Selenium\\chromedriver.exe";
  static {
    final File file = new File(CHROME_DRIVER_PATH);
    System.setProperty("webdriver.chrome.driver", file.getAbsolutePath());
  }
  static NLWebDriver driver;

  @BeforeClass
  public static void before() {
    final ChromeDriver webDriver = new ChromeDriver(addProxyCapabilitiesIfNecessary(new DesiredCapabilities()));
    
    // projectPath used to open NeoLoad project, null to use currently opened Project.
    final String projectPath = "C:\\Users\\anouvel\\Documents\\NeoLoad Projects\\v5.3\\Sample_Project\\Sample_Project.nlp";
    &nbsp;
    driver = NLWebDriverFactory.newNLWebDriver(webDriver, "SeleniumUserPath", projectPath);
  }

  @Test
  public void testSubmit() {
    driver.startTransaction("home1");
    driver.get("http://ushahidi.demo.neotys.com/");
    &nbsp;
    driver.startTransaction("reports");
    driver.findElement(By.id("mainmenu")).findElements(By.tagName("a")).get(1).click();
    &nbsp;
    driver.startTransaction("submit");
    driver.findElement(By.partialLinkText("SUBMIT")).click();
  }
  
  @Test
  public void testGetAlerts() {
    driver.startTransaction("home2");
    driver.get("http://ushahidi.demo.neotys.com/");
    &nbsp;
    driver.startTransaction("alerts");
    driver.findElement(By.partialLinkText("GET ALERTS")).click();
  }
  
  @AfterClass
  public static void after() {
    if (driver != null) {
      driver.quit();
    }
  }
}

Methods of the Selenium wrapper

Method Description Example

NLWebDriver(Selenium webdriver,Name of the NeoLoad User Path, path to the NL project);

NLWebDriver is the constructor of the NeoLoad webdriver.

This constructor allows you to specify the project that is to be updated with the new/updated User Path. final FirefoxDriver webDriver = new FirefoxDriver(addProxyCapabilitiesIfNecessary(new DesiredCapabilities()));

// projectPath used to open NeoLoad project, null to use the currently opened Project.
final String projectPath = "C:\\Users\\apaul\\projects\\Sample_Project.nlp";
NLWebDriver driver = NLWebDriverFactory.newNLWebDriver(webDriver, "SeleniumUserPath", projectPath);
NLWebDriver(Selenium webdriver,Name of the NeoLoad User Path);
Project path is optional.
If the project is not specified, the wrapper will use the currently opened project.
final FirefoxDriver webDriver = new FirefoxDriver(addProxyCapabilitiesIfNecessary(new DesiredCapabilities()));
 
NLWebDriver driver = NLWebDriverFactory.newNLWebDriver(webDriver, "SeleniumUserPath");

setCustomName

This method sets a custom name of the next Entry that will be sent to the Data Exchange server.

driver.SetCustomName("custom entry name");

Advanced usage

The Java proxy sets a custom name of the next Entry that will be sent to the Data Exchange server.

Additionally there is a method to retrieve the regular expression being used to create the path when the nl.path.naming.policy argument is set to URL.

The example below illustrates these advanced uses:

NLWebDriver driver = WebDriverProxy.newInstance(new FirefoxDriver());
driver.setCustomName("custom entry name");
System.out.println("Escaped regular expression: " + driver.getRegexToCleanURLs());

Create manual timers

If the tested application is not compatible with the navigation timing library, you can still create your own timers manually by using the DataExchange client library.

In order to send external data to NeoLoad without Java, you can create custom timers manually, either from scratch or with the help of our utility TimerBuilder.

To create manual timers, you need first to create the Data Exchange API Client as described below.

The NeoLoad Data Exchange API Client provides the utility TimerBuilder in order to time a transaction (a set of business actions). Below is an example of Java code to add a timer.

import com.neotys.rest.dataexchange.model.TimerBuilder;

// Start timer
final TimerBuilder timer = TimerBuilder.start("scriptName", "timerName");

// Do some transactions, for example:
vpba16.avw_backboneCellarAndro.avw_.mo_cHATEAU_LE_DOYENNE.click();

// Stop timer
dataExchangeAPIClient.addEntry(timer.stop());

To enhance the timer’s information with specific data, for example a URL, a status, etc.

import com.neotys.rest.dataexchange.model.Status.State;
import com.neotys.rest.dataexchange.model.TimerBuilder;
import com.neotys.rest.dataexchange.model.Status;
import com.neotys.rest.dataexchange.model.Status.State;
import com.neotys.rest.dataexchange.model.StatusBuilder;

// Start timer
final TimerBuilder timer = TimerBuilder.start("scriptName", "timerName");

// Do some transactions, for example:
vpba16.avw_backboneCellarAndro.avw_.mo_cHATEAU_LE_DOYENNE.click();

// Specify URL
timer.url("myURL");

// Specify Status
final Status status = (new StatusBuilder()).code("code").message("message").state(State.PASS).build();

timer.status(status);

// Stop timer
dataExchangeAPIClient.addEntry(timer.stop());

The transactions’ timers are then accessible in the Runtime and Results views of NeoLoad:

Timers-Results

Metrics retrieved by the Selenium wrapper

The Selenium wrapper automatically retrieves navigation timers and sends them to the NeoLoad Data Exchange API.

All metrics sent to NeoLoad are specified in milliseconds.

These metrics are available during runtime and once the test is complete in the Runtime and Results sections:

  • Time to First Byte
  • DOM content loaded
  • On Load
  • Document complete

Start Selenium scripts

“User Experience” scripts created in Selenium are started by NeoLoad’s Java Test Script advanced action.

For more information about the Java Test Script advanced action, refer to the Java Test Script Launchers documentation.

The following configuration is required:

JRE is the path to the Java Runtime Environment executable on the Load Generator

  • Attribute arg1 must be: -jar
  • Attribute arg2 must contain the path of the JAR file that was exported, either its absolute path or the path relative to the custom-resources folder in the NeoLoad project: ${NL-CustomResources}/myjar.jar
  • Attribute arg3 must contain the mode -Dnl.selenium.proxy.mode=EndUserExperience
  • Attribute arg4 must contain the mode -Dnl.data.exchange.url=http://192.168.1.6:7400/DataExchange/v1/Service.svc/

nl-seleniumjavaproxyconfigoptions2.png

Configure the NeoLoad scenario

To configure your User Experience scenario, follow the guidelines documented in the End User Experience Integration User Guide.

See run results

The external data injected during execution is displayed in Results > Details. For more information, see by external data.

https://www.neotys.com/documents/doc/neoload/latest/en/html/#1484.htm#o7602

User Experience Integration

License module “Integration & Advanced Usage” is required to enable the End User Experience Integration.

  • https://www.neotys.com/documents/doc/neoload/latest/en/html/#8269.htm
  1. Get to the “NeoLoad Selenium Proxy Driver” from the
    https://www.neotys.com/support/neotys-labs/selenium-proxy-driver-for-end-user-experience

    Neotys Labs page at https://www.neotys.com/support/neotys-labs.

    The direct link for Java at time of writing is:

    https://www.neotys.com/support/neotys-labs/selenium-proxy-driver-for-end-user-experience

    https://www.neotys.com/support/neotys-labs/selenium-proxy-driver-c-automated-script-maintenance-end-user-experience

    The Selenium Proxy Driver allows you to use a Selenium script to create or update NeoLoad User Paths and/or measure the end user experience on one or a few browsers or mobile devices and to send these measurements to NeoLoad.

  2. Click “Download: Jar” link to download file:

    neotys-selenium-proxy-2.0.6.jar

  3. Click “Jar-with-dependencies” link to download file:

    neotys-selenium-proxy-with-dependencies-2.0.6

  4. Optionally, click “Source” link to download file:

    neotys-selenium-proxy-2.0.6-sources

  5. Optionally, click “Javadoc” link to download file:

    neotys-selenium-proxy-2.0.6-javadoc

  6. In your Downloads folder, invoke the “Selenium Proxy Driver” from the

  7. Modify Selenium scripts to indicate the NeoLoad Selenium driver.

  8. Modify Selenium scripts to add timers that will be converted into NeoLoad “transactions”.

  9. Set the mode appropriately for the Selenium execution:

    https://www.neotys.com/documents/doc/neoload/latest/en/html/#23462.htm

Jenkins for NeoLoad

  1. The Jenkins job to run Selenium would involve invoking the Selenium run Maven job.

  2. The post-build action to a code “conversion”, if successful, is to run the load test.

  3. For that, install the Jenkins plug-in for NeoLoad at

    https://wiki.jenkins.io/display/JENKINS/NeoLoad+Plugin

    Its source is at
    https://github.com/jenkinsci/neoload-plugin

    Support is at “plugin-support@neotys.com”.

  4. The plug-in works with “Freestyle” projects, not “Pipeline” using Groovy scripts.

TODO: Steps to add a job for this.

References

Continuous Performance Testing and Monitoring in Agile Development by Neotys does not show the above techniques.

Scraps - ignore

NOTE: The NeoLoad API for Selenium also enables capture of end-user experience measurements and equate them back into the NeoLoad results set.

This makes use the NeoLoad’s Java Launcher action.

NeoLoad can collect end-user experience and sends to NeoLoad the metrics calculated on the client (browser or mobile devices).