Wednesday, May 7, 2014

When to Automate Software - Part 1

Problem

There are times in the application development when new feature and/or functionality keep adding into the existing software and there are functionality that are unchanged but have its own value in the application, sometimes such functionality becomes a bit boring for the testers to test over and over again after each feature functionality integration and that increases the chances of defect slippage, testers started to make assumptions and based on those assumption she might skip some key tests in that functionality that results in defect in later stages.

Solution

The solution for the above problems in which similar tests need to be executed again and again it is better we should automate those tests that are repeatable. Each time the test is going to be executed its value increases and confidence of each run will remain unshakable as it was in the first run.

See the following example, in which the form Reset functionality needs to be tested over and over again since it is one of the basic feature the EfroTech site provides.

Scenario
  • Launch application
  • Click on Jobs
  • Fill up the form
  • Click Reset button

Expected: All fields on the form are reset to default except Salary fields.

Test Case Class

 package com;  

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

 public class EfroTechCareers {  
      private WebDriver driver;  
      public EfroTechCareers(WebDriver driver)  
      {  
           this.driver = driver;  
           if(!"Jobs and Career at Efrotech | Efrotech Services".equals(driver.getTitle()))  
           {  
                throw new IllegalStateException("This is not the Careers Page");  
           }  
      }  
      By applyingFor = By.id("ddlJobs");  
      By candidateName = By.id("txtName");  
      By candidateFatherName = By.id("txtFName");  
      By candidateGender = By.id("ddlGender");  
      By candidateAddress = By.id("txtAddress");  
      By candidateCity = By.id("ddlResumeCity");  
      By candidateEmail = By.id("txtEmail");  
      By candidateHomePhone = By.id("txtPhoneHome");  
      By candidateOfficePhone = By.id("txtPhoneOff");  
      By candidateCellPhone = By.id("txtPhoneMob");  
      By candidateCNIC = By.id("txtCNIC");  
      By candidateExperience = By.id("ddlExperience");  
      By candidateCurrentSalary = By.id("txtCurrentSalary");  
      By candidateExpectedSalary = By.id("txtExpectedSalary");  
      By btnFormReset = By.id("btnReset");  
      public void formFillCareers()   
      {  
           driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[height='520']")));  
           new Select(driver.findElement(applyingFor)).selectByVisibleText("QA Engineer");  
           driver.findElement(candidateName).sendKeys("Candidate Name");  
           driver.findElement(candidateFatherName).sendKeys("Cand. Father's Name");  
           new Select(driver.findElement(candidateGender)).selectByVisibleText("Male");  
           driver.findElement(candidateAddress).sendKeys("XYZ Lane 123 Road");  
           new Select(driver.findElement(candidateCity)).selectByVisibleText("Karachi");  
           driver.findElement(candidateEmail).sendKeys("name@domainname.com");  
           driver.findElement(candidateHomePhone).sendKeys("12345678");  
           driver.findElement(candidateOfficePhone).sendKeys("87654321");  
           driver.findElement(candidateCellPhone).sendKeys("03331234567");  
           driver.findElement(candidateCNIC).sendKeys("12345-6789458-9");  
           new Select(driver.findElement(candidateExperience)).selectByVisibleText("5 Years");  
           driver.findElement(candidateCurrentSalary).sendKeys("123456");  
           driver.findElement(candidateExpectedSalary).sendKeys("654123");  
           driver.findElement(btnFormReset).click();  
      }  
      public boolean verifyFormReset()  
      {  
           if (  
                     ("-Select-".equals(new Select(driver.findElement(applyingFor)).getFirstSelectedOption().getText()) &&    
                     "".equals(driver.findElement(candidateName).getText()) &&  
                     "".equals(driver.findElement(candidateFatherName).getText()) &&   
                     "-Select-".equals(new Select(driver.findElement(candidateGender)).getFirstSelectedOption().getText()) &&   
                     "".equals(driver.findElement(candidateAddress).getText()) &&  
                     "-Select-".equals(new Select(driver.findElement(candidateCity)).getFirstSelectedOption().getText()) &&   
                     "".equals(driver.findElement(candidateEmail).getText()) &&   
                     "".equals(driver.findElement(candidateHomePhone).getText()) &&   
                     "".equals(driver.findElement(candidateOfficePhone).getText()) &&   
                     "".equals(driver.findElement(candidateCellPhone).getText()) &&  
                     "".equals(driver.findElement(candidateCNIC).getText()) &&  
                     "-Select-".equals(new Select(driver.findElement(candidateExperience)).getFirstSelectedOption().getText()) &&  
                     "012345".equals(driver.findElement(candidateCurrentSalary).getAttribute("value")) &&  
                     "065412".equals(driver.findElement(candidateExpectedSalary).getAttribute("value"))   
                     )  
            )  
                          return true;  
                                         else   
                                              return false;  
      }  

 } 


 

Main Class Calling the Test Case Class

 package com;  

 import java.util.concurrent.TimeUnit;  
 import org.openqa.selenium.WebDriver;  
 import org.openqa.selenium.firefox.FirefoxDriver;  
 import org.openqa.selenium.support.PageFactory;  

 public class EfroTechMain {  
      /**  
       * @param args  
       *   
       */  
      public static WebDriver driver;  
      public static String baseUrl;  
      public static void main(String[] args) {  
           // TODO Auto-generated method stub  
           baseUrl = "http://www.efrotech.com";  
           driver = new FirefoxDriver();  
           driver.manage().window().maximize();  
           driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);  
           driver.get(baseUrl +"/careers");  
           EfroTechCareers eTC = PageFactory.initElements(driver,                            EfroTechCareers.class);  
           eTC.formFillCareers();  
           if (eTC.verifyFormReset() == true)  
           {  
                System.out.println("All fields are reset to defaults");  
           } else  
                System.out.println("Some fields are not reset to defaults");  
      }  

 }


The above scenario of the scripted/automated tests can be used to solve the problem we started with discussion in this post. The test can be repeated as many time as the need arises. Its value keep increases and cost decreases as many time we execute the tests.

What approach you take while automating the test. Do share here if it is worth sharing.

Monday, April 28, 2014

Control Identification Problem Due to IFrame in Selenium WebDriver

Problem

I have been learning Selenium with my own interest by finding the helpful resources online. This time I picked one of the website that has a form, submit button and a reset button for automation script and testing the Reset form functionality on the page. After completing the first step of the scripting and getting the locators on the page (http://www.efrotech.com/careers), everything seems fine from the HTML that looks pretty neat because every control can be uniquely identified with ID locators. When I run the run the script (for understanding just writing couple of lines) Selenium WebDriver throws the dirty exception of NoSuchElementPresent.

                new Select(driver.findElement(By.id("ddlJobs"))).selectByVisibleText("QA Engineer");
                driver.findElement(By.id("txtName")).sendKeys("Muzaffar");

After trying this simple locator and one by one all the locators like CSS, XPath the same exception is thrown after each run.

Solution:

After posting the problem to the internet one of the guy Nitin Chawda from Kony Labs Hyderabad pointed the issue that the controls lie within the IFrame so the IFrame control must be identified first before the manipulation of the controls on the page and within IFrame. So the script would like this

             driver.switchTo().frame(driver.findElement(By.cssSelector("iframe[height='520']")));
new Select(driver.findElement(By.id("ddlJobs"))).selectByVisibleText("QA Engineer");
driver.findElement(By.cssSelector("input#txtName")).sendKeys("Muzaffar");

To see complete code snippet please click here (not now but in next few days :) ).

Friday, April 18, 2014

Finding and hunting bugs - Storefront Inc.

I was asked to navigate to the URL "http://storefront-staging.herokuapp.com/qa_testerss" and was asked to report the the bugs/error on the page. I manage to find few, can you share yours hunts from the above URL? do write in comments.

Storefron Inc. custom error page.

Thursday, April 17, 2014

[Selenium Webdriver] Connection to oracle database using Java

There are time during the functional automation when you the test engineer have to connect to the database in order to verify the data driven functionality. For that purpose, it is necessary to connect to the database during test execution to verify the functionality that is dependent on the data coming from the database.

Following is the class that is written in Java to connect to the database that: 

1. creates the connection to the database
2. execute the query on the database
3. close the database connection when the query is executed.

Pre-requisite:

Download oracle ojdbc14.jar or ojdbc6.jar from the internet and configure it to java-build path in your favorite IDE.

Database connection class

package com;

import java.io.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;



public class OrclConn {

private Connection connection;
private String serverName;
private String portNumber;
private String sid;
private String url;
private String username;
private String password;
private Statement stmt;
public ResultSet rset;
 
 /* 
This constructor initializes the database variables that requires to connect to the database
   */
public OrclConn(String serName, String portNum,
String osid, String dbUrl, String dbUserName, String dbPassword ) throws IOException
{
connection = null;
serverName = serName; // pass server name of IP from the calling classs
   portNumber = portNum; // pass port number from the calling classs
   sid = osid; // pass oracle service name from the calling classs
   url = dbUrl + serverName + ":" + portNumber + ":" + sid; // "jdbc:oracle:thin:@" + serverName + ":" + portNumber + ":" + sid;
   username = dbUserName; // pass oracle database name from the calling classs
   password = dbPassword; // pass oracle database password (plaintext) from the calling classs
       
}

public void OpenDBConnection()
{
   try 
{

   // Load the JDBC driver
   String driverName = "oracle.jdbc.driver.OracleDriver";
   Class.forName(driverName);

   // Create a connection to the database
   connection = DriverManager.getConnection(url, username, password);
   }
   
   catch (ClassNotFoundException e) 
{
System.out.println("Class not found from database" );
e.printStackTrace();

catch (SQLException e1) 
{
System.out.println("ORACLE Connection error " );
e1.printStackTrace();
}
       
   
}

 /* This Function execute the query on the connected database and return the ResultSet collection 
Upon callling from the test case class where actual verification is being done on UI and Database.
   */
   public ResultSet RunQuery(String Query) throws IOException
   {
   
    try{
   stmt = connection.createStatement();
   rset = stmt.executeQuery(Query);
   
   }
    catch(SQLException e1)
    {
    System.out.println("Query Execution Error" );
e1.printStackTrace();
    }
   
    return rset;
   }
       
       
       
 /* This Function closes the database connection from the Oracle Database Connection
Upon callling from the test case class where actual verification is being done.
   */
   public void OracleCloseConnection() throws IOException
   {
    try{
   connection.close();
    }
   
    catch(SQLException e1)
    {
    System.out.println("Query Execution Error" );
e1.printStackTrace();
   
    }
   

   
}

How do you connect to the database from the Java?

Wednesday, April 16, 2014

Automating real time test cases using Selenium Webdriver - 1

Test Scenario: To check whether Agent Names are filtered alphabetically

Test Steps:

 Navigate to http://propertyguru.com.sg
 Click on Find Agent on Main Menu Bar
 Click on Alphabet C.
 Verify if the results >10 e.g. (130 Agents Found), then Check that the first 10 agent names (results) start with Alphabet “C”.
 Else print “Results are not sorted Alphabetically”.

Test Case Code Snippet

package com;

import java.util.concurrent.TimeUnit;

import org.junit.Before;
import org.junit.After;
import org.junit.Test;

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;



public class ChromeDriverTest {
private WebDriver driver;
private String baseUrl;
private String strTextToVerify;


@Before
public void setUp() throws Exception{

driver = new FirefoxDriver();
baseUrl = "http://www.propertyguru.com.sg";
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
System.out.println("SetUp executed succesfully");
}

@Test
public void testPropertyGuru() throws Exception{
driver.get(baseUrl + "/");
driver.findElement(By.linkText("Find Agent")).click();
driver.findElement(By.id("name_2")).click();

if (Integer.valueOf(driver.findElement(By.cssSelector("font.redtext")).getText()).intValue() > 10){
System.out.println(Integer.valueOf(driver.findElement(By.cssSelector("font.redtext")).getText()).intValue());

for (int i =3; i <22 i="" span="">

strTextToVerify = driver.findElement(By.xpath(".//*[@id='homeleft']/div["+i+"]/div[2]/div[1]/div[1]/a")).getText();
System.out.println("Agent name " +strTextToVerify+ " starts with " +"'"+strTextToVerify.charAt(0)+"'");
i = i+1;

}


} else {

System.out.println("testPropertyGuru() executed succesfully");

}
System.out.println("testPropertyGuru() executed succesfully");

}

@After
public void tearDown() throws Exception{
driver.quit();
System.out.println("tearDown() executed succesfully");

}

}

Challenge!

Do you have better and faster way to this?

Sample coding logics using using Java

Problem

Write a Java program that prints the numbers from 1 to 50. But for multiples of three print "Property" instead of the number and for the multiples of five prints "Guru". For numbers which are multiples of both three and five print "PropertyGuru"

Code Snippet

package com;

public class PrintString{
public static void main(String[] args){


for(int i=1;i <=50;i++){
if (i%3==0)
if (i%5==0)
System.out.println("PropertyGuru");

if (i%3==0)
System.out.println("Property");
else if (i%5==0)
System.out.println("Guru");
else 
System.out.println(i);
}
}



}


Challenge!

Do you have better and faster way to solve the problem?

Automating real time test cases using Selenium Webdriver - 2

Test Scenario: To verify if the search results are within the specified price range.

Test Steps:

 Navigate to http://m.propertyguru.com.my/ 
 Select Min Price to 8000000 
 Select Max Price to 10000000
 Click on Search button
 Verify if the results are within the specified price range.

Note: Results Highlighted in yellow tagged with a star image should not be included on the verification. They are usually found on the first 3 rows and categorized as featured ads. Those are not part of the search results that you need to verify/assert.

Test Case Code Snippet:


package com;

import java.util.concurrent.TimeUnit;


import org.junit.Before;

import org.junit.After;
import org.junit.Test;

/*import org.openqa.selenium.chrome.ChromeDriver;

import org.openqa.selenium.chrome.ChromeOptions;*/

import org.openqa.selenium.firefox.FirefoxDriver;

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

public class VerifyRangeValues{

private WebDriver driver;
private String baseUrl;
// private int numToVerify;

public static String stripNonDigits(
            final CharSequence input /* inspired by seh's comment */){
    final StringBuilder sb = new StringBuilder(
            input.length() /* also inspired by seh's comment */);
    for(int i = 0; i < input.length(); i++){
        final char c = input.charAt(i);
         if(c > 47 && c < 58){ // Checking the ASCII between 48 to 57 for 0 to 9
         sb.append(c);
        }
    }
    return sb.toString();
}

public void compareNumWithRange(String strNum){
final String result = stripNonDigits(strNum);
final int a = (Integer.valueOf(result)).intValue();
System.out.println("Value extracted from string " + a);
if (a >= 8000000 && a <= 10000000){
System.out.println(a + "  is within the range 8000000 to 10000000 specified");
}
 else {
 System.out.println(a + "  is NOT withing the range 8000000 to 10000000 specified");
   
}

}


@Before
public void setUp() throws Exception{

//Uncomment the folling block and commented imports to run the code in Chrome Driver.

/*System.setProperty("webdriver.chrome.driver","E:\\D-Drive-Data\\Softwares\\Selenium Support Files\\chromedriver_win32\\chromedriver.exe");
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
driver = new ChromeDriver(options);*/

driver = new FirefoxDriver();
baseUrl = "http://m.propertyguru.com.my";
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
System.out.println("SetUp executed succesfully");

}

@Test
public void testValueRange() throws Exception{
driver.get(baseUrl +"/");


Select minPriceDropdown = new Select(driver.findElement(By.id("minprice-sale")));
minPriceDropdown.selectByVisibleText("RM 800,000");

Select maxPriceDropdown = new Select(driver.findElement(By.id("maxprice-sale")));
maxPriceDropdown.selectByVisibleText("RM 1,000,000");

//driver.findElement(By.id("maxprice-sale")).sendKeys("RM 1,000,000");
//driver.findElement(By.xpath(".//*[@id='maxprice-sale']/option[1000000]"));
driver.findElement(By.id("btnSearch")).submit();

/*compareNumWithRange(
driver.findElement(By.xpath(".//*[@id='listing[0-9]{7}']/table/tbody/tr/td/div[2]/p[1]/strong/span")).getText()); */
for(int i = 4; i <11 font="" i="">
System.out.println(driver.findElement(By.cssSelector("#listings li:nth-child("+i+") strong > span")).getText());
//driver.wait(15000);

compareNumWithRange(
driver.findElement(By.cssSelector("#listings li:nth-child("+i+") strong > span")).getText());


System.out.println(i+ " testValueRange() executed succesfully");
}
}

@After
public void tearDown() throws Exception {
System.out.println("tearDown() executed succesfully");
driver.quit();
System.out.println("Webdriver Quit Successfully.");


}



}


Challenge!

Do you have a better and faster way to do this?

Thursday, February 27, 2014

Identifying and working with element that changes dynamically

There several mechanism supported by Selenium to identify the element/object on the browser and to perform some actions. There are times when identifying an element and working with it is a lot difficult. I am sharing one of the problem I faced during identifying an element that is dynamically change after each page load (each new request).

Problem

Web page loads unordered listing element with children listings that have dynamic IDs on each requests/page loads. If you identify an element and try work with selenium scripts the next time scripts run the ID would change and you'll receive dirty exception of NoSuchElementFound blah blah.

Summary outer HTML

This the HTML of the application I was trying to work with.

  •  
  • ......

    Note:
    ID and other selenium selector are not that help since every attribute is same the attributes that are different are dynamic.Therefore, you can not uniquely identify an element and work confidently with. 

    Inner HTML of the First Listing Element.

    This is the detailed HTML of the first listing element as shown above.

  • "listingItem">
  • g="0" cellpadding="0">
             PKR 850,000                       

    The value that need to be pick was PKR 850,000 (which is also changing but its position does not change)

    Solution

    Firepath CSS selector does the trick and help you evaluate your expression, by itself firepath/firebug can give the exact output as below.

    #listings li:first-child strong > span 
    #listings li:nth-child(2) strong > span 
    ...
    List goes on and on

    If the same action needs to be performed on each element this can be iterate by adding the loop as 

    for(int i = 4; i <11 div="" i="">
    System.out.println(driver.findElement(By.cssSelector("#listings li:nth-child("+i+") strong > span")).getText());
    }

    Configuring Selenium with Eclipse on Windows

    Automation is not just about recording and playback the scripts. Its actual value comes far more after you write robust reusable, repeatable and maintainable scripts. To do that you have to have the tool that support designing scripts for such purpose. Many automation tools come with scripts editor to write dynamic code that is repeatable and reusable.

    Since selenium is an opensource browser automation tool that is easily integrated in the FireFox browser to recording the application common scenarios and playing it back for verification. If you want to go further in test automation you will need a bit of liberty where you can design and develop dynamic scripts that can not be done easily with Selenium IDE.

    Required downloads


    Configuration


    • Run Eclipse (after download, unzip the folder no special installation).
    • Set you desired directory as Eclipse workspace (this where you want to save all your projects).
    • Click on File -> New -> Java Project or JPA Project.
    • Name your project, say 'Test' and click Finish
    • Right-Click on the newly created project and then click - > New -> Package
    • Name the package, say 'com' and click Finish.
    • Again right-click on the project name 'Test' and then Properties - > Java Build Path
    • Select the Library tab, if not already selected.
    • Click Add External JARs button
    • Access the path, where you downloaded it, of Selenium Java Client driver.
    • Select Zip/JARs and click Open button, all JARs would be added.
    • Click again Add External JARs button
    • Access the path, where you downloaded it, of Selenium Server Standalone.
    • Select Zip/JARs and click Open button, all JARs would be added.
    • Go to the Package 'com', right-click on it, New -> Class.
    • Name the class as 'MyTestCase'. Remember to keep it 'public' and check 'public static void main(String[] args)' and 'Inherited abstract methods'. Paste the code snippet in your Eclipse IDE.
    • Run the scripts
    Code Snippet

    package com;

    import java.util.concurrent.TimeUnit;

    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.By;
    import org.openqa.selenium.firefox.*;

    public class MyTestCase {

    /**
    * @param args
    */
    public static void main(String[] args) {
    // TODO Auto-generated method stub
    WebDriver driver = new FirefoxDriver();
    driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
    driver.get("https://www.google.com.pk");
    driver.findElement(By.id("gbqfq")).sendKeys("Software Quality Geeks");
    driver.findElement(By.id("gbqfq")).submit();
    driver.findElement(By.linkText("Software Quality Geeks")).click();
    //driver.quit(); //uncomment this line if you want to quit browser after test run.

    }

    }


    Other things to consider

    Eclipse and Java must be of same bit architecture. For example if you are using 32 bit Eclipse then use 32 bit Java and the same is true to for 64 bit. Otherwise it would be little cumbersome to configure the cross bits eclipse and Java if you're a beginner.