Selenium WebDriver – Factory Design Pattern Using Java 8 – Supplier

Overview:

We had already covered about Factory Design Pattern in detail here. If you had not read that before, I would suggest you to check that article first. In this article, We are going to follow slightly a different approach using Java8 lambda expressions. Advantage of using lambda expressions is to write only fewer lines of code & not to create multiple classes.

Supplier:

Java from its version 8 supports lambda expressions by using special type of interfaces called Functional Interfaces. If you are new to Java and would like to be good at it, I would suggest you to spend some time here to explore this area very well. It might look like it is a lot of functional interfaces. Actually It is not. There are only very few basic functional interfaces. Some of them are repeating based on the number of arguments it could accept etc / depends on the data types it would return.

The one which we might be interested in for the factory pattern is called Supplier.  Supplier does not accept any arguments. Whenever it is invoked it returns a new/distinct object whenever it is invoked.  If you look at Java’s functional interfaces list, you could see different types of suppliers like IntSupplier, LongSupplier, BooleanSupplier..etc  They are for supporting java’s primitive data types. Lets ignore them for the time being. We are interested in the supplier which returns an object.

Very simple example of Supplier would be as shown here. Basically we would wrap the object inside a Supplier. Here we always return a hard coded data. But you could add your logic to return new Object you want. hopefully you get idea.

Supplier<String> hi = () -> {
    return "Hi";
};

Supplier<String> hello = () -> {
    return "Hello";
};

Now the important part is how to invoke the above supplier. That is simple. Just invoke the method ‘get’ from the supplier.

System.out.println(hi.get());

The above code prints ‘Hi’.

Driver Factory:

If the above example is clear, then understanding below code would be easier for you.  As you see, I return a new Driver instance here whenever supplier is called!

//chrome driver supplier
Supplier<WebDriver> chromeDriverSupplier = () -> {
    System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
    return new ChromeDriver();
};

//firefox driver supplier
Supplier<WebDriver> firefoxDriverSupplier = () -> {
    System.setProperty("webdriver.gecko.driver", "/Users/username/Downloads/geckodriver");
    return new FirefoxDriver();
};

You might want to add additional suppliers like Safari, IE etc depends on your requirement.

public enum DriverType {
    CHROME,
    FIREFOX,
    SAFARI,
    IE;
}

To avoid if-else / switch statements, I create a map as shown here. Once I have all my suppliers, then I add the suppliers into the map.

public class DriverFactory {

    private static final Map<DriverType, Supplier<WebDriver>> driverMap = new HashMap<>();

    //chrome driver supplier
    private static final Supplier<WebDriver> chromeDriverSupplier = () -> {
        System.setProperty("webdriver.chrome.driver", "/path/to/chromedriver");
        return new ChromeDriver();
    };

    //firefox driver supplier
    private static final Supplier<WebDriver> firefoxDriverSupplier = () -> {
        System.setProperty("webdriver.gecko.driver", "/Users/username/Downloads/geckodriver");
        return new FirefoxDriver();
    };

    //add more suppliers here

    //add all the drivers into a map
    static{
        driverMap.put(DriverType.CHROME, chromeDriverSupplier);
        driverMap.put(DriverType.FIREFOX, firefoxDriverSupplier);
    }

    //return a new driver from the map
    public static final WebDriver getDriver(DriverType type){
        return driverMap.get(type).get();
    }

}

Now your test should be simply written as shown here to get a new WebDriver.

public class SampleBrowserTest {

    private WebDriver driver;

    @BeforeTest
    public void setup(){
        driver = DriverFactory.getDriver(DriverType.CHROME);
    }

    @Test
    public void test1(){
        driver.get("https://www.google.com");
        //your test using webdriver
    }

    @AfterTest
    public void teardown(){
        driver.close();
    }

}

Udemy – Selenium WebDriver and Design Patterns Course:

VinsGuru has released a brand new course in Udemy on Selenium WebDriver and Design Patterns. ~8 hours course with all the important design patterns to design better, reusable page object models, test classes etc. Please access the above link which gives you the special discount.  You can also get your money back if you do not like the course within 30 days.

Summary:

The above code looks cleaner and removes ugly if-else/switch statements. Java8 Supplier also helps us from writing too many classes.

 

Happy Testing & Subscribe 🙂

 

Share This:

12 thoughts on “Selenium WebDriver – Factory Design Pattern Using Java 8 – Supplier

  1. Hi Vinoth,

    Great article, found it really useful. Just a question, I would like to pass some options to the driver object like say for example, chrome options. With the supplier method, how do I pass a chrome options parameter.

    1. ChromeOptions/FireFox options are implementations of Capabilities. Supplier does not accept arguments. Usually supplier itself should have default Capabilities. But if you need more control on creating your capabilities at run time, you need a Function which accepts an argument and return an object. Function. Replace Supplier with a Function and go from there. Idea still remains same.

  2. Hi!

    Great article, really making use of JAVA8 features for the driver factory pattern.
    Have you considered using properties in the enum?

    This way you would get a constant amount of methods (properties number) instead of the number of drivers.

    1. I am not able to get the sample code you had provided due to the formatting. But it is fine. Mostly I am trying to share a high level idea. I leave the rest to reader to figure it out. Yes we could use properties via enum. That would make the code look clean. Thanks.

  3. In order to avoid the supplier methods for each of the drivers, could you implement the Supplier interface directly to the class instead? How would one go about doing that?

    1. Supplier is an interface only. For each driver, we need to implement the interface. Usually we would be creating separate classes. But in Java8, the implementation in lambda style looks like methods

  4. Hi, if the Driver is initialized from the DriverFactory – how would you use it on a PageObject class?

  5. This is by far the best solution I found for driver initialization. I did change that static block and Map are not static to avoid driver to be static and I call it by creating static instance variable eg. private static final TestDriver instance = new TestDriver(); This is really refreshing after cumbersome if/else statements. I purchased two of your Udemy courses and both are great, any chance of some tutorial about Consumer and Biconsumer usage in Selenium?
    Thanks :))

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.