Appium 7 - Android Test Automation

Agenda:

To understand Appium and explore concepts that helps us to achieve mobile test automation.

Introduction:

  1. Open source tool that works for native, hybrid and mobile apps
  2. Supports selenium webdriver API
  3. Platform support for iOS, Android and FirefoxOS

Architecture:

Appium Client Code => Json (Request) ==> Appium Server ==> UIAutomator2 ==> Android
                                                                                                 ==> XCUITest        ==> iOS

  1. Appium client code is the code that is written by user using any language that is supported by selenium like Java, C#, python etc
  2. The request will be sent to Appium server in the form of JSON, which is interpreted by server and executes accordingly on platforms like iOS or Android.
  3. UI Automator2 or XCUITest are the test frameworks used by Android or iOS to test their apps. Appium is also designed to use the same, which makes it more robust.
Note: Response also traverse back in the same direction

Required Software Installation:

Java:

  1. download jdk8 from Java Archive Downloads - Java SE 8 | Oracle India
  2. set environment variable JAVA_HOME
    1. Example: JAVA_HOME = C:\Program Files\Java\jdk1.8.0_202

Android Studio:

  1. download android studio from Download Android Studio and SDK tools  |  Android Developers
  2. set environment variable ANDROID_HOME
    1. Example: ANDROID_HOME = C:\Users\Vinay\AppData\Local\Android\Sdk
  3. Add sdk tools --> bin to path variable
    1. Example: %ANDROID_HOME%\tools\bin
  4. Add tools to the path as well
    1. Example: %ANDROID_HOME%\tools
  5. Add platform tools to the path
    1. Example: %ANDROID_HOME%\platform-tools

Node:

  1. Appium server is written on node.js, so we need this software to run Appium server
  2. Download node js from Download | Node.js (nodejs.org)
  3. set environment variable NODE_HOME
    1. Example: C:\Program Files\nodejs
  4. Add node modules --> npm bin folder to path
    1. Example: %NODE_HOME%\node_modules\npm\bin
IDE:
  1. download any IDE of your choice like Eclipse or IntelliJ

Configure Virtual Emulator:

  1. Open Android studio --> create a dummy project (creating only to access emulator)
  2. Go to Tools --> Device Manger (Android Virtual Devices) --> Create Device --> Example: PIXEL XL 26 API --> Launch Emulator
Note: for Android its emulator, for iOS its simulator, just a naming convention :-)

Install Appium Server:

  1. install appium server using "npm install -g appium"
  2. to start appium, run the command appium
  3. once server started, it runs on port 4723

Create Appium - maven project:

  1. Create a simple maven project
  2. Add maven dependencies for appium and selenium - Note: make to sure to add supported version of selenium, which can found in their official github project - appium/java-client: Java language binding for writing Appium Tests, conforms to Mobile JSON Wire & W3C Webdriver Protocol (github.com)
  3. Note: Using appium stable version 7.5.1 and selenium 3.141.59
  4. Add maven dependency for testng (for assertions purpose)

Getting Started

Note: 
  1. download apk package from this location - appium/ApiDemos-debug.apk at master · appium/appium (github.com)
  2. copy to your src folder of your project
  3. start appium server

Sample code to invoke app on your emulator:

File appDir = new File("src");
File app = new File(appDir, "ApiDemos-debug.apk");

DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "VinayEmulator");
capabilities.setCapability(MobileCapabilityType.APP, app.getAbsolutePath());
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");

AndroidDriver driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);

Inspect elements using UIAutomatorViewer:

  1. it is found in your sdk folder --> tools --> bin. Example: C:\Users\Vinay\AppData\Local\Android\Sdk\tools\bin\uiautomatorviewer
  2. Note: Make sure to open your emulator and start the app, before running uiautomatorviewer
  3. Click on device screenshot, which will take screenshot of current view of the page. Select the element and details are displayed accordingly. Screenshot looks like below

Lets take a look at automation

  1. Try to use locators like xpath, id and classname.
  2. Syntax for xpath - //tagname[@attribute="value"]
  3. Under the node detail --> most of the time classname should be the tagname, followed by you can select any attribute and its value and create a xpath that uniquely identifies the elements.
  4. Example: androidDriver.findElementByXPath("//android.widget.TextView[@text='Preference']").click();
  5. On the similar note, elements can be found with id and classname.
  6. we can click on duplicate elements as well by indexing our xpath like below
    1. (//android.widget.TextView[@text='OS']"))[2] --> which selects second instance of the element.

AndroidUIAutomator Usuage:

  1. it's another type of identifier, where we identify element based on attribute and value like below.
  2. Example: androidDriver.findElementByAndroidUIAutomator("text(\"Preference\")").click();
  3. when user want to identify element based on property, say I want to identify elements which are not checkable, in that we have to use UiSelector which android api code not appium.
  4. Example: androidDriver.findElementsByAndroidUIAutomator("new UiSelector().checkable(true)").size() --> if size is zero, none of the elements are checkable

Gestures

  1. We will be using TouchAction class to perform Gestures like Tap and longpress.
  2. Sample code
touchAction.longPress(new LongPressOptions().withElement(new ElementOption().withElement(peopleNamesElement)).
withDuration(Duration.ofSeconds(2))).
release().perform();
AndroidElement titleElement = androidDriver.findElementByXPath("//android.widget.TextView[@text='Sample menu']");
Assert.assertTrue(titleElement.isDisplayed(), "pop up didn't display");

Swipe

  1. Here also we will use TouchAction class, where we longpress on an element and move to the element required.
AndroidElement src = androidDriver.findElementByXPath("//*[@content-desc='15']");
AndroidElement dest = androidDriver.findElementByXPath("//*[@content-desc='45']");
TouchAction touchAction = new TouchAction(androidDriver);
touchAction.longPress(
new LongPressOptions().withElement(new ElementOption().withElement(src)).withDuration(Duration.ofSeconds(2))).
moveTo(new ElementOption().withElement(dest)).release().perform();

Scroll

  1. We use android api code to perform this action like below
  2. Example: 
androidDriver.findElementByAndroidUIAutomator(
                "new UiScrollable(new UiSelector()).scrollIntoView(text(\"Views\"));").click();

Note:
We can use this concept for selecting any element from the drop down as well
or
Get the list of items by classname, iterate and find the one's that is required and click on it.

Note:
Suppose you want to add a product to cart, to search that product you can use this scroll, but to get product visible properly, we should first go to resouce and then into view as shown below
androidDriver.findElementByAndroidUIAutomator("new UiScrollable(new UiSelector().resourceId(\"com.androidsample.generalstore:id/rvProductList\")).scrollIntoView(new UiSelector().textMatches(\"AsusX6\"))"

Drag and Drop

  1. Here also we will use TouchAction class.
AndroidElement src = androidDriver.findElementsByClassName("android.view.View").get(0);
AndroidElement dest1 = androidDriver.findElementsByClassName("android.view.View").get(1);

TouchAction touchAction = new TouchAction(androidDriver);
touchAction.longPress(new LongPressOptions().withElement(new ElementOption().withElement(src))).
moveTo(new ElementOption().withElement(dest1)).release().perform();

Toast Messages

  1. Toast message is simple feedback about an operation and it disappears with a timeout. In appium, we can't identify the object, so we will make use of android code
Example: //android.widget.Toast[1] --> which refers to 1st toast message on the screen

Lets take a look at configuring physical device


  1. Enable developer options on your android mobile which can be done via Settings --> About Phone --> build number (tap for 7 times)
  2. Click on developer options and enable usb debugging.
  3. try invoking adb devices from your terminal which should list your physical device


  1. There is only one line of change in code, that actually points to physical device, and without any change tests can be executed.
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Android device");

Note:
we can download any apk and install it using adb in your platform tools, so that app reflects in your emulator directly.
Example:
1. Navigate to your android sdk platform tools --> adb install pathOfAPKFile

Context Handles

In hybrid apps, where we have native + web, there are instances where we need to do some operations on browser and revert back to native app and continue testing. That's where context handles comes into picture.

Example:
Set<String> contexts = driver.getContextHandles();
Once you get the context name, you can switch to that context
driver.context("name of the context");

Make sure you have the compatible chromedriver and copy to this location - C:\Users\Vinay\AppData\Roaming\npm\node_modules\appium\node_modules\appium-chromedriver\chromedriver\win

To come back to native app, you can use back button or use context
driver.pressKey(new KeyEvent(AndroidKey.BACK)));
driver.context("name");

How to run on Mobile Browser

  1. To run tests on browser in android emulator, we need to set below desired capabilities
capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "VinayEmulator");
capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");
capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, "uiautomator2");
  1. You can inspect elements on your chrome browser where you need to toggle to the mobile view and select mobile device that you are using. Please refer to below screenshot.


Creation of Page Objects

  1. Try Representing every screen as a page object. For example "HomePage.java"
  2. Under HomePage.java have all the xpaths or id's or classname's of the webelements
  3. Initialize all those webelements with a page object factory.
  4. Any changes in xpaths related to that page, can be handled here, which make our framework more robust.
HomePage.java
public class HomePage {

public HomePage(AndroidDriver driver){
PageFactory.initElements(new AppiumFieldDecorator(driver), this);
}

@AndroidFindBy(xpath = "//android.widget.TextView[@text='Preference']")
public WebElement preferenceLink;

}

HomePage object can be initialized in any class provided with a driver of their choice.
AndroidDriver<AndroidElement> androidDriver = capabilities("emulator");
HomePage homePage = new HomePage(androidDriver);
homePage.preferenceLink.click();

Start and Stop your appium server programmatically

  1. We can kill a node by running this command - taskkill /F /IM node.exe
  2. We can start server by using below code
AppiumDriverLocalService appiumDriverLocalService;
public void startAppiumServer(){
appiumDriverLocalService = AppiumDriverLocalService.buildDefaultService();
appiumDriverLocalService.start();
}
  1. We can stop server by using below code
public void stopAppiumServer(){
appiumDriverLocalService.stop();
}
  1. Make sure to check if anything running on that port
public static boolean isAppiumServerRunningOn(int port){
boolean isServerRunning = false;
ServerSocket serverSocket;
try{
serverSocket = new ServerSocket(port);
serverSocket.close();
} catch (IOException e) {
isServerRunning = true;
}finally {
serverSocket = null;
}
return isServerRunning;
}

How to start your emulator programmatically

  1. Navigate to sdk emulator folder - C:\Users\Vinay\AppData\Local\Android\Sdk\emulator
  2. and invoke this command - emulator -avd nameOfyourEmulator 
  3. Create a bat file with above steps and invoke from your code.

and invoke that bat file using Runtime, like below

How do we pass emulator name via maven?

  1. Everytime we can't change name of the emulator in code, so we need to pass this as a parameter in maven command - mvn test -DdeviceName=VinayEmulator -Ddevice=emulator
below are the code changes to support above variables
if(System.getProperty("device")!=null){
device = System.getProperty("device");
}else {
device = properties.getProperty("device");
}
if(System.getProperty("deviceName")!=null){
deviceName = System.getProperty("deviceName");
}else {
device = properties.getProperty("deviceName");
}

Run Appium Tests on BrowserStack

  1. Lets try to run our test in cloud. Here I am making use of BrowserStack Most Reliable App & Cross Browser Testing Platform | BrowserStack
  2. Click on App Automate --> follow this link to get started with your first step of automation - App Automate Quick Integration Guide (browserstack.com)
  3. Make sure to create account and have user name and access key with you
  4. Upload you apk, which generates a url which can be used as app location and for testing as well
DesiredCapabilities caps = new DesiredCapabilities();
caps.setCapability("browserstack.user", "xxxx");
caps.setCapability("browserstack.key", "xxxx");
caps.setCapability("app", "bs://xxxx");
caps.setCapability("device", "Google Pixel 3");
caps.setCapability("os_version", "9.0");
AndroidDriver<AndroidElement> driver = new AndroidDriver<AndroidElement>(
new URL("http://hub.browserstack.com/wd/hub"), caps);

driver.findElementByAndroidUIAutomator(
"new UiScrollable(new UiSelector()).scrollIntoView(text(\"Views\"));").click();
driver.findElementByXPath("//android.widget.TextView[@text='Drag and Drop']").click();
AndroidElement src = driver.findElementsByClassName("android.view.View").get(0);
AndroidElement dest1 = driver.findElementsByClassName("android.view.View").get(1);

TouchAction<?> touchAction = new TouchAction<>(driver);
touchAction.longPress(new LongPressOptions().withElement(new ElementOption().withElement(src))).
moveTo(new ElementOption().withElement(dest1)).release().perform();

driver.quit();
You can view the results in the dashboard like
execution replay, appium logs, screenshots etc.
Note: The beauty of this is you can run your tests parallelly

References



Comments

Popular posts from this blog

TestNg - Test Automation Framework

React Js and Redux