Program to an interface with Selenium WebDriver (eBook)

pexels-photo-755834.jpeg

Be Flexible With Java Interfaces – Pexels.com

 

Anyone can write code that a computer can understand.
Good programmers write code that humans can understand.

Martin Fowler

 

Testers and developers use the Selenium WebDriver library for implementing test automation for various websites.

They use Selenium WebDriver for its major purpose: to interact with a site in the browser.

 

But I believe that there is something else that we can use this library for.

We can use it to learn how to write good code.

Code that is easy to maintain.

Easy to extend, easy to use and understand.

 

What can you learn from the Selenium WebDriver code?

 

You can learn how to apply programming concepts such as factories.

Or how to extend code instead of modifying it with decorators.

Or how program to an interface.

 

Programming to an interface is the focus here.

 

What does it mean?

 

It means two things:

1. each class that you create should implement an interface

2. every time an object of the class is created, its type should be the interface that the class implements

 

This sounds pretty abstract so lets see if an example makes things simpler.

 

This is the example provided for interfaces in the java documentation.

In its most common form, an interface is a group of related methods with empty bodies.

A bicycle’s behavior, if specified as an interface, might appear as follows:

 

interface Bicycle {

  void changeCadence(int newValue);

  void changeGear(int newValue);

  void speedUp(int increment);

  void applyBrakes(int decrement);
}

 

To implement this interface, the name of the class would change to a particular brand of bicycle and you’d use the implements keyword in the class declaration.

The class would also have to provide an implementation for each method defined by the interface.
class TrekBicycle implements Bicycle {

  int cadence = 0;
  int speed = 0;
  int gear = 1;

  void changeCadence(int newValue) {
    cadence = newValue;
  }

  void changeGear(int newValue) {
    gear = newValue;
  }

  void speedUp(int increment) {
    speed = speed + increment;
  }

  void applyBrakes(int decrement) {
    speed = speed - decrement;
  }

  void printStates() {
    System.out.println("cadence:" +
      cadence + " speed:" +speed + " gear:" + gear);
 }

}

 

Implementing an interface allows a class to become more formal about its behavior.

If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.

 

What is so special about a class implementing an interface?

 

When you create an object of the class, you can do it in 2 different ways:

TrekBicycle trekBike = new TrekBicycle();
Bicycle trekBike = new TrekBicycle();

 

The second way of creating the object provides a lot of flexibility in dealing with all bicycle objects .

If you have an additional Bicycle class, for example

class GTBicycle implements Bicycle {

  int cadence = 0;
  int speed = 0;
  int gear = 1.25;

  void changeCadence(int newValue) {
    cadence = newValue;
  }

  void changeGear(int newValue) {
    gear = newValue * 1.1;
  }

  void speedUp(int increment) {
    speed = speed + increment + 1.2;
  }

  void applyBrakes(int decrement) {
    speed = speed - decrement;
  }

  void printStates() {
    System.out.println("cadence:" +cadence + " speed:" +
   speed + " gear:" + gear);
  }

}


an object of the GTBicycle class can also be saved in a Bicycle variable:

Bicycle gtBike = new TrekBicycle();

 

Any object of a class than implements the Bicycle interface can be saved in a Bicycle variable.

 

Where have we seen this with Selenium WebDriver?

 

You can see interfaces everywhere:

 

1. When creating a driver object

A driver object for the Chrome browser is created as follows

WebDriver driver = new ChromeDriver();

 

WebDriver is an interface while ChromeDriver is a class that extends RemoteDriver which implement WebDriver.

 

To create a driver for Firefox, we just change the class name:

WebDriver driver = new FirefoxDriver();

Same for the driver for Edge:

WebDriver driver = new EdgeDriver();

 

2. When finding a web element

WebElement button = driver.findElement(locator);

 

WebElement is an interface.

For this reason, you can save in a WebElement variable any type of html element: button, link, label, image, list, textbox, etc.

 

3. When typing a keyword in a textbox

All of the following ways of typing a keyword in a textbox work:

a. type a String value

WebElement searchBox = driver.findElement(textBoxId);
String keyword = "symphony";
searchBox.sendKeys(keyword);

 

b. type a StringBuilder value

WebElement searchBox = driver.findElement(textBoxId);
StringBuilder author = new StringBuilder()
                          .append("wolfgang")
                          .append(" ")
                          .append("amadeus")
                          .append(" ")
                          .append("mozart");

searchBox.sendKeys(author);

 

c. type a StringBuffer value

WebElement searchBox = driver.findElement(textBoxId);
StringBuffer topic = new StringBuffer().append("classical")
                                       .append(" ")
                                       .append("music");

searchBox.sendKeys(author);

 

d. type a String, a StringBuilder, a StringBuffer and a key

WebElement searchBox = driver.findElement(searchBoxId);
StringBuilder author = new StringBuilder()
                         .append("wolfgang")
                         .append(" ")
                         .append("amadeus")
                         .append(" ")
                         .append("mozart");

String space = " ";
StringBuffer topic = new StringBuffer()
                         .append("classical")
                         .append(" ")
                         .append("music");

String subTopic = "symphony";

searchBox.sendKeys(author, space, topic, space, subTopic, Keys.TAB);

 

Why do all these different ways of typing a keyword work?

 

It looks as if sendKeys may have one or more parameters and they can have different types: String, StringBuilder, StringBuffer, Keys.

The sendKeys signature explains it all:
void sendKeys(CharSequence... keysToSend)

 

The … explains why you can have one or more parameters.
… means that sendKeys can have a variable number of parameters of the same type.
All parameters must have the CharSequence type.

 

CharSequence explains why we can have so many classes as parameter types for sendKeys.

 

CharSequence is an interface in Java that is implemented by classes such as String, StringBuilder and StringBuffer.

This means that you can use any object of the String, StringBuffer and StringBuilder classes as a CharSequence variable.

 

What about Keys?

Keys is a Selenium enumeration which implements as well the CharSequence interface.

What should we learn from all this?

A few things …

1. Each class that we create should implement an interface.

2. When creating an object of the class, use the interface as its type.

 

How can you use interfaces in a Selenium project?

 

If you are interested in seeing how “programming to an interface” is done in a Selenium WebDriver project step by step, I have an ebook for you.

 

It will show you how to change code that does not use interfaces so that it follows the “programming to an interface” principle.

 

The result of applying this principle is that we will be able to replace 10 automated scripts that search for different categories (car, minivan, boat, rv, etc) with one script.

So, instead of having a search test for each category

public class TestClass {

   CarInfo carInfo = new CarInfo("audi", "a4");

   MinivanInfo minivanInfo = new MinivanInfo("nissan","navara", "pickup");

   BikesInfo bikesInfo = new BikesInfo(
                             "kawasaki", "gpz1000", "sports tourer");

   @Test
   public void canSearchForCars() {

     CarHome homePage = new CarHome();
     homePage.open();

     CarResults resultsPage = homePage.searchFor(carInfo);
     assertTrue(resultsPage.count() > 0);

   }

   @Test
   public void canSearchForMinivans() {

     MinivanHome homePage = new MinivanHome();
     homePage.open();

     MinivansResults resultsPage = homePage.searchFor(minivanInfo);
     assertTrue(resultsPage.count() > 0);

  }

  @Test
  public void canSearchForBikes() {

     BikesHome homePage = new BikesHome();
     homePage.open();

     BikesResults resultsPage = homePage.searchFor(bikesInfo);
     assertTrue(resultsPage.count() > 0);

  }


}

 

you can have

public class TestClass {

  String postalCode = "w1f7tu";

  @DataProvider(name = "vehicleInfo")
  public Object[][] vehicleInfo() {
    return new Object[][] {
      { "cars" , new CarInfo("BMW", "3 SERIES") },
      { "minivans", new MinivanInfo("NISSAN", "NAVARA", "Pickup")},
      { "bikes" , new MotorHomesInfo("AUTO-SLEEPERS", "2")},
    };
  }

  @Test(dataProvider = "vehicleInfo")
  public void canSearchForCategory(String category,
                                   VehicleInfo vehicleInfo) {

     HomePage homePage = openHomePage(category);
     homePage.open();

     ResultsPage resultsPage = homePage.searchFor(
                                     vehicleInfo, postalCode);
     assertTrue(resultsPage.count() > 0);
  }

}

 

Interested?

 

Send USD 15 to alex@alexsiminiuc.com through Paypal.
I will email you the book and answer all your questions about it, also by email.

 

Leave a comment