DriverFactory with Java functional interface
In this blog, lets see how to use Java functional interface with lambda to create a driverfactory. This is slightly advanced coding, so it will be nice to have a basic knowledge of Java functional interface, how to use lambda to implement the interface etc.
Case Study
Lets automate the scenario: Open gmail.com in any browser e.g. chrome or firefox, find all the links on the page and store all the links with “s” in the link name.
For this we will use
– Functional interface with lambda implementation
– bonigarcia/webdrivermanager
– Java Stream
For this use case we will use the IntelliJ. Let’s start with a maven project and add the dependencies in pom.xml file and build the project to download the libraries
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>SeleniumDriverFactory</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>3.141.59</version> </dependency> <!-- https://mvnrepository.com/artifact/io.github.bonigarcia/webdrivermanager --> <dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>4.4.3</version> </dependency> <!-- https://mvnrepository.com/artifact/org.testng/testng --> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>7.4.0</version> <scope>test</scope> </dependency> </dependencies> </project>
DriverFactory.java
DriverFactory class to supply the WebDrivers but this with the help of Supplier Functional interface and bonnigarcia libraries
package com.driversupplier; import io.github.bonigarcia.wdm.WebDriverManager; import org.openqa.selenium.WebDriver; import org.openqa.selenium.chrome.ChromeDriver; import org.openqa.selenium.firefox.FirefoxDriver; import java.util.HashMap; import java.util.Map; import java.util.function.Supplier; public class DriverFactory { public static final Supplier<WebDriver> CHROMESUPPLIER = () -> { WebDriverManager.chromedriver().setup(); return new ChromeDriver(); }; public static final Supplier<WebDriver> FIREFOXSUPPLIER = () -> { WebDriverManager.firefoxdriver().setup(); return new FirefoxDriver(); }; public static final Map<String, Supplier<WebDriver>> MAP = new HashMap<>(); static { MAP.put("chrome", CHROMESUPPLIER); MAP.put("firefox", FIREFOXSUPPLIER); } public static WebDriver getDriver(String browser) { return MAP.get(browser).get(); } }
Lets understand the code snippet
public static final Supplier<WebDriver> CHROMESUPPLIER = () -> {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
};
Supplier is a functional interface which has a single abstract method i.e. get() and it does not accept any argument but returns a type, in this case WebDriver. To know more about Supplier click here.
So DriverFactory.java supplies the WebDriver based on the browser type parameter passed in the TestCase. You can also add supply more drivers such IE, Edge etc.
What is this ” WebDriverManager.chromedriver().setup(); “?
If you remember we have added a dependency in pom.xml
<dependency> <groupId>io.github.bonigarcia</groupId> <artifactId>webdrivermanager</artifactId> <version>4.4.3</version> </dependency>
This takes care of driver management during run time. If you see we have not downloaded chrome and firefox drivers and stored in local and also there is no System.setProperty as well. You can find the details here.
Compare this DriverFactory.java with the WebDriverBase.java that we have written for Springboot blog. In springboot blog we have used switch case and setProperty to intialize the driver.
TestCase: GmailLinkTest.java
package com.test; import com.driversupplier.DriverFactory; import org.openqa.selenium.By; import org.openqa.selenium.WebDriver; import org.testng.annotations.*; import java.util.ArrayList; import java.util.List; public class GmailLinkTest { private WebDriver driver; @BeforeTest @Parameters("browser") public void setDriver(@Optional("chrome") String browser) { //get the driver based on the parameter passed. In this case its 'chrome' this.driver = DriverFactory.getDriver(browser); } @Test public void gmailTest() throws InterruptedException { //Create a list to store the link name with s in it List<String> myList = new ArrayList<>(); this.driver.get("https://www.gmail.com/"); //Open gmail.com Thread.sleep(10000); //pause for 10 seconds //Notice the code from here //It finds list of elements with By.tagName(a) then uses the stream to filter the list having text s in the name //Then add it to the list //This also can be achieved with the help of if then else and for loop. But the below code will show case that //you know advance java concepts and also it helps you to write the clean code this.driver.findElements(By.tagName("a")) .stream() .filter(e -> e.getText().toLowerCase().contains("s")) .forEach((s) -> { myList.add(s.getText()); }); //Now lets print the list myList.forEach(s -> System.out.println(s)); } @AfterTest public void afterTest() { //Quit the browser this.driver.quit(); } }
In the test case, the browser type is hard coded (generally we take it from testng.xml file) but this is an example to show the power of functional interface, lambda and stream.
Project Structure in IntelliJ