Thursday, November 22, 2012

A Selenium/WebDriver example in Java

A couple of years back, I was pitching for some work and the client wanted to see how I would tackle a real world problem.  They asked me to automate some tasks on the woot.com web site.

The task was to go to various woot web sites and to read the product name and price of the offer of the day.

I wrote a little bit of Selenium code and thought I'd post it here in case any of it is useful to anyone.

I got the job - so it can't be too bad.

First up I defined an interface to represent a woot page:


package uk.co.doogle;

import com.thoughtworks.selenium.Selenium;

/**
 * This interface defines the methods we must implement for classes
 * of type Woot.  Woot web sites have one item for sale every 24 hours.
 * @author Tony
 */
public interface Woot {

/**
* Defines the interface of the method we use to get the price
* of the item for sale on a Woot website
* @param selenium the selenium object we pass in which is used to interact
* with the browser/web page
* @return String representation of the price of the item for sale
*/
public String getPrice(Selenium selenium);

/**
* Defines the interface of the method we use to get the product name
* of the item for sale on a Woot website
* @param selenium the selenium object we pass in which is used to interact
* with the browser/web page
* @return String representation of the product name of the item for sale
*/
public String getProductName(Selenium selenium);

}

Then I implemented this interface a few times to represent the actual behaviour of the various woot pages - here for example if the winewoot page:

public class WineWoot extends BaseWoot {

/**
* Constructor
* @param url pass in the url of the web site
*/
public WineWoot(String url) {
super(url);
}
/**
* Implementation of the method to get the price of the object for sale on 
* the Woot web site.
*/
public String getPrice(Selenium selenium) {
//if you need to update the xpath to the piece of text of interest - use xpather firefox plugin
String xPath = "//html/body/header/nav/ul/li[8]/section/div/a/div[3]/span";
selenium.waitForCondition("selenium.isElementPresent(\"xpath=" + xPath + "\");", "12000");
return selenium.getText(xPath) + " ";
}

/**
* Implementation of the method to get the product name of the item for sale 
* on the Woot web site
*/
public String getProductName(Selenium selenium) {
//if you need to update the xpath to the piece of text of interest - use xpather firefox plugin
String xPath = "//html/body/header/nav/ul/li[8]/section/div/a/div[2]";
selenium.waitForCondition("selenium.isElementPresent(\"xpath=" + xPath + "\");", "12000");
return selenium.getText(xPath) + " ";
}
}

Note - back then I used the xPather plugin - this doesn't work for recent versions of firefox, so now I use firebug.

Then I wrote the actual 'test':

package uk.co.doogle;

import com.thoughtworks.selenium.*;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.List;

/**
 * This class is where we define tests of the Woot web sites
 * @author Tony
 *
 */
public class TestWoots extends SeleneseTestCase {
/**
* Outputstream for our results file
*/
private BufferedWriter out;
/**
* Our list of Woot web sites we want to test
*/
private List<BaseWoot> sites = new ArrayList<BaseWoot>();
/**
* This is where we do any set up needed before our test(s) run.
* Here we add the list of Woot web sites we want to test and we create an 
* output stream ready to write results to file
*/
public void setUp() throws Exception {
sites.add(new BaseWoot("http://www.woot.com/"));
sites.add(new ShirtWoot("http://shirt.woot.com/"));
sites.add(new WineWoot("http://wine.woot.com/"));
try {
//let's append to our file...
FileWriter fstream = new FileWriter("out.csv", true);
       out = new BufferedWriter(fstream);
       out.write("Site, Product Name, Product Price");
       out.newLine();
} catch (Exception e) {
System.err.println("Error creating a file to write our results to: " + e.getMessage());
}
}

/**
* Tests getting the item name and price for the item for sale on each Woot web site we test.  We see the results of the test 
* in std out in the form of a table and we also write the results to a csv file.  
* If there are any errors getting the information, this is displayed instead.  
* How to run me: open command prompt and from the directory where our selenium server is 
* located type: java -jar selenium-server-standalone-2.0b3.jar (or equivalent) and wait for the server to start up. 
* Then just run this unit test.
*/
public void testGetItemsAndPrices() throws Exception {
//for each Woot site in our list of sites we want to test
for (BaseWoot woot : sites) {
//let's put this in a try catch block as we want to try ALL the sites - some may be down or slow...
try {
selenium = new DefaultSelenium("localhost", 4444, "*firefox", woot.getUrl());
selenium.start();
selenium.open("/");
selenium.waitForPageToLoad("50000");
//add a new row for our table to std out
System.out.println();
//print out the information we need - the site, the title of the item for sale and the price
String siteUrl =  woot.getUrl();
String productName = woot.getProductName(selenium);
String productPrice = woot.getPrice(selenium);
//sometimes there are commas which mess up our csv file - so
//we substitute with ;
productName = productName.replace(",", ";");
System.out.print("website: " + siteUrl + " ");
System.out.print("product name: " + productName);
System.out.print("price: " +   productPrice);
out.write(siteUrl + ", " + productName + ", " + productPrice);
out.newLine();
} catch (Exception ex) {
//here may may see that the web site under test has changed and the xpath to the price or product name may need to 
//be changed in the Woot class
System.out.print("problem getting the data for: " +  woot.getUrl()+ " " + ex.getMessage() + " ");
} finally {
selenium.stop();
}
}
}

/**
* Any tear-down we need to do to cleanup after our test(s).
* Here we just stop selenium and close the output stream
*/
public void tearDown() throws Exception {
selenium.stop();
out.close();
}
}

I know this code worked for a couple of years, and I have made some minor changes to get it to work with the current woot.com web sites - all I had to do was get the latest selenium-server-standalone.jar for it to work with the latest firefox and also to update the xpaths to the price and product name information.  That would be a good improvement to the code - to make it data driven - such that we could just update the xpaths in a config file rather than changing the hard-coded ones I have used here.  That was the only feedback from the client actually.

Anyway - hope you find it useful - and if you need expert automation engineers get in touch with Doogle!



3 comments:

  1. Interesting piece of code could you help me installing some html code in my blog? i could pay you..

    Lynda

    ReplyDelete
    Replies
    1. Hi - glad you found it interesting! Get in touch via my web site with more details about what you need to do (www.doogleonline.co.uk) and I'll see if I can help, Cheers, Tony.

      Delete
  2. This comment has been removed by the author.

    ReplyDelete