Many of us must be trying to find the best way to do automation testing using selenium. And if we write our script in the same class, it becomes too long and difficult to manage. To tackle the same one can always follow the hybrid framework mentioned in my earlier post. But is it the best way to do it? The answer depends on how do we want to code our script. There is a way which I have implemented recently, which gives an option to reuse the code in an efficient manner. The details of the approach are as follows.
Here, in this approach, what I am trying to do is create separate classes as per the properties we will be testing. Let’s say the table below drives my test.
Property | Locator | LocatorType | Value | ExpectedResult | Permission | Name |
url | http://ibnlive.in.com/ | open | ||||
pagetitle | CNN-IBN Live News, Breaking News, Top Headlines, Live/Current News Alerts |
Let’s now look at the first row of the table. Property for the first row is url. So the logic would be,
if(property = "url") then create url object. use the object to do url related operation.
So our requirement now is a class called ‘Url’ which contains some property and methods to do testing related to URL’s. Below is the sample class. (The class is a sample. It depends on the user what to write as the business logic for the same)
import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.chrome.ChromeDriver; @SuppressWarnings("unused") public class Url { private WebDriver localDriver; String localProperty; String localLocator; String localLocatorType; String localValue; String localExpectedResult; String localPermission; String localName; String actualResult; public Url(WebDriver driver, String property, String locator, String locatorType, String value, String expectedResult, String permission, String name){ localDriver = driver; localProperty = property; localLocator = locator; localLocatorType = locatorType; localValue = value; localExpectedResult = expectedResult; localPermission = permission; localName = name; } public boolean testUrl() throws Exception{ if(localPermission.equals("open")){ localDriver.get(localLocator); setActualResult("Opened URL"); return true; } else { String url = localDriver.getCurrentUrl(); //assertEquals("In Page: "+localDriver.getTitle(), localExpectedResult, url); if(localExpectedResult.equals(url)){ setActualResult(url); return true; } else { setActualResult(url); return false; } } } public void setActualResult(String actualResult){ this.actualResult = actualResult; } public String getActualResult(){ return actualResult; } private boolean isElementPresent(By by) { try { localDriver.findElement(by); return true; } catch (NoSuchElementException e) { return false; } } }
This class has all the properties defined as the column names of the table. Also there is a constructor available to create the object of the class type. The business logic is written in the testUrl method which is dependent on the parameters passed to the method and it returns a boolean type value (either true or false). Depending on the result returned the final result of the test step is decided. Similarly one more sample class for the second row property (pagetitle) would be as below.
package TestElements; import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.chrome.ChromeDriver; @SuppressWarnings("unused") public class PageTitle { private WebDriver localDriver; String localProperty; String localLocator; String localLocatorType; String localValue; String localExpectedResult; String localPermission; String localName; String actualResult; public PageTitle(WebDriver driver, String property, String locator, String locatorType, String value, String expectedResult, String permission, String name){ localDriver = driver; localProperty = property; localLocator = locator; localLocatorType = locatorType; localValue = value; localExpectedResult = expectedResult; localPermission = permission; localName = name; } public boolean testPageTitle() throws Exception{ String title = localDriver.getTitle(); setActualResult(title); //assertEquals("In Page: "+title, localExpectedResult, title); if(localExpectedResult.equals(title)){ return true; } else{ return false; } } public void setActualResult(String actualResult){ this.actualResult = actualResult; } public String getActualResult(){ return actualResult; } private boolean isElementPresent(By by) { try { localDriver.findElement(by); return true; } catch (NoSuchElementException e) { return false; } } }
Here the testPageTitle method does all the work. Below is another sample class for a different page element let’s say textbox.
package TestElements; import org.openqa.selenium.*; import org.openqa.selenium.firefox.FirefoxDriver; import org.openqa.selenium.ie.InternetExplorerDriver; import org.openqa.selenium.chrome.ChromeDriver; @SuppressWarnings("unused") public class TextBox { private WebDriver localDriver; String localCashCoupon; String localTicketNumber; String localProperty; String localLocator; String localLocatorType; String localValue; String localExpectedResult; String localPermission; String localName; String actualResult; public TextBox(WebDriver driver, String cashCoupon, String ticketNumber, String property, String locator, String locatorType, String value, String expectedResult, String permission, String name){ localDriver = driver; localCashCoupon = cashCoupon; localTicketNumber = ticketNumber; localProperty = property; localLocator = locator; localLocatorType = locatorType; localValue = value; localExpectedResult = expectedResult; localPermission = permission; localName = name; } public TextBox(WebDriver driver, String value, String locator){ localDriver = driver; localValue = value; localLocator = locator; } public boolean testTextBox() throws Exception{ //assertTrue("In Page: "+localDriver.getTitle(), isElementPresent(By.xpath(localLocator)) || isElementPresent(By.cssSelector(localLocator)) || isElementPresent(By.name(localLocator)) || isElementPresent(By.id(localLocator))); if(isElementPresent(By.xpath(localLocator)) || isElementPresent(By.cssSelector(localLocator)) || isElementPresent(By.name(localLocator)) || isElementPresent(By.id(localLocator))){ if(localPermission.equals("editability")){ if(localLocatorType.equals("xpath")){ //assertTrue("In Page: "+localDriver.getTitle(), localDriver.findElement(By.xpath(localLocator)).isEnabled()); if(localDriver.findElement(By.xpath(localLocator)).isEnabled()){ setActualResult("Editable"); return true; } else { setActualResult("Not Editable"); return false; } } else if(localLocatorType.equals("cssSelector")){ //assertTrue("In Page: "+localDriver.getTitle(), localDriver.findElement(By.cssSelector(localLocator)).isEnabled()); if(localDriver.findElement(By.cssSelector(localLocator)).isEnabled()){ setActualResult("Editable"); return true; } else{ setActualResult("Not Editable"); return false; } } else if(localLocatorType.equals("id")){ //assertTrue("In Page: "+localDriver.getTitle(), localDriver.findElement(By.id(localLocator)).isEnabled()); if(localDriver.findElement(By.id(localLocator)).isEnabled()){ setActualResult("Editable"); return true; } else{ setActualResult("Not Editable"); return false; } } else if(localLocatorType.equals("name")){ //assertTrue("In Page: "+localDriver.getTitle(), localDriver.findElement(By.name(localLocator)).isEnabled()); if(localDriver.findElement(By.name(localLocator)).isEnabled()){ setActualResult("Editable"); return true; } else{ setActualResult("Not editable"); return false; } } } if(localPermission.equals("type")){ if(localLocatorType.equals("xpath")){ localDriver.findElement(By.xpath(localLocator)).clear(); localDriver.findElement(By.xpath(localLocator)).sendKeys(localValue); } else if(localLocatorType.equals("cssSelector")){ localDriver.findElement(By.cssSelector(localLocator)).clear(); localDriver.findElement(By.cssSelector(localLocator)).sendKeys(localValue); } else if(localLocatorType.equals("id")){ localDriver.findElement(By.id(localLocator)).clear(); localDriver.findElement(By.id(localLocator)).sendKeys(localValue); } else if(localLocatorType.equals("name")){ localDriver.findElement(By.name(localLocator)).clear(); localDriver.findElement(By.name(localLocator)).sendKeys(localValue); } setActualResult("Value Entered"); return true; } if(localPermission.equals("date")){ DynamicDate date = new DynamicDate(); String testDate = date.getTestDate(); if(localLocatorType.equals("xpath")){ localDriver.findElement(By.xpath(localLocator)).clear(); localDriver.findElement(By.xpath(localLocator)).sendKeys(testDate); } else if(localLocatorType.equals("cssSelector")){ localDriver.findElement(By.cssSelector(localLocator)).clear(); localDriver.findElement(By.cssSelector(localLocator)).sendKeys(testDate); } else if(localLocatorType.equals("id")){ localDriver.findElement(By.id(localLocator)).clear(); localDriver.findElement(By.id(localLocator)).sendKeys(testDate); } else if(localLocatorType.equals("name")){ localDriver.findElement(By.name(localLocator)).clear(); localDriver.findElement(By.name(localLocator)).sendKeys(testDate); } setActualResult("Date Entered"); return true; } } } else { setActualResult("Element Not Found"); return false; } return true; } public void typeValue(){ localDriver.findElement(By.xpath(localLocator)).clear(); localDriver.findElement(By.xpath(localLocator)).sendKeys(localValue); } public void setActualResult(String actualResult){ this.actualResult = actualResult; } public String getActualResult(){ return actualResult; } private boolean isElementPresent(By by) { try { localDriver.findElement(by); return true; } catch (NoSuchElementException e) { return false; } } }
Here the business logic is present in the testTextBox method.
Now how to make use of them. Let’s assume we are using a Database where the table is residing. So we need to create another class which will drive the test. Let’s call it “TestDriver” class. Below is the sample class that is required for driving our test.
//import the required libraries //import the test classes that you already have written public class TestDriver{ private WebDriver driver; private String baseUrl="http://www.redbus.in/"; private StringBuffer verificationErrors = new StringBuffer(); private boolean result; private String actualResult; @BeforeClass public void setUp() throws Exception { driver = new FirefoxDriver(); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); driver.get(baseUrl); } @Test() public void testElements() throws Exception { Connection conn=null; try { Class.forName("com.mysql.jdbc.Driver"); conn = DriverManager.getConnection("connection string", "user name", "password"); } catch (SQLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } ResultSet resultSet = null; PreparedStatement preparedStatement = conn.prepareStatement("select * from YourTableName"); resultSet = preparedStatement.executeQuery(); while(resultSet.next()){ String property = resultSet.getString(1); String locator = resultSet.getString(2); String locatorType = resultSet.getString(3); String value = resultSet.getString(4); String expectedResult = resultSet.getString(5); String permission = resultSet.getString(6); String name = resultSet.getString(7); System.out.println("Current Row is "+property+", "+locator+", "+locatorType+", "+value+", "+expectedResult+", "+permission+", "+name); //Start of Page Title testing block if(property.equals("pagetitle")){ PageTitle title = new PageTitle(driver, property, locator, locatorType, value, expectedResult, permission, name); result = title.testPageTitle(); actualResult = title.getActualResult(); updateResult(result,name,expectedResult); } //End of Page Title testing block //Start of Text Box testing block, used to test if text box is editable, to write values in them if(property.equals("textbox")){ TextBox textBox = new TextBox(driver, cashCoupon, ticketNumber, property, locator, locatorType, value, expectedResult, permission, name); result = textBox.testTextBox(); actualResult = textBox.getActualResult(); updateResult(result,name,expectedResult); } //End of Text Box testing block //Start of URL testing block, used to get the URL being displayed for a page if(property.equals("url")){ Url url = new Url(driver, property, locator, locatorType, value, expectedResult, permission, name); result = url.testUrl(); actualResult = url.getActualResult(); updateResult(result,name,expectedResult); } //End of URL testing block } } @AfterClass public void tearDown() throws Exception { driver.close(); driver.quit(); //service.stop(); String verificationErrorString = verificationErrors.toString(); if (!"".equals(verificationErrorString)) { fail(verificationErrorString); } } private boolean isElementPresent(By by) { try { driver.findElement(by); return true; } catch (NoSuchElementException e) { return false; } } private void updateResult(boolean bool, String name, String expectedResult) throws Exception{ Label label1 = new Label(0,rowCounter,name); Label label2 = new Label(1,rowCounter,expectedResult); Label label3 = new Label(2,rowCounter,actualResult); sheet.addCell(label1); sheet.addCell(label2); sheet.addCell(label3); if(result){ WritableFont writableFont = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD); WritableCellFormat writableCellFormat = new WritableCellFormat(writableFont); writableCellFormat.setBackground(Colour.GREEN); Label label4 = new Label(3,rowCounter,"Pass",writableCellFormat); passCounter++; sheet.addCell(label4); } else{ WritableFont writableFont = new WritableFont(WritableFont.ARIAL, 10, WritableFont.BOLD); WritableCellFormat writableCellFormat = new WritableCellFormat(writableFont); writableCellFormat.setBackground(Colour.RED); Label label4 = new Label(3,rowCounter,"Fail",writableCellFormat); failCounter++; sheet.addCell(label4); } rowCounter++; } }
Let’s concentrate on the Test method and ignore the rest part. (Anyways the code is a sample and many snippets are deleted. It will not work by copy pasting the same). So to make use of the test classes, we need to create the objects of the classes. Then we need to call the method defined the classes using the object. So here the objects are created depending on the property type defined in the table and bases on the same each block is executed. The test goes on in loop for as many rows present in the table.
* Selenium 2 is used to describe the code blocks
* The codes mentioned here are snippets and many thing are deleted. They may not work if directly copied
* The sample mentioned here generates a custom output. TestNG capabilities can be used if the user prefers by using assertions instead of if else block the the test classes by making the return type of the method void.