Tuesday, September 27, 2016

Selenium Grid

Selenium Grid

Selenium Grid is a tool that distributes the tests across multiple physical or virtual machines so that we can execute script in parallel(simultaneously) that results in cutting down the time required for running tests. This dramatically accelerates testing across browsers and across platforms by giving us quick and accurate feedback.

Selenium Grid allows us to execute multiple instances of WebDriver or Selenium Remote Control tests in parallel which uses same code base, hence code need NOT be present on the system they execute. The selenium-server-standalone package includes Hub, WebDriver, and Selenium RC to execute the scripts in grid.

Selenium Grid has a Hub and a Node

Hub - The hub can also be understood as server which acts as the central point where the tests would be triggered. A Selenium Grid has ONLY one Hub and it is launched on a single machine once.

Node - Nodes are the Selenium instances that are attached to the Hub which will execute the tests. There can be one or more nodes in a grid which can be of any OS and can contain any of the Selenium supported Browsers.

Architecture

Architecture of Selenium Grid is explained with the help of simple flow diagram.

Working with Grid

In order to work with the Grid, we need to ensure that we follow certain protocol. Below are the major steps involved and let us lookg at each one of them in detail.

Configuring Hub

Configuring Nodes

Develop Script

XML Preperation

Test Execution

Result Analysis

Configuring Hub

Step 1 : Download the latest Selenium Server standalone JAR file from http://docs.seleniumhq.org/download/. Download it by clicking on the version as shown below.

Step 2 : Start the Hub by Launching the Selenium Server using the following command. Now we will use the port '4444' to start the hub.

NOTE : Ensure that there are no other applications that are running on port# 4444.

java -jar selenium-server-standalone-2.25.0.jar -port 4444 -role hub -nodeTimeout 1000

Step 3 : Now open the browser and navigate to the URL http//localhost:4444 from Hub(The system where you have executed Step#2).

Step 4 : Now click on 'console' link and click 'view config'. The config of hub would be shown. As of now we haven't got any nodes, hence we will not be able to see the details.

Configuring Nodes

Step 1 : Logon to node(where you would like to execute the scripts) and place the 'selenium-server-standalone-2.42.2' in a folder. We need to point to the selenium-server-standalone JAR when launching the nodes.

Step 2 : Launch FireFox Node using the below command.

java -jar D:\JAR\selenium-server-standalone-2.42.2.jar -role node -hub http://10.30.217.157:4444/grid/register -browser browserName=firefox -port 5555 Where, D:\JAR\selenium-server-standalone-2.42.2.jar = Location of the Selenium Server Standalone Jar File(on the Node Machine) http://10.30.217.157:4444 = IP Address of the Hub and 4444 is the port of the Hub browserName = firefox (Parameter to specify the Browser name on Nodes) 5555 = Port on which Firefox Node would be up and running.

Step 3 : After executing the command, Now come back to Hub. Navigate to the URL - http://10.30.217.157:4444 and the Hub would now display the the node attached to it.

Step 4 : Now let us Launch Internet Explorer Node. For Launching the IE Node, we need to ensure that we have Internet Explorer driver downloaded on the node machine.

Step 5 : To Download the Internet Explorer Driver, navigate to http://docs.seleniumhq.org/download/ and download based on the architecture of your OS. After you have downloaded, unzip the exe file and place it a folder which has to be referred while launching IE nodes.

Step 6 : Launch IE using the below command.

C:\>java -Dwebdriver.ie.driver=D:\IEDriverServer.exe -jar D:\JAR\selenium-server-standalone-2.42.2.jar -role webdriver -hub http://10.30.217.157:4444/grid/register -browser browserName=ie,platform=WINDOWS -port 5558 Where, D:\IEDriverServer.exe = The location of the downloaded the IE Driver(on the Node Machine) D:\JAR\selenium-server-standalone-2.42.2.jar = Location of the Selenium Server Standalone Jar File(on the Node Machine) http://10.30.217.157:4444 = IP Address of the Hub and 4444 is the port of the Hub browserName = ie (Parameter to specify the Browser name on Nodes) 5558 = Port on which IE Node would be up and running.

Step 7 : After executing the command, Now come back to Hub. Navigate to the URL - http://10.30.217.157:4444 and the Hub would now display the IE node attached to it.

Step 8 : Now let us Launch Chrome Node. For Launching the Chrome Node, we need to ensure that we have Chrome driver downloaded on the node machine.

Step 9 : To Download the Chrome Driver, navigate to http://docs.seleniumhq.org/download/ and navigate to Third Party Browser Drivers area and click on the version number '2.10' as shown below.

Step 10 : Download the Driver based on the type of OS. We will execute it on Windows Environment, hence we will download the Windows Chrome Driver. After you have downloaded, unzip the exe file and place it a folder which has to be referred while launching chrome nodes.

Step 11 : Launch chrome using the below command.

C:\>java -Dwebdriver.chrome.driver=D:\chromedriver.exe -jar D:\JAR\selenium-server-standalone-2.42.2.jar -role webdriver -hub http://10.30.217.157:4444/grid/register -browser browserName=chrome,platform=WINDOWS -port 5557 Where, D:\chromedriver.exe = The location of the downloaded the chrome Driver(on the Node Machine) D:\JAR\selenium-server-standalone-2.42.2.jar = Location of the Selenium Server Standalone Jar File(on the Node Machine) http://10.30.217.157:4444 = IP Address of the Hub and 4444 is the port of the Hub browserName = chrome (Parameter to specify the Browser name on Nodes) 5557 = Port on which chrome Node would be up and running.

Step 7 : After executing the command, Now come back to Hub. Navigate to the URL - http://10.30.217.157:4444 and the Hub would now display the chrome node attached to it.

Develop Script

Step 1 : We will develop a test using TestNG. In the below example we will have launch each one of those browsers using remote webdriver can pass on their capabilities to the driver so that driver has all information to execute on Nodes.

The Browser Parameter would be passed from "XML" File.

package TestNG; import org.openqa.selenium.remote.DesiredCapabilities; import java.util.concurrent.TimeUnit; import org.openqa.selenium.*; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import java.net.URL; import java.net.MalformedURLException; import org.openqa.selenium.remote.RemoteWebDriver; public class TestNGClass { public WebDriver driver; public String URL, Node; protected ThreadLocal<RemoteWebDriver> threadDriver = null; @Parameters("browser") @BeforeTest public void launchapp(String browser) throws MalformedURLException { String URL = "http://www.calculator.net"; if (browser.equalsIgnoreCase("firefox")) { System.out.println(" Executing on FireFox"); String Node = "http://10.112.66.52:5555/wd/hub"; DesiredCapabilities cap = DesiredCapabilities.firefox(); cap.setBrowserName("firefox"); driver = new RemoteWebDriver(new URL(Node), cap); //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(URL); driver.manage().window().maximize(); } else if (browser.equalsIgnoreCase("chrome")) { System.out.println(" Executing on CHROME"); DesiredCapabilities cap = DesiredCapabilities.chrome(); cap.setBrowserName("chrome"); String Node = "http://10.112.66.52:5557/wd/hub"; driver = new RemoteWebDriver(new URL(Node), cap); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(URL); driver.manage().window().maximize(); } else if (browser.equalsIgnoreCase("ie")) { System.out.println(" Executing on IE"); DesiredCapabilities cap = DesiredCapabilities.chrome(); cap.setBrowserName("ie"); String Node = "http://10.112.66.52:5558/wd/hub"; driver = new RemoteWebDriver(new URL(Node), cap); driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(URL); driver.manage().window().maximize(); } else { throw new IllegalArgumentException("The Browser Type is Undefined"); } } @Test public void calculatepercent() { driver.findElement(By.xpath(".//*[@id='menu']/div[3]/a")).click(); // Click on Math Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[4]/div[3]/a")).click(); // Click on Percent Calculators driver.findElement(By.id("cpar1")).sendKeys("10"); // Enter value 10 in the first number of the percent Calculator driver.findElement(By.id("cpar2")).sendKeys("50"); // Enter value 50 in the second number of the percent Calculator driver.findElement(By.xpath(".//*[@id='content']/table/tbody/tr/td[2]/input")).click(); // Click Calculate Button String result = driver.findElement(By.xpath(".//*[@id='content']/p[2]/span/font/b")).getText(); // Get the Result Text based on its xpath System.out.println(" The Result is " + result); //Print a Log In message to the screen if(result.equals("5")) { System.out.println(" The Result is Pass"); } else { System.out.println(" The Result is Fail"); } } @AfterTest public void closeBrowser() { driver.quit(); } }

Step 2 : The Browser parameter will be passed using an XML. Create an XML we need to create the same under project folder.

Step 3 : Select 'File' from 'General' and click 'Next'.

Step 4 : Enter the name of the file and click 'Finish'.

Step 5 : TestNg.XML is created under the project folder as shown below.

Step 6 : Contents of XML are shown below. We create 3 tests and put in a suite and mention parallel="tests" so that all tests would be executed parallelly.

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Suite" parallel="tests"> <test name="FirefoxTest"> <parameter name="browser" value="firefox" /> <classes> <class name="TestNG.TestNGClass" /> </classes> </test> <test name="ChromeTest"> <parameter name="browser" value="chrome" /> <classes> <class name="TestNG.TestNGClass" /> </classes> </test> <test name="IETest"> <parameter name="browser" value="ie" /> <classes> <class name="TestNG.TestNGClass" /> </classes> </test> </suite>

Test Execution

Step 1 : Select the created XML and perform a right click and choose 'Run As' >> 'TestNG Suite'.

Step 2 : Now open the Node, where we have launched all the browser nodes. We will be able to see all three browsers in execution simultaneously.

Result Analysis

Step 1 : Upon completing the execution, we will be able to analyze the result like any other execution. The result summary is printed on Console. Below is the snapshot of the same.

Step 2 : Navigate to 'Results of Running Suite' Tab and TestNG would display the result summary as shown below.

Step 3 : Upon Generating the HTML, we will be able to see the test results in HTML format.

Selenium TestNG

Selenium TestNG

What is TestNG

TestNG is a powerful testing framework, an enhanced version of Junit which was in use for long years before TestNG came into existance. NG stands for 'Next Generation'.

TestNG framework provides the following features and answers to our question "Why we need TestNG"?

Annotations helps us to organize the tests easier.

Flexible test configuration.

Test cases can be grouped more easily

Parallelization of test can be achieved using TestNG

Support for data-driven testing

Inbuilt Reporting

Installing TestNG for Eclipse

Step 1 : Launch Eclipse and select 'Install New Software'.

Step 2 : Enter the URL as 'http://beust.com/eclipse' and click 'Add'.

Step 3 : Add Repository dialog opens. Enter the name as 'TestNG' and click 'OK'

Step 4 : Click 'Select All' and 'TestNG' would be selected would be selected as shown in the figure.

Step 5 : Click 'Next' to continue.

Step 6 : Review the items that are selected and click 'Next'.

Step 7 : "Accept the License Agreement" and click 'Finish'.

Step 8 : TestNG starts installing and the progress would be shown as below..

Step 9 : Security Warning pops up as the validity of the software cannot be established. click 'Ok'.

Step 10 : The Installer pops up for the restart. click 'Yes'.

Annotations in TestNG

Annotations were formally added to the Java language in JDK 5 and TestNG made the choice to use annotations to annotate test classes. Following are some of the benefits of using annotations. More about TestNG can be foundhere

TestNG identifies the methods it is interested in by looking up annotations. Hence, method names are not restricted to any pattern or format.

We can pass additional parameters to annotations.

Annotations are strongly typed, so the compiler will flag any mistakes right away.

Test classes no longer need to extend anything (such as TestCase, for JUnit 3).

AnnotationDescription@BeforeSuiteThe annotated method will be run only once before all tests in this suite have run.@AfterSuiteThe annotated method will be run only once after all tests in this suite have run.@BeforeClassThe annotated method will be run only once before the first test method in the current class is invoked.@AfterClassThe annotated method will be run only once after all the test methods in the current class have been run.@BeforeTestThe annotated method will be run before any test method belonging to the classes inside the <test> tag is run.@AfterTestThe annotated method will be run after all the test methods belonging to the classes inside the <test> tag have run.@BeforeGroupsThe list of groups that this configuration method will run before. This method is guaranteed to run shortly before the first test method that belongs to any of these groups is invoked.@AfterGroupsThe list of groups that this configuration method will run after. This method is guaranteed to run shortly after the last test method that belongs to any of these groups is invoked.@BeforeMethodThe annotated method will be run before each test method.@AfterMethodThe annotated method will be run after each test method.@DataProviderMarks a method as supplying data for a test method. The annotated method must return an Object[ ][ ] where each Object[ ] can be assigned the parameter list of the test method. The @Test method that wants to receive data from this DataProvider needs to use a dataProvider name equals to the name of this annotation.@FactoryMarks a method as a factory that returns objects that will be used by TestNG as Test classes. The method must return Object[ ].@ListenersDefines listeners on a test class.@ParametersDescribes how to pass parameters to a @Test method.@TestMarks a class or a method as part of the test.

TestNG-Eclipse Setup

Step 1 : Launch Eclipse and create a 'New Java Project' as shown below.

Step 2 : Enter the project name and click 'Next'.

Step 3 : Navigate to "Libraries" Tab and Add the Selenium Remote Control Server JAR file by clicking on "Add External JAR's" as shown.

Step 4 : The Added JAR file is shown as below and click 'Add Library'.

Step 5 : The 'Add Library' dialog opens. Select 'TestNG' and click 'Next' in 'Add Library' Dialog.

Step 6 : The added 'TestNG' Library is added and it is displayed as shown below.

Step 7 : Upon creating the project the structure of the project would be as shown below.

Step 8 : Right click on 'id' folder and select 'New' and 'other'.

Step 9 : Select 'TestNG' and click 'Next'.

Step 10 : Select 'Source Folder' Name and click 'Ok'.

Step 11 : Select 'Package name', class name and click 'Finish'.

Step 12 : The Package explorer and the created class would be displayd to the user.

First Test in TestNG

Now let us start scripting using TestNG. Let us script for the same example that we used in understanding the Webdriver. We will make use of the demo application, www.calculator.net and perform percent calculator.

In the below test, you will notice that there is NO main method, as testNG will drive the program execution flow. After Initializing the driver, it will execute '@BeforeTest' method followed by '@Test' and then '@AfterTest'. Please note that there can be any number of '@Test' annotation in a class but '@BeforeTest' and '@AfterTest' can appear only Once.

package TestNG; import java.util.concurrent.TimeUnit; import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class TestNGClass { WebDriver driver = new FirefoxDriver(); @BeforeTest public void launchapp() { //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to("http://www.calculator.net"); driver.manage().window().maximize(); } @Test public void calculatepercent() { // Click on Math Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[3]/a")).click(); // Click on Percent Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[4]/div[3]/a")).click(); // Enter value 10 in the first number of the percent Calculator driver.findElement(By.id("cpar1")).sendKeys("10"); // Enter value 50 in the second number of the percent Calculator driver.findElement(By.id("cpar2")).sendKeys("50"); // Click Calculate Button driver.findElement(By.xpath(".//*[@id='content']/table/tbody/tr/td[2]/input")).click(); // Get the Result Text based on its xpath String result = driver.findElement(By.xpath(".//*[@id='content']/p[2]/span/font/b")).getText(); //Print a Log In message to the screen System.out.println(" The Result is " + result); if(result.equals("5")) { System.out.println(" The Result is Pass"); } else { System.out.println(" The Result is Fail"); } } @AfterTest public void terminatetest() { driver.close(); } }

Execution

The Test execution is performed by performing a Right Click on the created XML and selecting "Run As" >> "TestNG Suite"

Result Analysis

The Output is thrown to the console and it would appear as shown below. The Console output also has the execution summary.

The result of TestNG can also be seen in a different tab. Click on 'HTML Report View' button as shown below.

The HTML result would be displayed as shown below.

Capture Screenshots

Capture Screenshots

Screenshot capture functionality helps us to grab the screenshot at run time when required, inparticularly when a failure happens. With the help of screenshots and log messages we will be able to analyse the results better

Screenshots are configured differently for local executions and Selenium Grid(remote) Executions. Let us take a look at each one them with an example

Localhost Execution

In the below example, we will take a screenshot after calculating the percentage. Ensure that you give a valid path to save the screenshot.

import java.io.File; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.apache.commons.io.FileUtils; import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver; public class webdriverdemo { public static void main(String[] args) throws IOException { WebDriver driver = new FirefoxDriver(); //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to("http://www.calculator.net/"); //Maximize the browser driver.manage().window().maximize(); // Click on Math Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[3]/a")).click(); // Click on Percent Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[4]/div[3]/a")).click(); // Enter value 10 in the first number of the percent Calculator driver.findElement(By.id("cpar1")).sendKeys("10"); // Enter value 50 in the second number of the percent Calculator driver.findElement(By.id("cpar2")).sendKeys("50"); // Click Calculate Button driver.findElement(By.xpath(".//*[@id='content']/table/tbody/tr/td[2]/input")).click(); // Get the Result Text based on its xpath String result = driver.findElement(By.xpath(".//*[@id='content']/p[2]/span/font/b")).getText(); File screenshot = ((TakesScreenshot)driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(screenshot, new File("D:\\screenshots\\screenshots1.jpg")); //Print a Log In message to the screen System.out.println(" The Result is " + result); //Close the Browser. driver.close(); } }

Output

Upon Executing the script, the screenshot is saved in the 'D:\screenshots' folder with the name 'screenshots1.jpg' as shown below.

Selenium Grid - Screenshot Capture

When working with Selenium Grids, we should ensure that we are taking the screenshot correctly from the remote system. We will make use of augmented driver.

Example

We will execute the script on a firefox node attached to a hub. More on configuring hub and nodes, please refer to Selenium Grids Chapter.

package TestNG; import org.openqa.selenium.remote.Augmenter; import org.openqa.selenium.remote.DesiredCapabilities; import org.openqa.selenium.TakesScreenshot; import java.util.concurrent.TimeUnit; import org.openqa.selenium.*; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.Parameters; import org.testng.annotations.Test; import java.io.File; import java.net.URL; import java.net.MalformedURLException; import org.apache.commons.io.FileUtils; import org.openqa.selenium.remote.RemoteWebDriver; import java.io.IOException; public class TestNGClass { public WebDriver driver; public String URL, Node; protected ThreadLocal<RemoteWebDriver> threadDriver = null; @Parameters("browser") @BeforeTest public void launchapp(String browser) throws MalformedURLException { String URL = "http://www.calculator.net"; if (browser.equalsIgnoreCase("firefox")) { System.out.println(" Executing on FireFox"); String Node = "http://10.112.66.52:5555/wd/hub"; DesiredCapabilities cap = DesiredCapabilities.firefox(); cap.setBrowserName("firefox"); driver = new RemoteWebDriver(new URL(Node), cap); //Puts a Implicit wait, Will wait for 10 seconds before throwing exception driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); //Launch website driver.navigate().to(URL); driver.manage().window().maximize(); } else { throw new IllegalArgumentException("The Browser Type is Undefined"); } } @Test public void calculatepercent() throws IOException { driver.findElement(By.xpath(".//*[@id='menu']/div[3]/a")).click(); // Click on Math Calculators driver.findElement(By.xpath(".//*[@id='menu']/div[4]/div[3]/a")).click(); // Click on Percent Calculators // Make use of augmented Driver to capture Screenshots. WebDriver augmentedDriver = new Augmenter().augment(driver); File screenshot = ((TakesScreenshot)augmentedDriver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(screenshot, new File("D:\\screenshots\\remotescreenshot1.jpg")); // Please note - Screenshot would be saved on the system where the script is executed and NOT on remote machine. driver.findElement(By.id("cpar1")).sendKeys("10"); // Enter value 10 in the first number of the percent Calculator driver.findElement(By.id("cpar2")).sendKeys("50"); // Enter value 50 in the second number of the percent Calculator driver.findElement(By.xpath(".//*[@id='content']/table/tbody/tr/td[2]/input")).click(); // Click Calculate Button String result = driver.findElement(By.xpath(".//*[@id='content']/p[2]/span/font/b")).getText(); // Get the Result Text based on its xpath System.out.println(" The Result is " + result); //Print a Log In message to the screen if(result.equals("5")) { System.out.println(" The Result is Pass"); } else { System.out.println(" The Result is Fail"); } } @AfterTest public void closeBrowser() { driver.quit(); } }

Output

Upon executing the script, the screenshot is captured and saved in the specified location as shown below.