Tuesday, December 15, 2015

Selenium automation design pattern - The Journey Pattern

Browser automation is becoming more and more popular. Many people use it today: IT companies, automation testers, hackers, etc ...

Its possible to do lots of things with it; testing a website, scrap some latest changes, social media bots, and much more...(I stop there, Im not wearing my black hat today, no worries ;) )

You probably know, that there is a tool out there called Selenium for those who like Java and want to do browser automation. As per what I've seen so far from working in large companies, automation tasks are not always done by programmers, more and more often testers are writing pseudo-java code to do this tasks.

For the purpose of testing, Selenium code should always be treated in the same way as every other Java code. By this I mean, that clean coding and Object Oriented principles are still important.
A clean and understandable test harness is extremely important for being able to scale automation testing.


Unfortunately testers that are given automation tasks often lack the Object Oriented background that Java developers have and unless the company is willing to provide the proper programming training or the task is actually done by a programmer alongside, the chances of ending up with an unmaintainable UI automation test harness are high.


When it comes to using selenium for browser automation, the most widely used pattern is the PageObject. Basically page objects are just classes that represent each screen in the webapp. The PageObject its a good pattern that its being around for long time, but unfortunately the practice shows us that following this patter we often create duplication and we are not always capable of reusing the page objects.

A colleague not too long ago, told me to have a look at the Journey Pattern.
The idea behind the Journey pattern is that the automation is done around journeys. Every journey is composed of actions such as Enter text into, Click...

So lets have a look at 2 sample journeys:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
        //Just preparing selenium
        WebDriverBackedSelenium selenium;
        WebDriver driver = new FirefoxDriver();
        selenium = new WebDriverBackedSelenium(driver, START_URL);
        selenium.open(START_URL);
        selenium.waitForPageToLoad("2000");


        // Journey 1 - to verify login works (assertions omitted)
        LogIn.as(driver, "myUsername", "myPassword");
        // Journey 2 - write a comment on the news headlines
        WriteComment.in(driver, HeadlinesPage.commentBox);

The driver is passed around and its state is modified during each journey. In this example, we choose to create 2 separate journeys, where one Journey starts when the other ends. Since we pass the driver around, we don't need to worry about the user not being logged in before writing a comment(DRY). Each journey is composed of different action, and their components may be reusable across journeys:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
//Login is the Journey
public class LogIn {
    public static void as(WebDriver driver, String username, String password) {
        Enter.textInto(driver, username, LoginScreen.usernameBox);
        Enter.textInto(driver, password, LoginScreen.passwordBox);
        Click.on(driver, LoginScreen.loginButton);
    }
}

//Write a comment is a Journey
public class WriteComment {

    public static void in(WebDriver driver, By commentBox) {
        Enter.textInto(driver, "test comment", commentBox);
        Click.on(driver, HeadlinesPage.commentButton);
    }
}


Each of this Journeys as you can see reuse actions, such as Click, Enter, etc ...


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Enter {
    public static void textInto(WebDriver driver, String text, By selector) {
        driver.findElement(selector).sendKeys(text);
    }
}

public class Click {
    public static void on(WebDriver driver, By selector) {
        driver.findElement(selector).click();
    }
}


And finally, the actual pages just contain selectors to get access to the elements of the page:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class LoginScreen {
    public static By usernameBox = By.cssSelector("#username");
    public static By passwordBox = By.cssSelector("#password");
    public static By loginButton = By.cssSelector("#loginButton");
}


public class HeadlinesPage {
    public static By commentBox = By.cssSelector("#commentBox");
    public static By commentButton = By.cssSelector("#commentButton");
}


The journey pattern is very simple to learn, flexible and also scalable. If you are a tester with some notions of Java and Selenium, play with it, give it a try,


No comments:

Post a Comment

Share with your friends