Appium Mobile Automation Framework from scratch in Java using Maven, TestNG, Cucumber and Extent Reporting

Raghwendra Sonu
5 min readOct 1, 2019

--

Now a days, updating apps over the air is very easy, raising users’ expectations of new features delivered sooner. So what this means for development teams is, they have to deliver many releases frequently and in turn what this means for Test teams is, they are continuously tasked with testing entire applications faster and more often.

Solution for such problems is Test Automation. Appium is a mobile Test Automation tool that has made life a lot easier for testers because of its capabilities and powers. Appium has made it easier for teams to test their apps for multiple platforms(one test case can test an app on iOs and android both).

But, Appium alone cannot solve the challenges around implementing behavior driven development & frequent UI/functionality updates.What is needed is, the combination of tools which can address these problems when combined together. So on this thought process,i created a Test Framework combining Appium, Cucumber, Page Objects and Extent Reports.

Application under Test

Lets first understand the Application under Test. http://qatechtesting.com/

This is a my portfolio website, detailing about myself and my work.We are going to navigate to this website and test few Links on Home page and then navigate to Blog page to verify Page Header.

Pre-requisites

  • Appium 1.13.0
  • Java 8
  • Maven
  • Eclipse IDE with Cucumber Plugin installed

Test Cases

we are going to write:

For HomePage:
1. TC1 : Navigate to QATechTesting, and verify that Homepage is
2. TC2: Navigate to to QATechTesting, and verify that Blog Link is displayed on the home page.

For BlogPage:
1. TC1 : Navigate to Blog page from Home page, and verify that Blog Page title is correct.

Now Lets understand the Maven Project that we created for this framework.

Step 1: Since its a maven project, we need to add dependencies in the pom.xml for Cucumber and Appium. Below is the snapshot of the pom.xml:

Dependencies

  • Appium Java Client
  • Cucumber Java & TestNG
  • Extent Reports

Step 2: Lets understand the project structure by next snapshot:

  • Configuration package — Hooks and API Processor
  • Runners — Cucumber Runner Test
  • Screens — Page Classes with Page Actions defined
  • Step Definitions — Screen and its Steps Defs.
  • Features — cucumber features

Step 3: Since its a cucumber project, next step is to write a feature file. I have created the feature file as per the application pages(screen shot and test cases above). Here is the snapshot for step definitions:

Step 5: Next step is to right some hooks code,which will invoke Appium Instance and close the instance after test case is finished.Here is the snapshot for the same:

package stepdefs;
import java.net.MalformedURLException;
import org.apache.commons.lang.StringUtils;
import io.cucumber.core.api.Scenario;
import io.cucumber.java.After;
import io.cucumber.java.Before;
import listeners.ExtentReportListener;
public class BaseClassSteps extends ExtentReportListener{
public static String featureName;
@Before
public void before(Scenario scenario) throws MalformedURLException {
getFeatureFileNameFromScenarioId(scenario);
setUp();
setUpDriver();
}
private void getFeatureFileNameFromScenarioId(Scenario scenario) {
featureName = "Feature ";
String rawFeatureName = scenario.getId().split(";")[0].replace("-"," ");
featureName = StringUtils.substringAfterLast(rawFeatureName, "/").split(".feature")[0];
}
@After
public void after(Scenario scenario){
closeDriver(scenario);
extent.flush();
}
}

Step 6: Here is the code for invoking and closing Appium Instance. you can keep this code in any class and then use that class in hooks class accordingly. I have created a Java Class WebConnector.java and declared this code there.here is the code snapshot for the same:

package webconnector;public class WebConnector<V> {public static WebDriver driver=null;public void setUpDriver() throws MalformedURLException{
String browser = prop.getProperty("browser");
if (browser == null) {
browser = "chrome";
}
switch (browser) {
case "android-tablet":
DesiredCapabilities androidCapabilities= new DesiredCapabilities();
androidCapabilities.setCapability("deviceName", prop.getProperty("DeviceName"));
androidCapabilities.setCapability("udid", prop.getProperty("UDID"));
androidCapabilities.setCapability("platformVersion", prop.getProperty("PlatformVersion"));
androidCapabilities.setCapability("platformName", prop.getProperty("PlatformName"));
//androidCapabilities.setCapability("appPackage", prop.getProperty("AppPackage"));
//androidCapabilities.setCapability("appActivity", prop.getProperty("AppActivity"));
androidCapabilities.setCapability(CapabilityType.BROWSER_NAME,prop.getProperty("Device_Browser"));
URL url= new URL(prop.getProperty("DeviceURL"));
driver= new AppiumDriver<MobileElement>(url,androidCapabilities);
System.out.println("###........CONNECTION SUCCESSFULLY ESTABLISHED WITH NODE DEVICE........###");
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT);");
break;
case "iPad":
DesiredCapabilities iPadCapabilities = new DesiredCapabilities();
iPadCapabilities.setCapability("deviceName", "UBSÕs iPad");
iPadCapabilities.setCapability("device", prop.getProperty("Device"));
iPadCapabilities.setCapability("udid", prop.getProperty("UDID"));
iPadCapabilities.setCapability("bundleid", prop.getProperty("BuldleID"));
iPadCapabilities.setCapability(CapabilityType.BROWSER_NAME,prop.getProperty("Device_Browser"));
iPadCapabilities.setCapability(CapabilityType.VERSION, prop.getProperty("DeviceVersion"));
iPadCapabilities.setCapability(CapabilityType.PLATFORM,prop.getProperty("Platform"));
//capabilities.setCapability("app", prop.getProperty("ApplicationPath"));
driver = new AppiumDriver(new URL(prop.getProperty("DeviceUrl")), iPadCapabilities);
System.out.println("###........CONNECTION SUCCESSFULLY ESTABLISHED WITH NODE DEVICE........###");
JavascriptExecutor js1 = (JavascriptExecutor) driver;
js1.executeScript("target.setDeviceOrientation(UIA_DEVICE_ORIENTATION_LANDSCAPELEFT);");
break;
default:
throw new IllegalArgumentException("Browser \"" + browser + "\" isn't supported.");
}
}
public void closeDriver(Scenario scenario){
if(scenario.isFailed()){
saveScreenshotsForScenario(scenario);
}
if(driver!=null) {
//driver.close();
}
}
}

Step 7: Next we write the code for functions that we expect our test cases to perform. Here are the functions that we have in the StepDefinition file. This file is per page. So, for now i have two java classes one for Home Page and another for Blog Page. Also, there is one BaseClassSteps.Here is the snapshot for that code:

//HomePageSteps.java
package stepdefs;
import java.io.IOException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.GherkinKeyword;
import com.aventstack.extentreports.gherkin.model.Feature;
import com.aventstack.extentreports.gherkin.model.Scenario;
import ApplicationPages.Homepage;
import io.cucumber.java.BeforeStep;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import listeners.ExtentReportListener;
public class HomePageSteps extends ExtentReportListener {
private Homepage homePage;
public HomePageSteps() {
this.homePage = new Homepage();
}
@Given("^User navigates to QATechTesting HomePage$")
public void aUserNavigatesToHomePage() throws InvalidFormatException, IOException, ClassNotFoundException {
ExtentTest logInfo=null;
try {
test = extent.createTest(Feature.class, "Home Page Verifications");
test=test.createNode(Scenario.class, " Check Home page is displayed");
logInfo=test.createNode(new GherkinKeyword("Given"), "User navigates to QATechTesting HomePage");
this.homePage.goToHomePage();
logInfo.pass("Opened chrome browser and navigated to Homepage");
logInfo.addScreenCaptureFromPath(captureScreenShot(driver));
} catch (AssertionError | Exception e) {
testStepHandle("FAIL",driver,logInfo,e);
}
}
@Then("^User verify that Blog Link is displayed$")
public void googleLogoIsDisplayed() throws Exception {
ExtentTest logInfo=null;
try {
logInfo=test.createNode(new GherkinKeyword("Then"), "verify that Blog Link is displayed");
this.homePage.checkBlogLinkDisplay();
logInfo.pass("Blog Link is displayed");
logInfo.addScreenCaptureFromPath(captureScreenShot(driver));
} catch (AssertionError | Exception e) {
testStepHandle("FAIL",driver,logInfo,e);
}
}
}

Now, we are a stage where we have created a small cucumber-appium-maven project that verifies behavior of the application. This project now contains two automation test cases.

Test Execution

$ git clone https://github.com/raghwendra-sonu/Appium_Cucumber_TestNG_Maven.git

$ mvn clean install

Git

That’s it!Congratulations on making it through this write-up and hope you found it useful!

You can find the entire framework code here:

https://github.com/raghwendra-sonu/Appium_Cucumber_TestNG_Maven

--

--

Raghwendra Sonu
Raghwendra Sonu

Written by Raghwendra Sonu

Software Automation Testing expert with 9 years of work experience in diverse tools and technologies.

No responses yet