Monday 25 August 2014

Using Page Factories with Page Objects!!

Continues with my previous Post!!!

The code that we have learnt to write earlier can be quite verbose.
To clean up our code, we can start to use Page Factories.
This allows us to annotate variables in our page objects with how to search the page.
This means that we don't have to have full
WebElement element = driver.findElement(…); code all over the file.

We can change it to:
@FindBy(how=How.ID, using="foo")
WebElement foo;

As you can see this can make our code slightly easier to read and therefore more
maintainable. If you regularly use other languages like Ruby or Python,
you will notice that they don't have the PageFactory support project.
This is because those languages don't have Factory constructs in the language.
They are not idiomatic and therefore not in the language. To use the
PageFactory project in WebDriver, we will have to make sure that the
we have added it as a dependency.

Let us now update my previous post code from with an example of the PageFactory.

See my  the previous post   and go to Chapter2.java. It should look like the
following example:

Chapter2.java

import org.openqa.selenium;
import junit.framework.Assert;
public class Chapter2 {
WebDriver selenium;
WebElement verifybutton;

public Chapter2(WebDriver selenium){
this.selenium = selenium;
verifybutton = selenium.findElement(By.id("verifybutton"));
if (!"Chapter 2".equalsIgnoreCase(this.selenium.getTitle())){
selenium.get("http://book.theautomatedtester.co.uk/chapter2");
}
}
public boolean isButtonPresent(String button){
return selenium.findElements(By.xpath("//input[@id='"+button+"']")).size()>0;
}
}

We can then change the line that looks for verify button so that it is not in 
the constructor.  This then changes to:

public class Chapter2 {
WebDriver selenium;

@FindBy(how= How.NAME, using="verifybutton")
WebElement verifybutton;

public Chapter2(WebDriver selenium){
this.selenium = selenium;
if (!"Chapter 2".equalsIgnoreCase(this.selenium.getTitle())){
selenium.get("http://book.theautomatedtester.co.uk/chapter2");
}
}
public boolean isButtonPresent(String button){
return selenium.findElementByXpath('//button[@id='+button+']');
}
}

If you run your test now, you will see it do the same thing but we have not 
called the findElement() method available to WebDriver.

In the test we need to initialize the factory by calling initElements():

TestChapter2.java

import org.openqa.selenium.*;
import org.junit.*;
public class TestChapter2 {
WebDriver selenium;

@Before
public void setUp(){
selenium = new FirefoxDriver();
}

@After
public void tearDown(){
selenium.quit();
}
public Chapter2 clickChapter2(){
clickChapter("2");
return PageFactory.initElements(selenium, Chapter2.class);
}

@Test
public void ShouldLoadTheHomePageAndThenCheckButtonOnChapter2() {
selenium.get("http://book.theautomatedtester.co.uk");
HomePage hp = new HomePage(selenium);
Chapter2 ch2 = hp.clickChapter2();
assertTrue(ch2.isButtonPresent("but1"));
}

}

We can seen how we can get rid of a line of code from a constructor or a method
by adding a decorator to the variable. When our code is compiled, the variable will get
populated at the right time so that we can make sure that it gets the right bit of the
DOM. It will look like our element hasn't been instantiated. When we initialize the
PageFactory, by calling initElements() it will populate the variables with the right data.

Sudhakar.Mangi

Sunday 24 August 2014

Design Patterns In Selenium

‹‹ Page Object design
‹‹ Using Page Factory in Page Objects
‹‹ Using Loadable Components

Important preliminary points
In this chapter it will be assumed that all files will have the following import statements:
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

Page Objects
In this section ,we are going to have a look at how we can apply some best practices to tests. You will learn how to make maintainable test suites that will allow you to update tests in seconds. We will have a look at creating your own DSL so that people can see intent. We will create tests using the Page Object Pattern.

Create a new Java class :
1. Import the relevant Selenium Packages.
2. Create the setup() and  teardown()  method. I prefer the JUnit 4 style of tests and
will show code samples with the annotations.
3. We need to check that the page is on the correct page. For this we will use the
selenium.getTitle to see the page title and then if incorrect move to the
chapter 2 link. We do this because navigating to page is slower than checking the
page's title or any other calls to the page already loaded.
4. We need to then validate that it is correct and then work accordingly. The following
is a code snippet of how we can do this:

if (!"Page 2".equals(selenium.getTitle())){
selenium.get(
"http://book.theautomatedtester.co.uk/chapter2");
}

5. Create the rest of the test to check that items are on the page.

Time for action – moving Selenium steps into private methods
to make tests maintainable

Imagine that you just need to test one page on your site and you have quite a few tests
for this page. A lot of the tests will be using the same code over and over again. This can
be quite annoying to maintain if something changes on the page meaning we have to go
through all the tests to fix this one issue

tests as follows:

@Test
public void shouldCheckButtonOnChapter2Page(){
selenium.get("http://book.theautomatedtester.co.uk");
selenium.findElement(By.link, "Chapter2").click();
Assert.assertEqual(selenium.findElements(
By.id"but1").getSize(), 1);
}
@Test
public void shouldCheckAnotherButtonOnChapter2Page(){
selenium.get("http://book.theautomatedtester.co.uk");
selenium.findElement(By.link, "Chapter2").click();
Assert.assertEqual(selenium.findElements(
By.id,"verifybutton").getSize(), 1);

}

Time for action – using the Page Object Pattern to design tests

Imagine that you have a site that has a number of different pages that you need to test. This
is quite common for a number of sites. We can create an object that represents the page and
then pass the Selenium object in the programming language. So let us now create our first
Page Object against the home page.
1. Create a new Java class in IDEA called HomePage.
2. Import the relevant packages for the tests to run.

3. We will now need a constructor to handle Selenium. You may want to make it go to
the home page when it is instantiated too. An example of this can be seen as follows:

HomePage.java

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class HomePage{
WebDriver selenium;
public HomePage(WebDriver selenium){
this.selenium = selenium;
}
public Chapter2 clickChapter2(){
clickChapter("2");
return new Chapter2(selenium);
}
private void clickChapter(String number){
selenium.findElement(By.linkText("Chapter"+number)).click();
}
}

Chapter2.java

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
public class Chapter2 {
WebDriver selenium;
public Chapter2(WebDriver selenium){
this.selenium = selenium;
if (!"Chapter 2".equalsIgnoreCase(
this.selenium.getTitle())){
selenium.get(
"http://book.theautomatedtester.co.uk/chapter2");
}
}
public boolean isButtonPresent(String button){
return selenium.findElements(By.xpath("//input[@id='" +
button + "']")).size()>0;
}
}

BestPractises3.java

import org.junit.After;
import org.junit.Before;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
public class BestPractises3 {
WebDriver selenium;
@Before
public void setUp(){
selenium = new FirefoxDriver();
}
@After
public void tearDown(){
selenium.quit();
}
@Test
public void
ShouldLoadTheHomePageAndThenCheckButtonOnChapter2(){
selenium.get("http://book.theautomatedtester.co.uk");
HomePage hp = new HomePage(selenium);
Chapter2 ch2 = hp.clickChapter2();
assertTrue(ch2.isButtonPresent("but1"));
}
}

If you create these three files you will see it pass. The test is a lot more succinct and
easier to maintain.