BDD Framework for Mobile Applications Automation with Appium

BDD Framework for Mobile Applications Automation with Appium

Introduction

Cucumber is a testing framework which supports Behaviour Driven Development (BDD).

It defines application behavior in plain meaningful English text using a simple grammar defined by a language called Gherkin.

Procedure to setup cucumber framework:-

  • Download and install java
  • Install Eclipse
  • Create a java project(Ex:-BDD_Demo)
  • Associate(=> In Eclipse >> Right-click on the project folder >> Properties >> Java Build Path >> Add External JARs) below mentioned cucumber jar files to the project in Pom file as Maven Dependancy
1. Cucumber Core - Cucumber JVM: Core 
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-core -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-core</artifactId>
    <version>1.2.5</version>
</dependency>
2. Cucumber-HTML - A cross-platform HTML formatter for all the Cucumber implementations.
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-html -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-html</artifactId>
    <version>0.2.6</version>
</dependency>
3. Cucumber Java -Cucumber Jvm
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-java -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>1.2.5</version>
</dependency>
4. Cucumber JUnit
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-junit -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>1.2.5</version>
    <scope>test</scope>
</dependency>
5. Cucumber JVM Dependencies
<!-- https://mvnrepository.com/artifact/info.cukes/cucumber-jvm-deps -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>cucumber-jvm-deps</artifactId>
    <version>1.0.5</version>
    <scope>provided</scope>
</dependency>
6. Gherkin - Pure Java Gherkin
<!-- https://mvnrepository.com/artifact/info.cukes/gherkin -->
<dependency>
    <groupId>info.cukes</groupId>
    <artifactId>gherkin</artifactId>
    <version>2.12.2</version>
    <scope>provided</scope>
</dependency>
7. Hamcrest 
<!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all -->
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>
8. JUnit
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
</dependency>

Also, if you are working on mobile automation associate the following Selenium & Appium Jars to the java project: Selenium jar

Selenium Server Standalone jar

Appium Java client for Appium Mobile WeDriver
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
    <groupId>io.appium</groupId>
    <artifactId>java-client</artifactId>
    <version>5.0.4</version>
</dependency>

Project Structure (Packages and respective class files)

- Create a Driver package under the above java project(src/test/java) and create a runner class (Ex: runner.java)(which will basically help to invoke “feature file” which in-turn would interact with step definition file created in the below steps).
- Create a stepdefination.java class in the same Package (this class will have the java code).
- Create another Testcasespackage in the name of src/test/resources
- Create a feature file (Ex:-MyFeatures.feature) [Feature File should be created with (extension.feature)
- Steps to create a feature file: Right-click on the package(Testcases)--> select option File & name your feature file)] under Testcases package

Execution Flow:

Runner class  >>  Feature file  >> Step Definition

What is Cucumber Feature File?

  • Feature File is an entry point to the Cucumber tests.
  • This is the file where you will describe your tests in Descriptive(gherkin) language (like English).
  • It is an essential part of Cucumber, as it serves as an automation test script as well as the live document.
  • A single feature file can contain one or many scenarios

Sample Feature File:

Feature: working with zoo site

Scenario: 
login to the zoo website
Given navigate to the zoo
When clicking on "contact_link"
Then check title is of "Contact"
And close the browser

Scenario: 
check title
Given navigate to the zoo
When clicking on "adoption_link"
Then check title is of "Adoption
And close the browser

Keywords:

Now moving forward we have just defined a test. You will notice colored part of the tests (Feature, Scenario, Given, When, And and Then). These are keywords defined by Gherkin.

Feature: Defines what feature you will be testing in the tests below
Scenario: Defines the scenario that you will test
Given: Tells the pre-condition of the test
When:  Defines the condition of the test
And: Defines additional conditions of the test
Then: States the postcondition. You can say that it is an expected result of the test.

What is Step Definition File?

A Step Definition is a java method in a class/file with an annotation(like: @Given, @When, @then, etc) attached to it, followed by the pattern(like: "^click on \"([^\"])\"$"). This pattern is used to link the Step Definition to all the matching (gherkin)Steps => this code is what Cucumber would execute when it sees a Gherkin Step. Cucumber finds the Step Definition file with the help of Glue code in Cucumber Options.*

Sample Step Definition File Code:

package cucumbersecond.feature;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import cucumber.api.java.en.And;
import cucumber.api.java.en.Given;
import cucumber.api.java.en.Then;
import cucumber.api.java.en.When;
import junit.framework.Assert;
public class secondsteps{

      WebDriver driver =null;
      @Given("^navigate to zoo$")
      public void navigate_to_zoo() throws Throwable{
              driver = new FirefoxDriver();
              driver.get("http://thetestroom.com/webapp/");
      }
      @When("^click on \"([^\"]*)\"$")
      public void click_on(String link) throws Throwable{
             driver.findElement(By.id(link)).click();
      } 
      @Then("^check title is of \"([^\"]*)\"$")
      public void check_title_is_of(String title) throws Throwable{
             String var=driver.getTitle();
             System.out.println(var);
             Assert.assertTrue("title does not match", 
             driver.getTitle().equals(title));
      }
      @And("^close the browser$")
      public void close_the_browser() throws Throwable{
          driver.close();
       }
       }

Note:- Cucumber starts it’s execution by reading the feature file steps. As soon as Cucumber reaches the first step for e.g. Given statement of a Scenario, it looks for the same statement in the Step Definition file, the moment it finds the statement, it executes that piece of code written inside the function.

Cucumber Runner Class:

This class will set up the interaction between the feature file and step definition file. Sample Cucumber Runner class code:

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

@RunWith(Cucumber.class)
@CucumberOptions( plugin = {"pretty","html:target/html/"}, features = {"src/Cucumber/"},
tags ={"@sendmail"})
public class CucumberRunner
{ }

What is Cucumber Options?

In layman language @CucumberOptions are like property files or settings for your test. @CucumberOptions enables us to do all the things that we could have done if we have used the cucumber command line. This is very helpful and of utmost importance, if we are using IDE such as eclipse only to execute our project.

Parametrization: Parametrization in cucumber is basically done when you have the same scenario but few events are changing, to perform parametrization in cucumber, enter the keyword(event) in double-quotes.

Below mentioned is the sample feature file and step definition file when parametrization is performed.

Sample Feature File:-
Feature: working with zoo site
Scenario: login to the zoo website
    Given navigate to the zoo
    When clicking on "contact_link"
    Then check title is of "Contact"
    And close the browser
Scenario: check the title
    Given navigate to the zoo
    When clicking on "adoption_link"
    Then check title is of "Adoption"
    And close the browser

Sample Step Definition File:-
@When("^click on \"([^\"]*)\"$")
public void click_on(String link) throws Throwable
    {
       driver.findElement(By.id(link)).click();
    }
@Then("^check title is of \"([^\"]*)\"$")
public void check_title_is_of(String title) throws Throwable
    {
       String var=driver.getTitle();
       System.out.println(var);
       Assert.assertTrue("title does not match", 
       driver.getTitle().equals(title));
    }

Auto-generating the Setup Definition File:

  • In a scenario if any word is parametrised (specified "double quotes") then, that keyword should be in the form of regex script in the step-definition file.
  • For each such statement added into the feature file, there corresponding dummy java (Step definition)methods can be generated (in the console) by just executing the "Runner" class
  • This auto-generated dummy java (Step definition)methods should then be added back to the step definition file Java file.

Data Table:

Data Tables are handy for passing a list of values to a step definition: E.g. In a scenario, if you want to enter the data in a few fields you can go ahead with below example

Sample Feature File:-
Scenario: Login to Gmail and compose mail
Given Login into Gmail
When click on compose
When Enter "Field" and "Value" details
 | Field        | Value              |
 | to           | test@yahoo.in   |
 | subject     | test email        |
 | body        | This is body      |
 Then click on send option

To Make use of data table in the step definition file, please go through sample code:-

Sample Step Definition File:-
@When("^Enter to address and subject$")
public void enter_to_address_and_subject(DataTable table) throws Throwable  
{
System.out.println("Entered into data table");
List<List<String>> data = table.raw();
System.out.println(data.get(1).get(1));
driver.manage().timeouts().implicitlyWait(50,TimeUnit.SECONDS);           driver.findElement(By.name("to")).sendKeys(data.get(1).get(1));
driver.findElement(By.name("to")).sendKeys(Keys.SPACE);          driver.findElement(By.name("subjectbox")).sendKeys(data.get(2).get(1) driver.findElement(By.id(":pc")).sendKeys(data.get(3).get(1));
}

Scenario Outline:

The Scenario Outline keyword can be used to run the same Scenario multiple times, with different combinations of values. The keyword Scenario Template is a synonym of the keyword Scenario Outline. Copying and pasting scenarios to use different values quickly becomes tedious and repetitive Scenario outlines allow us to more concisely express these scenarios through the use of a template with < >-delimited parameters:

Scenario Outline: eating
  Given there are <start> cucumbers
  When I eat <eat> cucumbers
  Then I should have <left> cucumbers

  Examples:
    | start | eat | left |
    |    12 |   5 |    7 |
    |    20 |   5 |   15 |

A Scenario Outline must contain an Examples (or Scenarios) section. Its steps are interpreted as a template which is never directly run. Instead, the Scenario Outline is run once for each row in the Examples section beneath it (not counting the first header row).

The steps can use <> delimited parameters that reference headers in the examples table. Cucumber will replace these parameters with values from the table before it tries to match the step against a step definition.

Sample Step definition file for Scenario outline:-
@When("^I enter Username as \"([^\"]*)\" and Password as \"([^\"]*)\"$")
public void I_enter_Username_as_and_Password_as(String arg1, String arg2) {
 driver.findElement(By.id("email")).sendKeys(arg1);
 driver.findElement(By.id("pass")).sendKeys(arg2);
 driver.findElement(By.id("u_0_v")).click();
}

From Above mentioned example, you will come to know that First entire scenario will be executed for "username1" and "Password1", Then again the same Scenario will get executed for "username2" and "Password2"

Scenario Hooks:-

Cucumber provides several hooks which allow us to run blocks at various points in the Cucumber test cycle. Below mentioned are the most common hooks used.

@Before: Before hooks will run before the first step of each scenario. They will run in the same order of which they are registered.

Usage of @Before in step definition file:-

@Before
public void before()
 {
    driver = new FirefoxDriver();
 }

@After: After hooks will run after the last step of each scenario, even when there are failing, undefined, pending or skipped steps.

Usage of @After in step definition file:-

@After
public void After()
 {
     driver.quit();
 }

Tagged Hooks: Sometimes you may want a certain hook to run only for certain scenarios. This can be achieved by associating a Before, After hook with one or more tags.

EX:-if there are multiple @Before & @After tags and you want selected @before and @after tag to run in that case we make use of tagged hooks by adding an additional tag, has shown below in step definition file

Sample Feature File:-

@web
Scenario: login to the zoo website
Given navigate to the zoo
When clicking on "contact_link"
Then check title is of "Contact"
And close the browser

sample Step Definition file:-
@Before(“@web”)
public void before()
   {
       driver = new FirefoxDriver();
   }
@After(“@web”)
public void After()
  {
       driver.quit();
  }

Cucumber Test Suites:

Test suites in cucumber framework are basically used when there are multiple feature files and you want only selected feature files to run. this is achieved by using user-defined custom tags. Add the custom tag for feature file which u want to run.

@Application
  Scenario: login to the zoo website
    Given navigate to the zoo
    When clicking on "contact_link"
    Then check title is of "Contact"
    And close the browser

In step definition file add, the tags option as shown below

package cucumber;
import org.junit.runner.RunWith;
import cucumber.api.CucumberOptions;
import cucumber.api.junit.Cucumber;
@RunWith(Cucumber.class)
@CucumberOptions( plugin = {"pretty","html:target/html/"}, features = {"src/Cucumber/"},
tags ={"@Application"})
public class CucumberRunner
{
}
Note:- to run multiple selected feature files keep on specifying tags in above code inside the double quotes, separated by “,”

Cucumber Reporting:

Reporting is a very important aspect irrespective of any Framework. Cucumber works well with Extent Report. A detailed document is on the way about extent report.

Background:

Background Keyword is written at the very starting of the feature file, Any statement or group of statements added to the background will execute before the execution of all the scenarios mentioned in that feature file.

Execution Flow for Android & IOS

Below mentioned is the framework structure which remains the same for both android and iOS

Screenshot 2019-10-07 at 4.47.44 pm.png

From the above image, you can make out that in folder src/test/java we have the first 2 folders as Driver and Driver.stepDefs

  • In Driver package we have kept java files from execution begins i.e. Runner.Java
  • It also contains the DesiredCapabilities.java class which setups the mobile device for execution
  • It also has supporting files properties.java and BaseTest.java

Driver.StepDefs

  • Package contains all the BDD step definitions file which will basically have the implementations of Gherkin Steps

ObjectRepository

  • This package contains all the locators which are used across different mobile screens

PageObjects

  • This package contains all the helper functions which are called in different step definition files

src/test/resources

  • This package contains all the feature files related to the functionality of the app, this is nothing but a file containing a list of test cases. This file has extension as .feature

How to Begin Execution

  • Execution begins from the Runner.java file, Pass the path of feature.file whose scenarios/TestCases you want to execute.
  • Also, pass the location of cucumber report where you want your cucumber reports to be saved
  • Run this Runner.java file as JUnit

Below mentioned is the sample snapshot

Screenshot 2019-10-07 at 4.59.05 pm.png are added in pom.xml

Pom.xml

All the jars that need to be associated with the project, that corresponding dependency

Below attached is the pom.xml file

<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>Amazon_BDD</groupId>
    <artifactId>Amazon_BDD</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <description>Amazon BDD Automation Framework supporting both iOS &amp; Android</description>

    <name>Amazon_BDD</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.3.9</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-core -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-core</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-html -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-html</artifactId>
            <version>0.2.6</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-java -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-junit -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>1.2.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-jvm-deps -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-jvm-deps</artifactId>
            <version>1.0.5</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/info.cukes/cucumber-testng -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>cucumber-testng</artifactId>
            <version>1.2.5</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/info.cukes/gherkin -->
        <dependency>
            <groupId>info.cukes</groupId>
            <artifactId>gherkin</artifactId>
            <version>2.12.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all -->
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-all</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <!-- <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> 
            <version>4.12</version> <scope>test</scope> </dependency> -->

        <dependency>
            <groupId>junit</groupId>     <!-- NOT org.junit here -->
            <artifactId>junit-dep</artifactId>
            <version>4.8.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/io.appium/java-client -->
        <dependency>
            <groupId>io.appium</groupId>
            <artifactId>java-client</artifactId>
            <version>6.1.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-server -->
        <!-- <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-server</artifactId>
            <version>3.7.0</version>
        </dependency> -->

        <!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
        <!-- <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>3.7.0</version>
        </dependency> -->

        <!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
        <dependency>
                <groupId>com.aventstack</groupId>
               <artifactId>extentreports</artifactId>
                <version>3.1.5</version>
                <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.vimalselvam/cucumber-extentsreport -->
    <dependency>
         <groupId>com.vimalselvam</groupId>
            <artifactId>cucumber-extentsreport</artifactId>
             <version>3.0.2</version>
            </dependency>
    </dependencies>
 </project>

References:

Appium Desired Capabilities

cucumber.io

tutorialspoint.com/cucumber