How to Make Selenium Web Driver Scripts Faster



Many companies use today Selenium Web Driver for automating their web test cases. This is not a surprise because the Selenium Web Driver framework is
• Free
• Open source
• Language independent
• Operating System independent
 But the Selenium WebDriver scripts are typically slow. What follows is a list of suggestions for making your Selenium WebDriver scripts faster.
 Most of the suggestions work all the time. Some of them work only in specific situations. These suggestions can be used independently or together.

The Selenium Web Driver scripts are very slow because they run through the browser.
There are multiple things that can improve the Selenium WebDriver scripts’ speed:
1.      use fast selectors
2.      use fewer locators
3.      create atomic tests
4.      don’t test the same functionality twice
5.      write good tests
6.      use only explicit waits
7.      use the chrome driver
8.      use drivers for headless browsers
9.      re-use the browser instance
10.  run scripts in parallel
11.  use HTTP parse libraries
12.  pre-populate cookies
13.  do not load images in the web page

  If you want to learn more about Selenium Web Driver  or Selenium scripts performance in particular Register at Selenium Online Training.


USE FAST SELECTORS

Selenium WebDriver scripts allow using many types of locators.
When selecting the locator, start with the fast ones:
1. Search by ID
This works if the html element has the id attribute.
It is the fastest locator as it uses the document.getElementById() javascript command which is optimized for all browsers.
2. NAME selector
This works if the element has a name attribute.
3. CSS selector
It is faster than XPATH but not as flexible.
4. XPATH selector
This is the most flexible strategy for building locators.
But xpath selectors are the slowest of all as the browser dom of the web page needs to be traversed for finding the element.

 USE FEW LOCATORS IN SCRIPTS
 

Keep the number of locators as low as possible especially if using XPATH.
This goes together with keeping scripts focused and short.

 CREATE ATOMIC TESTS 

Avoid testing too many things in a single script.
It is better to have more small scripts focused on one thing only than fewer big scripts that do too many things.
§  Each test should test a single tiny bit of functionality
§  Each test should have up to 20 steps.
§  Each test should run in under 10 seconds.
Having atomic test is very useful in case of failures.
The failures are very clear about where the problem is.
Example
Let’s assume that one of the scripts is called testSignupLoginChangePasswordLogout().
This script checks 4 different things:
1.      Signup form works
2.      Login works
3.      Change password works
4.      Logout works
If the script fails, which part has an error? Signup? Login? ChangePassword? Logout?
Instead, we should use smaller and atomic scripts:
1.      testSignup()
2.      testLogin()
3.      testChangePassword()
4.      testLogout()
If any of the smaller tests fails, it is very clear where the problem is.

DONT TEST THE SAME FUNCTIONALITY TWICE 

Make sure that your scripts are not checking the same features over and over.

 If you checked that the login works correctly in one script, there is no benefit from checking it again in another script.

  WRITE GOOD TESTS


Good tests are created by following a few simple rules: Good written tests are fast tests.
§  Eliminate step duplication
§  Keep the scripts independent
§  Write just enough steps to go from A to B in the quickest way possible
§  Remove steps that are not related to the final result


USE ONLY EXPLICIT WAITS


One of the best ways of making a script faster is by using only explicit waits.
If your test scripts uses delays and implicit waits like this,
WebDriver driver = new FirefoxDriver();

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


driver.get(“
http://somedomain/url_that_delays_loading”);

WebElement myElement=driver.findElement(By.id(“myElement”));
replace them with explicit waits.
WebDriver driver = new FirefoxDriver();

driver.get(“http://somedomain/url_that_delays_loading”);


WebElement element = (new WebDriverWait(driver, 10))

.until(ExpectedConditions.presenceOfElementLocated(By.id(“element”)));

The script performance is better with explicit waits as HTML elements are accessed as soon as they become available.
No additional waiting times are needed.

USE THE CHROME DRIVER AND CHROME BROWSER

If you need a real browser, use Chrome and the Chrome driver.
The Chrome browser is faster than IE, Firefox, Safari and Opera.

 

 REUSE THE BROWSER INSTANCE


A typical JUNIT class includes the following components:
1.      constructor
2.      setUp() method
3.      tearDown() method
4.      test scripts
The setUp() method uses the @Before annotation and runs before each test script.
Its purpose is usually to create the driver object and open the browser window.
The tearDown() method uses the @After annotation and runs after each test script.
Its purpose is to destroy the driver object and close the browser window.
Each test script is using its own browser instance when the @Before and @After are used:
setUp() –> opens browser
Test Script 1
tearDown() –> closes browser
setUp() –> opens browser
Test Script 2
tearDown() –> closes browser
setUp() –> opens browser
Test Script 3
tearDown() –> closes browser
setUp() –> opens browser
Test Script 4
tearDown() –> closes browser
The browser  instance can be shared by all test scripts if we use different annotations:
1.      @BeforeClass instead of @Before for the setUp() method
2.      @AfterClass instead of @After for the tearDown() method
In this case, the setUp() method does not run before each test script but just once before all test scripts.
The tearDown() method runs once only after all test scripts.
After each test script, the browser is not closed so the next script can re-use it:
setUp() –> opens browser
Test Script 1
Test Script 2
Test Script 3
Test Script 4
tearDown() –> closes browser

RUN THE SCRIPTS IN PARALLEL


By default, JUNIT test scripts are run sequentially.
There are a few options for running them in parallel:

1. Run the scripts in parallel on the local computer


This can be done by
§  creating a Maven project in Eclipse
§  adding the Maven Surefire plugin to the POM.XML file
Maven Surefire allows methods or classes to be run in parallel.
It also allows the thread count to be set up.
See below a POM.xml file sample:
<modelVersion>4.0.0</modelVersion>
<groupId>com.siminiuc</groupId>
<artifactId>MavenProject</artifactId>
<version>0.0.1</version>
<name>Maven Project</name>
<dependencies>
     <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.12</version>
           <scope>test</scope>
      </dependency>
      <dependency>
          <groupId>org.seleniumhq.selenium</groupId>
          <artifactId>selenium-firefox-driver</artifactId>
          <version>2.47.1</version>
     </dependency>           
</dependencies>  

<build>
      <plugins>
           <plugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>2.3.2</version>
              <configuration>
                       <source>1.7</source>
                       <target>1.7</target>
                       <executable>C:\JDK\bin\javac.exe</executable>
             </configuration>
       </plugin>

      <plugin>  
                <groupId>org.apache.maven.plugins</groupId>  
                <artifactId>maven-surefire-plugin</artifactId>  
                <version>2.19</version>  
                <configuration>              
                          <parallel>methods</parallel>
                          <threadCount>5</threadCount>
              </configuration>
   </plugin>         
</plugins>
</build>

</project>

Running scripts in parallel using Maven Surefire reduces the execution time with about 50%.

2. Use Selenium Grid

Generally speaking, there are two reasons why you might want to use Selenium-Grid.
§  To run your tests against multiple browsers, multiple versions of browser, and browsers running on different operating systems.
§  To reduce the time it takes for the test suite to complete a test pass.
Selenium-Grid is used to speed up the execution of a test pass by using multiple machines to run tests in parallel.
For example, if you have a suite of 100 tests, but you set up Selenium-Grid to support 4 different machines to run those tests, your test suite will complete in (roughly) one-fourth the time as it would if you ran your tests sequentially on a single machine.
How does it work?
A grid consists of a single hub, and one or more nodes.
Both are started using the selenium-server.jar executable.
The hub receives a test to be executed along with information on which browser and ‘platform’ (i.e. WINDOWS, LINUX, etc) where the test should be run.
It ‘knows’ the configuration of each node that has been ‘registered’ to the hub.
Using this information, it selects an available node that has the requested browser-platform combination.
Once a node has been selected, Selenium commands initiated by the test are sent to the hub, which passes them to the node assigned to that test.
The node runs the browser, and executes the Selenium commands within that browser against the application under test.

3. Use Sauce Labs (selenium grid in the cloud)

It works similar with Selenium Grid with the advantage that you do not need to set up the grid environment.
It has hundreds of combinations of browser/device/operating system available.

USE HTTP PARSE LIBRARIES
 

There are cases when Selenium WebDriver is not the best option for creating test scripts.
For example, let’s take a simple test scenario:
1.      the user opens the home page of a website
2.      the user does a keyword search
3.      the results page is opened and it displays multiple results
4.      for each result displayed, open the details page and check that result information is included
It is quite simple to implement this with Selenium WebDriver.
See below a code sample:
@Test
public void test1() throws InterruptedException {

//1. open the home page of the site

driver.get(“http://www.vpl.ca&#8221;);

//2. execute keyword search

WebElement searchField = wait.until(ExpectedConditions.
visibilityOfElementLocated(searchFieldLocator));

searchField.click();

searchField.sendKeys(“java”);

WebElement searchButton = wait.until(ExpectedConditions.

elementToBeClickable(searchButtonLocator));

searchButton.click();


//4. iterates through all results links

for (int i = 1; i <= 10; i++) {

WebElement resultTitle = wait.until(ExpectedConditions.

elementToBeClickable(resultTitleLocator));

resultTitle.click();


//checks that the result title exists on details page

WebElement bookTitleElement = wait.until(ExpectedConditions.
visibilityOfElementLocated(bookTitleLocator));

assertTrue(bookTitleElement.getText().length() > 0);


//checks that the author value exists on the details page

try {

WebElement bookAuthorElement = wait.until(ExpectedConditions.

visibilityOfElementLocated(bookAuthorLocator));

assertTrue(bookAuthorElement.getText().length() > 0);


}

catch(Exception e) { }

//go back to results page

driver.navigate().back();
}
}
Since everything happens through the browser, the script executes in approximately 100 seconds.
In cases like this, HTML parsing libraries like JSOUP are a better choice than Selenium Web Driver.
Lets see what JSOUP is about.
jsoup is a Java library for working with real-world HTML.
It provides a very convenient API for extracting and manipulating data, using the best of DOM, CSS, and jquery-like methods.
jsoup implements the WHATWG HTML5 specification, and parses HTML to the same DOM as modern browsers do.
§  scrape and parse HTML from a URL, file, or string
§  find and extract data, using DOM traversal or CSS selectors
§  manipulate the HTML elements, attributes, and text
§  clean user-submitted content against a safe white-list, to prevent XSS attacks
§  output tidy HTML
Lets see the same script using JSOUP:
@Test public void test1() throws IOException {

Document resultsPage = Jsoup.connect(“
http://somedomain/url/search?q=java&t=keyword&#8221;).get();

Elements titles = resultsPage.select(“span.title”);


for (Element title : titles) {


Element link = title.child(0);


String detailsPageUrl = “
http://somedomain/url&#8221; + link.attr(“href”);

Document detailsPage = Jsoup.connect(detailsPageUrl).get();


Elements bookTitle = detailsPage.getElementsByAttributeValue(“testid”, “text_bibtitle”);


if (bookTitle.size() > 0)

assertTrue(bookTitle.get(0).text().length() > 0);

Elements bookAuthor = detailsPage.getElementsByAttributeValue(“testid”, “author_search”);


if (bookAuthor.size() > 0)

assertTrue(bookAuthor.get(0).text().length() > 0);
}
}
}
The script is not only shorter but much faster (9 seconds).

PRE-POPULATE COOKIES

Pre-populating site cookies can speed up scripts by avoiding additional site navigation.
Let’s take the following test case:
1.      open the home page of a any website
2.      execute a keyword search
3.      the results page is displayed with 10 results; language is English
1.      go to page 2 of results
2.      change the language to french; the page reloads in french
3.      change the number of results to 25; the page reloads with 25 results
1.      go to page 3 of results
2.      change the language to chinese; the page reloads in chinese
3.      change the number of results to 3; the page reloads with 3 results
For both pages 2 and 3, the script needs to
§  change the language through a listbox; the page reloads when a different language is selected.
§  change the number of results through another listbox; the page reloads with the new number of results
Since the page sets cookies when the results number and language change, it is quite easy to add cookies to the site before loading page 2 and 3.
This way, page 2 will load directly with 25 results and in french.
Page 3 will load directly in chinese with 3 results.
Code Sample:
public void addCookie(String name, String value) {

Cookie pageSize = new Cookie.Builder(name, value)

.domain(“vpl.bibliocommons.com”)
.expiresOn(new Date(2016, 12, 31))                               
.isSecure(true)
.path(“/”)
.build();

driver.manage().addCookie(pageSize);                                

}

@Test
public void testResult() throws InterruptedException { 

driver.get(“
http://somedomain/url/search?q=java&t=keyword&#8221;); 
Thread.sleep(5000);

addCookie(“page_size”, “25”);                                               
addCookie(“language”, “fr-CA”);
        
driver.get(“
http://somedomain/url/search?page=1&q=java&t=keyword&#8221;); 

Thread.sleep(5000);

addCookie(“page_size”, “3”);
addCookie(“language”, “zh-CN”);                                                             

driver.get(“
http://somedomain/url/search?page=2&q=java&t=keyword&#8221;);                                     
Thread.sleep(5000); 
}

DO NOT LOAD ANY IMAGES IN THE WEBPAGE


Many site pages are very rich in images so they do not load fast in the browser.
If the page loads faster in the browser, the script will be faster as well.
The page will load faster if no images are loaded.
This can be accomplished by setting up a new profile for the browser and disable loading images for it.
Then, in the script, use the new profile when starting the browser driver:
1. In chrome type : chrome://version/
 2. Using the console, navigate to the directory “Executable Path” using CD command.
 3. type : chrome.exe –user-data-dir=”your\custom\directory\path” where to create your custom profile.
 4. When chrome opens and ask you for account, click a small link that declines to use an account.
 5. In the opened chrome goto settings>Advanced settings> Privacy > Content Settings > Images > Do Not Show Any Image
 6. If you wish to disable some Chrome Extensions that will be unnecessary for your driver and may impact the driver performance, disable them in : chrome://extensions/
 7. Close chrome and reopen it again from the console with the same command sequence used in 3. Verify that it is not loading the images and that the extensions you disabled (if any) are disabled.
8. Now, in your code, create the capabilities for the driver.
System.setProperty(“webdriver.chrome.driver”, “C:\\Selenium\\BrowserDrivers\\chromedriver.exe”);
ChromeOptions options = new ChromeOptions();
options.addArguments(“user-data-dir=C:\\Selenium\\ChromeProfile”);
options.addArguments(“–start-maximized”);
driver = new ChromeDriver(options);

 


Comments

Popular posts from this blog

15+ Useful Selenium Web driver Code Snippets

BEST AUTOMATION TESTING TOOLS FOR 2018 (TOP 10 REVIEWS)

10 Remarkable Learning Quotes From 10 Astonishing People