Sunday, March 31, 2013

test report generation (50 mcg)

Report generation is a common function of the applications especially financial applications. For example, all the banks provide statement download function through their websites. I am not sure how they test that functionality, this is what I did for one of my client.

The report downloading process contains following steps, thus a template method or composite approach will be suitable to design a generic ReportDownload, let me design an interface first,

public interface Report{
}

public interface ReportDownload {
   void navigate();
   void enterCriteria(ReportCriteria criteria);
   void triggering();
   Clickable trigger();
   Report findReport();
   Report resolveExpection(Report actual)
}

Report is a type, based on its file type, it can be a CSV, Excel or PDF document.

This is an article about how to save the downloaded file a certain folder, selenium forefox profile, with design, we can add a variable to hold the directory of the download files as per test base, so the findReport() method can look into that directory to find newly arrived file, in that way, you don't need to specify the download file name in the test. To test the result, a simple way is to use pre generation file as an expectation to compare the downloaded report. The expectation can be stored in a classpath directory which can be resolved by the file name of the actual report.

Once expectation and actual report are founded, we can compare two files to find out whether they are same, we can override the equals method to compare the content of the two files.


Report actual = page.findReport();
Report expected = page.resolveExpectation();
assertEquals(expected, actual)

Saturday, March 23, 2013

tackle the incompatibility of selenium jar file with firefox binary version (120 mcg)

If we don't specify the firefox binary location, Selenium web driver will use the default firefox binary location, on Windows, it is C:\Program Files\Mozilla\Firefox\. When firefox upgrade to a newer version, the web driver may fail to trigger the firefox since some API may be changed. Selenium developers will release a newer version of selenium jar file for you to upgrade, but unless you upgrade you dependency file, the test will not work and it can cause frustration.

There is a way to overcome this, to include firefox binary in a jar file and add a maven step to explode it to file system before starting the tests, and you can also include a customized profile in the jar file so it can support file download of known file formats, for example, CSV, PDF and Excel formats. It also saves each individual developer's time in manipulating profile which is also error prone. You can include firebug plugin with the binary so you can use it to examine web elements when running the test on a debug mode.

if the above step is too difficult to achieve, there is another simpler approach, just copy target firefox binary and customized profiles to a location and pass the location as a JVM option variable to the test, the test class then load the firefox binary from the location,


   public static WebDriver getWebDriver() {
      FirefoxBinary firefox = new FirefoxBinary(new File(System.getProperty("firefox.binary"));
      FirefoxProfile profile = new FirefoxProfile(new File(System.getProperty("firefox.profile")
      return new FirefoxDriver(firefox, profile);
   }
This is the constructor used by the method.

and set the following JVM options variables,

   -Dfirefox.binary=/projects/test/firefox
   -Dfirefox.profile=/projects/test/profile



/projects/test/firefox is the unix style for file system folder, it works for Windows as well, it points to C:\projects\test\firefox, where firefox.exe is located for the tests.

This solved the problem caused by the incompatibility of web driver and firefox browser version and make the test more stable.

This solution has evolved into a more advance form, a browser factory using enum

use enum to increase the readability of the test (50 mcg)

Using enum can greatly increase the readability of the code and it may significantly reduce the complexity as well. Let us start with some code not using enum,
    DateUtils.getDate(2012, 5, 6)
It is not clear which month it is. Does it mean May or June? Worse thing is in one library it may mean May and in another library it means June. I added another method to make the following call possible, with static import in Java, it look like this,
    date(June, 6, 2012)
I believe even non technical people can read it and understand now, it make the code much easier to understand.
   public enum Months {
       January,
       February,
       March,
       April,
       May,
       June,
       July,
       August,
       September,
       October,
       November,
       December;
   }
I don't need to rewrite new method, I just need to call the old method in the new method,
    static Date date(Enum month, int day, int year) {
       DateUtils.getDate(year, month.ordinal(), day)
    }
Sometimes, on the web layer, the month may be spelled as a short form, then we can introduce another enum,
   public enum ShortMonths {
       Jan,
       Feb,
       Mar,
       Apr,
       May,
       Jun,
       Jul,
       Aug,
       Sep,
       Oct,
       Nov,
       Dec;
   }
We can pass this ShortMonths and make the call like this,
    date(Jun, 6, 2012)
DatePicker uses this pattern.

Monday, January 21, 2013

horizontally refactor selenium example using page (100 mcg)

When people talk about Refactoring, most of time, it is about Vertical Refactoring as laid out in the Refactoring book by Martin Fowler. Actually, there is another kind of refactoring, Horizontal Refactoring, which is quite useful in writing more comprehensible code.

Please take a look of the example in this page,

http://code.google.com/p/selenium/wiki/PageObjects Do you see duplicated code?
// ☹ this is a bad example, please don't follow the style.
public class LoginPage {
    private final WebDriver driver;

    public LoginPage(WebDriver driver) {
        this.driver = driver;

        // Check that we're on the right page.
        if (!"Login".equals(driver.getTitle())) {
            // Alternatively, we could navigate to the login page, perhaps logging out first
            throw new IllegalStateException("This is not the login page");
        }
    }

    // Conceptually, the login page offers the user the service of being able to "log into"
    // the application using a user name and password. 
    public HomePage loginAs(String username, String password) {
        // This is the only place in the test code that "knows" how to enter these details
        driver.findElement(By.id("username")).sendKeys(username);
        driver.findElement(By.id("passwd")).sendKeys(password);
        driver.findElement(By.id("login")).submit();
         
        // Return a new page object representing the destination. Should the login page ever
        // go somewhere else (for example, a legal disclaimer) then changing the method signature
        // for this method will mean that all tests that rely on this behaviour won't compile.
        return new HomePage(driver);
    }
}
Most people would tolerate this kind of duplicates and so far no tool can detect this kind of duplicates either. However, this coding style cluttered source code with too much information and slows down people's speed since there are too much code to read,

Here is refactored version of the same code, you would see much cleaner code base. I recommend using this style, achieved through Horizontal Refactoring.
//   ☺ This is an good example.
public class LoginPage extends AbstractPage{

    public HomePage loginAs(String username, String password) {
        put(USERNAME, username);
        put(PASSWORD, password);
        button(LOGIN).click();
        return new HomePage(this);
    }
}

These are the methods handling text input field,
 //   ☺ This is an good example.

    /**
     * Enter text into an input filed.
     *
     * @param method
     * @param value
     */
    default public void put(Supplier<By> method, Object value) {
        new Input<>((Where) this).put(method, value);
    }

    /**
     * Autocomplete for text field and return the first found suggestion match the whole word.
     *
     * @param method
     * @param value
     * @param locator
     */
    default public void autocomplete(Supplier<By> method, Object value, Locator<Where, Element> locator) {
        new Input<>((Where) this).autocomplete(method, value, locator);
    }

New code is much cleaner.

Tuesday, October 23, 2012

essential tools for writing effective selenium tests (100 mcg)

When writing Selenium tests, Selenium API alone is not enough. There are some tools which are essential in functional testing.

1. Firefox Browser

Selenium has implemented most popular browsers such as Internet Explorer, Safari, Opera, iPhone, Android and Firefox. In a project, due to cost constraint, usually it is very difficult to writing tests for many browsers, I choose to use Firefox driver since it comes with a Screenshot saving function to allow recording of screenshot at anytime. I choose to take a screenshot before and after clicking a WebElement which invoke a HTTP request so when when things go wrong, I can combine the log on build machine and the screenshot series to figure out the cause of the problems. Another reason I choose to use Firefox is the availability of Firebug.


2. Firebug

https://getfirebug.com/

Even you are not writing Selenium tests, as long as you are doing web development, Firebug should be included in your toolkit. I use Firebug to inspect the web pages and design a searching strategy for the WebElements. And for none significant information, just right click the element and select "Copy XPath" from the popup menu, and the information is ready to use,



WebDriver webDriver = new FirefoxDriver();
webDriver.findElements(By.xpath("/html/body/div/div/div[3]");

This query will return the WebElement for the bug. While these two lines of code may not be meaningful to most people, but if it is in a Page object, it becomes instantly meaningful. That's the reason we need to introduce a Page model into Selenium based function tests, see design of page (500 mcg) for nutrition information.


public class FirebugHomePage {

   WebDriver webDriver = new FirefoxDriver();

   public WebElement getLargeFirebugImage() {
      webDriver.findElement(By.xpath("/html/body/div/div/div[3]");
   }
}


Friday, October 19, 2012

clickable interface (300 mcg)

Clickable is a simple interface with only one method click. It is a common interface for Url, Link and Button classes.

public interface Clickable {

    void click();

}
public class Clickables<Where extends Searchable<Where>> implements Clickable {

    private static final Logger log = getLogger(Clickables.class);
    private final Where where;
    private final Locator<Where, Element> locator;

    public Clickables(Where where, Locator<Where, Element> locator) {
        this.locator = locator;
        this.where = where;
    }

    @Override
    public void click() {
        Element apply = locator.locate(where);
        log.info("clicking [" + apply + "]");
        where.save();
        apply.click();
        where.save();
    }

    @Override
    public String toString() {
        return locator.toString();
    }
}
public class Link<Where extends Searchable<Where>> extends Clickables<Where> {

    public Link(Where where, Locator<Where, Element> locator) {
        super(where, locator);
    }
}

    /**
     * Find the link using the selector.
     *
     * @param selector selector
     * @return the link using the selector.
     */
    @SuppressWarnings("unchecked")
    default public Clickable link(Supplier<By> selector) {
        return new Link<>((Where) this, element(selector));
    }

    public static <Where extends Searchable<Where>> Locators<Where, Element> element(Supplier<By> selector) {
        return new ElementLocator<>(selector);
    }
public class ElementLocator<Where extends Searchable<Where>>
        extends Locators<Where, Element> {

    public ElementLocator(Supplier<By> selector) {
        super((Where where) -> where.untilFound(selector));
    }
}

this example show how to use click(), and until()

        manningPage.link(Java).click();
        Element element = manningPage.until(new ElementLocator<>(ActiveMQ_In_Action));
        element.click();
        manningPage.until(IS_COPYRIGHTED);

What benefit do we get from this Link class? There are couple of benefits, one advantage is to add some logging and screenshot generating logic before and after the clicking event, those screenshots can be used for problem solving purpose in case test fails, we can use the generated screenshots as a analysis input to figure out what went wrong during last time. For example, finding an element will fail if there is a server error and the application return an error page instead of the expected page. Without the screenshot, we wouldn't be sure why we can't find the element.

So the click method can be rewritten like this,

Besides Link, Submit input and some button can also submit http request to refresh pages, so these can be encapsulated into Submit, Button classes.


After Java 8 came out, the wait logic can be further simplified into an interface with default methods.
public interface ExplcitWait<T> {

    default public <T1> T1 until(Function<T, T1> predicate) {
        return until(30, SECONDS, predicate);
    }

    default public void until(Predicate<T> predicate) {
        until(30, SECONDS, predicate);
    }

    default public <T1> T1 until(int duration, TimeUnit timeUnit, Function<T, T1> function) {
        return getFluentWait(duration, timeUnit).until((T it) -> function.apply(it));
    }

    default public void until(int duration, TimeUnit timeUnit, Predicate<T> predicate) {
        getFluentWait(duration, timeUnit).until((T it) -> predicate.test(it));
    }

    default public FluentWait<T> getFluentWait(int duration, TimeUnit timeUnit) {
        return new FluentWait<>((T) this).withTimeout(duration, timeUnit).pollingEvery(50, MILLISECONDS).ignoring(Exception.class);
    }
}

An useful application of Clickable interface is to collect all the menu items into a Stream of Clickable and for each item inside the stream, click them one by one to implement the menu testing,

Thursday, October 18, 2012

explicit wait interface (200 mcg)

In my opinion, Selenium WebDriver should have a callback mechanism similar to AJAX callback and invoke the callback when HTTP request is settled. This would greatly reduce the waiting period in error cases. When expecting something to appear, there is no indicator to tell whether the element hasn't appear yet, or it will never appear. For now, according to Selenium document, there are two kind of waiting mechanish available to use,

1. Implicit Waits An implicit wait is to tell WebDriver to poll the DOM for a certain amount of time when trying to find an element or elements if they are not immediately available. The default setting is 0. Once set, the implicit wait is set for the life of the WebDriver object instance.
WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = driver.findElement(By.id("myDynamicElement"));


The disadvantage is after setting implicit wait, WebDriver will wait for all elements which are not found at once which will dramatically slow down the tests in the error condition, so Selenium provided an alternative, Explicit Waits,

2. Explicit Waits An explicit waits is code you define to wait for a certain condition to occur before proceeding further in the code. The worst case of this is Thread.sleep(), which sets the condition to an exact time period to wait. There are some convenience methods provided that help you write code that will wait only as long as required. WebDriverWait in combination with ExpectedCondition is one way this can be accomplished.

WebDriver driver = new FirefoxDriver();
driver.get("http://somedomain/url_that_delays_loading");
WebElement myDynamicElement = (new WebDriverWait(driver, 10))
  .until(ExpectedConditions.presenceOfElementLocated(By.id("myDynamicElement")));
3. FluentWait and WebDriverWait This WebDriverWait, extends FluentWait which implements an interface Wait, and give a timeout as the maximum patience.

At first sight, FluentWait has more complex API then WebDriverWait, WebDriverWait is a refined memeber since it is easier to use and meet your testing need thus I didn't spend time to study FluentWait. I only use WebDriverWait and I found out the places FluentWait used can be replaced by WebDriverWait to simplify the source code.

For example, I found an example using FluentWait here



    FluentWait<WebDriver> wait = new FluentWait<WebDriver>(driver)
            .withTimeout(timeoutSeconds, TimeUnit.SECONDS)
            .pollingEvery(500, TimeUnit.MILLISECONDS)
            .ignoring(NoSuchElementException.class);

    WebElement element = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver webDriver) {
            return driver.findElement(locator);
        }
}

can be simplified as this, less code to read for other developers,

    WebDriverWait wait = new WebDriverWait(driver, timeoutSeconds)

    WebElement element = wait.until(new Function<WebDriver, WebElement>() {
        public WebElement apply(WebDriver webDriver) {
            return driver.findElement(locator);
        }

}


As you can see, if you add Explicit Wait to the code, the codebase will be cluttered with this waiting mechanism repeated over and over again.

To avoid repeating this, an interface ExplicitWait is introduced, so it can be selectively called. In the the Searchable interface, a method untilFound is designed to call this until method in the ExplicitWait interface.

public interface ExplicitWait<Where> {

    void save();

    default public <What> What until(Locator<Where, What> predicate) {
        return until(30, SECONDS, predicate);
    }

    default public void until(Predicate<Where> predicate) {
        until(30, SECONDS, predicate);
    }

    default public <What> What until(int duration, TimeUnit timeUnit, Locator<Where, What> locator) {
        try {
            return getFluentWait(duration, timeUnit).until((Where where) -> locator.apply(where));
        } catch (RuntimeException e) {
            save();
            throw e;
        }
    }

    default public void until(int duration, TimeUnit timeUnit, Predicate<Where> predicate) {
        try {
            getFluentWait(duration, timeUnit).until((Where where) -> predicate.test(where));
        } catch (RuntimeException e) {
            save();
            throw e;
        }
    }

    default public FluentWait<Where> getFluentWait(int duration, TimeUnit timeUnit) {
        return new FluentWait<>((Where) this).withTimeout(duration, timeUnit).pollingEvery(50, MILLISECONDS).ignoring(Exception.class);
    }
}


If you want to have a more generic waiting interface like the ExplicitWait in this example, FluentWait is a better candidate to use since it allows you to give a parameterized type as shown. In the development of Selenium Capsules, the reason FluentWait is chosen over WebDriverWait is that there are 3 classes in the framework which wrapper the original WebDriver, WebElement from Selenium. They are AbstractPage, AbstractForm and Element which implement Waitable interface.

In the code, <Where> is a type parameter, it can be an AbstractPage, an Element, or an AbstractForm. Not only T, E can be used as generic type parameter, Where, What or other meaningful words, as long as not conflicting with the Class names used in the containing class, can be used as type parameters.

This interface then can be used everywhere in the project, and have AbstractPage implement it. After any clicking event which triggers a page refresh, call the one of the until methods, either pass in a Predicate or a Locator.

public abstract class AbstractPage implements ExplicitWait<AbstractPage> {

    @Override
    public final Element untilFound(By by) {
        return until(15, SECONDS, (AbstractPage page) -> browser.findElement(by));
    }


This untilFound greatly reduced the duplicate of the testing code. Without this method, each individual developer needs to add a wait statement after each findElement method call. The untilFound method abstracts the complexity away so the page class is cleaner.

/**
 *
 * Copyright (c) 2012, Algocrafts, Inc. All rights reserved.
 * Apache License version 2.
 */
package com.algocrafts.page;
 
import com.algocrafts.selenium.core.WaitWithPatience;
import com.google.common.base.Predicate;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;

public class YujunsBlogPage extends AbstractPage {
 
   public void clickDesignOfDatePickerLink() {
      untilFound(By.linkText("Design of DatePicker").click();
   }
 
   public void clickDesignOfPageLink() {
      untilFound(By.linkText("Design of Page").click();
   }
}

One particular method, untilFound, will be waiting for the element to appear or throwing NoSuchElementException after timed out.

    @Override
    public final Element findElement(By by) {
        try {
            return browser.findElement(by);
        } catch (Exception e) {
        }
        return null;
    }


    /**
     * Find the first element or throw NoSuchElementException
     *
     * @param by selector
     * @return the first element or throw NoSuchElementException
     */
    @Override
    public final Element untilFound(final By by) {
        return until((AbstractPage page) -> browser.findElement(by));
    }

    @Override
    public final Stream<Element> findElements(Supplier<By> by) {
        return browser.findElements(by);
    }

So if you are definitely expecting an element on the page, please use untilFound method. findElement will not wait. The untilFound method is more suitable in a AJAX environment where timing is very important.

ElementLocator calls untilFound while ElementTryLocator calls findElement,

import com.algocrafts.pages.Element;
import com.algocrafts.pages.Searchable;
import org.openqa.selenium.By;

import java.util.function.Supplier;

public class ElementLocator<Where extends Searchable<Where>> extends AbstractLocator<Where, Element> {

    public ElementLocator(Supplier<By> method) {
        super(method);
    }

    @Override
    public Element find(Where where) {
        return where.untilFound(by);
    }
}


import com.algocrafts.pages.Element;
import com.algocrafts.pages.Searchable;
import org.openqa.selenium.By;

import java.util.function.Supplier;

public class ElementTryLocator<Where extends Searchable<Where>> extends AbstractLocator<Where, Element> {

    public ElementTryLocator(Supplier<By> method) {
        super(method);
    }

    @Override
    public Element find(Where where) {
        return where.findElement(by);
    }
}

The ExplicitWait interface is very useful in providing Explicit wait By wrapping FluentWait, since Java 8, it is legal to provide default method implementation inside interface which made the code even cleaner.

Before Java 8, Google Guava code provided two interfaces, Function and Predicate, to enable functional programming in Java. Selenium FluentWait, uses both Function and Predicate from Guava code.

Should Selenium Capsules sticks to Google Guava, or the Function and Predicate from Java 8? The decision I made is to use Java 8. The reason is simple, Java 8 Collection API has a new addition, Stream, which requires the interface of Java 8 Function and Predicate, so using them is beneficial in utilizing new features from Java 8. Then how to convert the Java 8 into Guava Function and Predicate? Actually that's pretty easy in Java 8, let me show all the possible solutions,

1. Plain Old Anonymous Inner Class

    /**
     * @param duration  timeout duration
     * @param timeUnit  unit
     * @param predicate predicate
     * @throws TimeoutException timeout
     */
    default public void until(int duration, TimeUnit timeUnit, final Predicate<Where> predicate) throws TimeoutException {
        try {
            getFluentWait(duration, timeUnit).until(new com.google.common.base.Predicate<Where>() {
                @Override
                public boolean apply(Where where) {
                    return predicate.test(where);
                }
            });
        } catch (TimeoutException e) {
            save();
            throw e;
        }
    }

2. Lambda Expression

    /**
     * @param duration  timeout duration
     * @param timeUnit  unit
     * @param predicate predicate
     * @throws TimeoutException timeout
     */
    default public void until(int duration, TimeUnit timeUnit, Predicate<Where> predicate) throws TimeoutException {
        try {
            getFluentWait(duration, timeUnit).until((Where where) -> predicate.test(where));
        } catch (TimeoutException e) {
            save();
            throw e;
        }
    }


3. Method Reference

    /**
     * @param duration  timeout duration
     * @param timeUnit  unit
     * @param predicate predicate
     * @throws TimeoutException timeout
     */
    default public void until(int duration, TimeUnit timeUnit, Predicate<Where> predicate) throws TimeoutException {
        try {
            getFluentWait(duration, timeUnit).until(predicate::test);
        } catch (TimeoutException e) {
            save();
            throw e;
        }
    }


You can see, Method Reference is the simplest, Java 8 is a huge step forward.