Tuesday, February 18, 2020

Selenium WebDriver – Singleton DriverFactory Design Pattern Using Java 8

WebApplication Singleton driver Factory Design Pattern :


Mobile Singleton driver Factory Design Pattern :
  • AppiumServerJava : is used to customize the url and desirecapabilities 
  • CreateDriver     : is to create LocalThread instance 


Package Runner;

import java.io.IOException;

import java.net.MalformedURLException;

import java.net.URL;

import org.apache.log4j.Logger;

import org.apache.log4j.xml.DOMConfigurator;

import org.apache.commons.cli.CommandLine;

import org.apache.log4j.Logger;

import org.openqa.selenium.WebDriver;

import org.openqa.selenium.remote.DesiredCapabilities;

import org.openqa.selenium.remote.RemoteWebDriver;

import org.testng.annotations.BeforeClass;

import org.testng.annotations.BeforeSuite;

 

import io.appium.java_client.android.AndroidDriver;

import io.appium.java_client.remote.AndroidMobileCapabilityType;

import io.appium.java_client.remote.MobileCapabilityType;

import io.appium.java_client.remote.MobilePlatform;

import io.appium.java_client.service.local.AppiumDriverLocalService;

import io.appium.java_client.service.local.AppiumServiceBuilder;



public class AppiumServerJava {

       private static DesiredCapabilities cap;

       public static AndroidDriver driver;

       public static AppiumServiceBuilder builder = null;

       static AppiumDriverLocalService service = null;

         private static Logger Log = Logger.getLogger(AppiumServerJava.class);

 

//     @BeforeSuite

       public static DesiredCapabilities AppiumServerCapabilities() {

              DOMConfigurator.configure(System.getProperty("user.dir") + File.separator + "log4j.xml");

              Log.debug("This is debug message ");

              Log.info("desire capabilities initized");

              File appDir = new File(System.getProperty("user.dir") + "/src/test/java/appStore/");

              File app = new File(appDir, "Flipkart Online Shopping App_v6.17_apkpure.com.apk");

              Log.info(app + "_____");

              cap = new DesiredCapabilities(); // Cabaliliesties for server

              cap.setCapability("noReset", "false");

//            cap.setCapability(MobileCapabilityType.BROWSER_NAME, "Android");

              cap.setCapability(MobileCapabilityType.UDID, "4200cab8de3b747f"); // Give Device ID of your mobile phone

              cap.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());

              cap.setCapability(MobileCapabilityType.DEVICE_NAME, "Galaxy On Max");

              cap.setCapability(MobileCapabilityType.PLATFORM_NAME, MobilePlatform.ANDROID);

              cap.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, "com.flipkart.android");

              cap.setCapability("appActivity", "com.flipkart.android.SplashActivity");

              builder = new AppiumServiceBuilder().withCapabilities(cap);

              DesiredCapabilities capClient = new DesiredCapabilities(); // Capabilities for client

              return cap;

       }


       public static String getURL() {

              AppiumServerCapabilities();

              service = builder.build();

              Log.info("appium service started ");

              service.start();

              Log.error(service.getUrl().toString());

              return service.getUrl().toString();

       }


    }

public class CreateDriver extends AppiumServerJava{

private static Logger Log = Logger.getLogger(CreateDriver.class);




       private static final ThreadLocal<AndroidDriver> mobileDriver = new ThreadLocal<AndroidDriver>();

       private URL serverUrl = null;



/*

        * Method to create local driver

        * @param capabilities

        * @param testBedConfig

        */

      

       public void createLocalDriver(){

//            AndroidDriver driver = null;

              try {

                      serverUrl = new URL(AppiumServerJava.getURL());

                      Log.info("createLocalDriver ::: serverUrl:::"+serverUrl);

              } catch (MalformedURLException e) {

                      e.printStackTrace();

              }

              try{

                      driver = new AndroidDriver(serverUrl, AppiumServerJava.AppiumServerCapabilities());

                     driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

                      setDriver(driver);

              }catch(Exception ex){

                      Log.error("Error while createLocalDriver:::"+ex.getMessage());

                      ex.printStackTrace();

              }

       }

      

       /**

        * Method to get driver

        * @param capabilities

        * @param testBedConfig

        * @return

        */

       @BeforeSuite

       public AndroidDriver getDriverAndroid(){

//            AndroidDriver driver = null;

              if(mobileDriver.get()==null){

                      createLocalDriver();

              }

              return mobileDriver.get();

       }

      

       /**

        * Method to set driver

        * @param localDriver

        */

       public void setDriver(AndroidDriver localDriver){

              mobileDriver.set(localDriver);

       }

      

       /**

        * Method to get driver

        * @return

        */

       public static AndroidDriver getDriver(){

              return driver =mobileDriver.get();

       }

}




2 .  Singleton driver Factory Design Pattern :

//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();
};
Copy
You might want to add additional suppliers like Safari, IE etc depends on your requirement.
public enum DriverType {
    CHROME,
    FIREFOX,
    SAFARI,
    IE;
}
Copy
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();
    }
 
}
Copy
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();
    }
 
}


3.   Driver Factory using Maven  dependency



 <dependency>
    <groupId>ru.stqa.selenium</groupId>
    <artifactId>webdriver-factory</artifactId>
    <version>4.4</version>
</dependency>
<dependency>
    <groupId>org.seleniumhq.selenium</groupId>
    <artifactId>selenium-java</artifactId>
    <version>3.141.59</version>
</dependency>
 


The library provides three ways to manage instances:
  • SingleWebDriverPool allows a single managed instance of WebDriver to exist at any given moment,
  • ThreadLocalSingleWebDriverPool allows a single managed instance of WebDriver to exist for each thread,
  • LooseWebDriverPool does not impose any restrictions, it creates a new managed instance on each request.
You can use as many separate pools as you like, but there is also WebDriverPool.DEFAULT that is an instance of ThreadLocalSingleWebDriverPool.



import ru.stqa.selenium.factory.WebDriverPool;
 
 
// adding desirecapabilities;
@BeforeEach public void initDriver() throws Throwable { 
       driver = WebDriverPool.DEFAULT.getDriver(gridHubUrl, capabilities); 
}
 
// Start Browser :
@BeforeMethod public void startBrowser() { 
       driver = WebDriverPool.DEFAULT.getDriver(DesiredCapabilities.firefox());
 }
 
 
@Test
public void testSomething() {
  WebDriver driver = WebDriverPool.DEFAULT.getDriver(new FirefoxOptions());
  // do something with the driver
  driver.get("http://seleniumhq.org/");
}
 
@Test
public void testSomethingElse() {
  WebDriver driver = WebDriverPool.DEFAULT.getDriver(new ChromeOptions());
  // do something with the driver
  driver.get("http://seleniumhq.org/");
}
 
@AfterSuite
public void stopAllDrivers() {
  WebDriverPool.DEFAULT.dismissAll();
}







4.   




Monday, February 17, 2020

Cucumber (BDD framework ) for maven project for login using Java

Why Use Cucumber-Selenium?

Cucumber is an open source tool that supports Behavior Driven Development (BDD) framework. It provides the facility to write tests in a human readable language called Gherkin. The Selenium-Cucumber framework supports programming languages such as Perl, PHP, Python, .NET, Java, etc.
In this blog, we will focus on how to set up Selenium with Cucumber using Maven, and also learn to write feature files using Gherkin, execution, and generating HTML reports.

Prerequisites To Set Up Cucumber

In order to install Cucumber on your system, you would need some basic installations on your system:
  1. Set up JDK on your system (JDK 1.8 or the latest version)
  2. Install Eclipse (Eclipse OXYGEN or the latest version)
  3. Install Cucumber plugin:
    • In Eclipse, go to Help → Install new software
    • On the Available Software popup, enter the URL “ http://cucumber.github.com/cucumber-eclipse/update-site ” in the Work with field.

      1
    • You will see “Cucumber Eclipse Plugin” displayed in the filter; select the checkbox and click Next, and you will navigate to the Install Details popup. Click Next to proceed further.
    • Accept the license in the Review License pop-up and click Finish.

Why Maven?

Maven is a automation build tool and is widely used for Java projects. It is mainly used in managing dependencies through pom.xml. Suppose you want to upgrade the JAR files and in your project you are using version 1.25 for Cucumber-Java dependency. You need to upgrade to the latest version. With the use of Maven, it’s easy to upgrade the version.

Set Up Your Maven Project

Step 1: To create a Maven Project in Eclipse, click on New → Project → In the wizard, select Maven Project.
2

Step 2: Now, in order to build a Selenium-Cucumber framework for us to work with, we need to add dependency for Selenium and Cucumber in pom.xml, which is somewhat similar to adding JAR files. We will be needing dependencies of the following: 
Selenium-java
Cobertura
Cucumber-jvm-deps
Cucumber-reporting
Gherkin
JUnit
Mockito-all-1.10.19
Cucumber-core
Cucumber-java
Cucumber-junit


POM.XML file 
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.7.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.7.0</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-java</artifactId>
<version>1.2.5</version>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-jvm-deps</artifactId>
<version>1.0.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>info.cukes</groupId>
<artifactId>cucumber-junit</artifactId>
<version>1.2.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.vimalselvam</groupId>
<artifactId>cucumber-extentsreport</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.aventstack</groupId>
<artifactId>extentreports</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
</project>

Note: You may need to install the Cucumber Eclipse Plugin for this to work. Goto -- Helps->Install New Software->copy paste the link http://cucumber.github.io/cucumber-eclipse/update-site/ and install



Now, create feature file in the 'Features' folder with the name of "MyTest.feature" - Process is similar to creating a folder
 'MyTest.feature' file 
Feature: Reset functionality on login page of Application Scenario: Verification of Reset button Given Open the Firefox and launch the application When Enter the Username and Password Then Reset the credential
Runner.java

package TestRunner;
import org.junit.runner.RunWith;  
import cucumber.api.CucumberOptions;  
import cucumber.api.junit.Cucumber;  

@RunWith(Cucumber.class)    
@CucumberOptions(features="Features",glue={"StepDefinition"})      
public class Runner     
{  

}

'StepDefinition' package
package StepDefinition; import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When; public class Steps {
@Given("^Open the Firefox and launch the application$")
public void open_the_Firefox_and_launch_the_application() throws Throwable
{
System.out.println("This Step open the Firefox and launch the application.");
} @When("^Enter the Username and Password$")
public void enter_the_Username_and_Password() throws Throwable
{
System.out.println("This step enter the Username and Password on the login page.");
} @Then("^Reset the credential$")
public void Reset_the_credential() throws Throwable
{
System.out.println("This step click on the Reset button.");
} }

Create HTML Reports In Cucumber

Imagine that you have to share the test reports with your client and senior management; in that case you will need a shareable HTML report which you can share after executing your tests.
You can achieve this by following some very simple steps.

Create An HTML Report By Adding A Plugin To Testrunner.Java Class

Step 1: In your testrunner.java class, add a plugin inside @CucumberOptions to format your test results into the HTML format.
plugin = { "pretty", "html:target/htmlreports" }
In order to set the path for the reports, we have to give a path in the project. To make this easier, the path is target/htmlreports.
Step 2: Now save the testrunner.java class and execute it. On execution, you will see that the folder htmlreports is created inside the target folder.
Step 3: Access the folder and look for the index.html file; that is the file which contains the test results in HTML format.
11
Step 4: Open the index.html to view the report. The report created would be similar to the image below.
12

Create HTML Report By Using Extent-Reports

We have already seen how to create an HTML test report, but with the help of extent reports we can create more well-organized and detailed reports.
Step 1: To implement extent report, we need to add two dependencies to the pom.xml and update the project after adding the dependency.
Cucumber-extentsreport
extentreports
The dependencies for the above would be like this:
<dependency>
    <groupId>com.vimalselvam</groupId>
    <artifactId>cucumber-extentsreport</artifactId>
    <version>3.0.2</version>
   </dependency>

    <dependency>
    <groupId>com.aventstack</groupId>
    <artifactId>extentreports</artifactId>
    <version>3.1.2</version>
   </dependency>

Step 2: Add a new folder to the project. Eg. “config” by right clicking the project folder → New → Folder → Config. Now we have to add an XML file to this folder. This XML file states the theme of the report, title, etc. The report.xml file would be like this:

<?xml version="1.0" encoding="UTF-8"?>
<extentreports>
  <configuration>
    <!-- report theme --> <!-- standard, dark -->
    <theme>standard</theme>
  
    <!-- document encoding -->  <!-- defaults to UTF-8 -->
    <encoding>UTF-8</encoding>
    
    <!-- protocol for script and stylesheets -->   <!-- defaults to https -->
    <protocol>https</protocol>
    
    <!-- title of the document -->
    <documentTitle>Selenium Cucumber Framework</documentTitle>
    
    <!-- report name - displayed at top-nav -->
    <reportName>Functional Testing report</reportName>
    
    <!-- global date format override -->  <!-- defaults to yyyy-MM-dd -->
    <dateFormat>yyyy-MM-dd</dateFormat>
    
    <!-- global time format override -->   <!-- defaults to HH:mm:ss -->
    <timeFormat>HH:mm:ss</timeFormat>
    
    <!-- custom javascript -->
    <scripts>
      <![CDATA[
        $(document).ready(function() {
        
        });
      ]]>
    </scripts>
    
    <!-- custom styles -->
    <styles>
      <![CDATA[
        
      ]]>
    </styles>
  </configuration>
</extentreports>

Step 3: Now we are almost ready with the setup required for the report, but in order to fetch the report for every test, we need to add a plugin in testrunner.java and add an @AfterClass. In the plugin, we will mention the Extent formatter and the location where we want the report to be saved, and in the after class, we will write a function to load the report.xml. The final testrunner.java class would be like this:
package Runner;

import java.io.File;

import org.junit.AfterClass;
import org.junit.runner.RunWith;

import com.cucumber.listener.ExtentCucumberFormatter;
import com.cucumber.listener.Reporter;

import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;

@RunWith(Cucumber.class)
@CucumberOptions(
        features ="src/test/java/features"
        ,glue= "seleniumgluecode",
        plugin = { "com.cucumber.listener.ExtentCucumberFormatter:target/cucumber-reports/report.html"}, 
        monochrome = true
                )

public class testrunner {
    @AfterClass
    public static void writeExtentReport() {
        Reporter.loadXMLConfig(new File("config/report.xml"));
    
    }
}

Step 4: On executing the tests, a new folder will be created at the path mentioned in the plugin. Open the folder and open the report.html.

13
The report created will have a heading, graph of the test results, detailed results for all features executed, and you can also filter the test results with the status Pass/Fail by clicking the Status menu.
14

Command Line Execution

Executing your Cucumber tests from Eclipse is very easy, but you can also execute them through the command line. The steps to execute the tests through the command line are as follows:
  1. Open the terminal in your system and navigate to your project directory.
  2. Since we have already added a Maven dependency through pom.xml, we can execute the test using the simple command mvn test
  3. In case you have a large number of feature files added to your project, and you only want to execute a smoketest.feature file, you can use the command mvn test -Dcucumber.options=”src/test/java/Features/smoketest.feature.