How To Automate Android Apps Using Appium

WasiqBhamla - Mar 3 '23 - - Dev Community

In this age where new technologies are coming up rapidly, it’s very important to keep up with speed and ensure the highest application quality is delivered to the customers. If we see the user base of different operating systems, we can see that Android is currently the market leader worldwide. Let’s see this market trend:

image1

Many companies want a mobile version of their web applications or even directly create mobile applications for their customers. Therefore, it must be tested thoroughly to ensure customers get quality applications.

When I started with mobile automation testing in 2017, I explored many automation testing tools, like, Calabash with Ruby, Selendroid, and Appium, but out of those, I found Appium is one of the most popular automation tools, and it was relatively easy to get started because of the similarities it had with Selenium WebDriver. Also, it had support with many different programming languages like Java, JavaScript, C#, Python, Ruby, etc., which gave more flexibility to everyone who could use Appium in the language of their choice.

This mobile app testing tutorial on how to automate Android apps will help you know everything to get started with Android automation testing.

What is Appium?

Appium is an open-source mobile app testing framework and an ecosystem to help automate Android apps and iOS apps categorized across different mobile-based applications, like native, web, and hybrid. It also supports automating smart TV and Windows/macOS-based desktop applications.

Since Appium came up with the new version 2.0.0, it has introduced many new changes which further enhanced the overall functionality of Appium. To mention a few recent changes, it has now decoupled drivers from its command line installation. It also introduced a way to override, alter, extend, and add new functionality to Appium by creating Plugins. It also encourages using the W3C protocol for automation compared to earlier Mobile JSON wire protocol.

If you’re new to Appium, this tutorial can provide an easy-to-follow guide on performing mobile app testing.

Through this usability testing tutorial, you will learn how usability testing is a great way to discover unexpected bugs, find what is unnecessary or unused before going any further, and have unbiased opinions from an outsider.

Getting started with Android app automation

For Appium to run successfully and automate Android apps on your machine, you must set up your machine correctly. Let’s see what setup is required to be done to automate Android apps.

Install Node JS

You can install Node JS v16 LTS using Node Version Manager (NVM) by executing the following command on the terminal or command prompt on your machine.

> curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
Enter fullscreen mode Exit fullscreen mode

This command will download the installation script and run it on your machine to install NVM.

Once NVM is installed successfully, you can install Node JS 16.x.x LTS using the following command.

> nvm install lts/gallium
Downloading and installing node v16.19.0...
Downloading https://nodejs.org/dist/v16.19.0/node-v16.19.0-darwin-arm64.tar.xz...
######################################################################################################################################## 100.0%
Computing checksum with shasum -a 256
Checksums matched!
Now using node v16.19.0 (npm v8.19.3).
Enter fullscreen mode Exit fullscreen mode

Once this is installed, you can confirm the installed Node version by running the following command:

> node -v
V16.19.0
Enter fullscreen mode Exit fullscreen mode

Pre-requisites

You must also download and install the following to compile and run your tests successfully:

  • JDK 11: You can download the installer from the link provided for your machine and install it, or you can also use Homebrew on your macOS machine to install the JDK using the following command:

    brew tap homebrew/cask-versions
    brew install --cask temurin11

  • Maven: You can download the distribution package from the provided link, unzip it in the location of your choice, and set the M2_HOME, or you can simply run brew install maven on your macOS machine.

Install Android Studio

To install Android Studio, download the installer from the Android download page and run it. Once the installation is done, open SDK manager and install the following selected packages:

Run your Jest testing automation in massive parallel across multiple browser and OS combinations with LambdaTest, Read more.

image2

Notice the package highlighted in red. This package will only get visible when you uncheck Hide Obsolete Packages.

All these packages are required to automate Android apps.

The last step is setting up the ANDROID_HOME environment variable pointing to the SDK path. Also, we need to update the PATH variable with paths to emulator, tools, platform-tools, and cmdline-tools paths.

export ANDROID_HOME="/path/to/Android/sdk"


export PATH=$PATH:$ANDROID_HOME/emulator
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin
Enter fullscreen mode Exit fullscreen mode

Install Appium Server CLI

To run Appium to automate Android apps on your machine, you will need to install the Appium Command line tool to manage the server and drivers. To install the Appium CLI, run the following command on your terminal:

> npm install -g appium@next


added 453 packages, and audited 454 packages in 30s


49 packages are looking for funding
 run `npm fund` for details


found 0 vulnerabilities
Enter fullscreen mode Exit fullscreen mode

This will only install the latest Appium v2.0 CLI on your machine. Run appium -v to confirm that v2.0.0 was installed successfully.

Get Available Appium Drivers

With Appium 2.0, they have decoupled the Appium Server and drivers. So when you installed Appium CLI, it did not install any drivers. To see all the supported drivers by Appium, run this command:

Install Appium Driver

Now, from the list of supported drivers, you can install any of the required drivers as per your requirement. To install a specific driver, in this case, the uiautomator2 driver for Android, run the following command:

image3

To check if the driver is installed, you can again run the command to list all the supported drivers, and it will show a tick (✔️) next to the installed driver.

Install Appium Doctor

To check whether your machine setup is done correctly now, you would need appium-doctor to help us check it. To install appium-doctor, run the following command:

> npm install -g @appium/doctor
npm WARN deprecated debug@4.1.1: Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)


changed 367 packages, and audited 368 packages in 43s


44 packages are looking for funding
 run `npm fund` for details


found 0 vulnerabilities
Enter fullscreen mode Exit fullscreen mode

Check Machine Setup

Once Appium doctor is installed, run the following command to check machine setup to automate Android apps:

image4

Run Appium mobile testing of native and web apps. Improve your app quality with instant access to real devices on LambdaTest. Register now for free.

Start Appium Server

To start the Appium Server using Appium v2, run the following command:

> appium server --address localhost --port 4723 --use-drivers uiautomator2 --base-path /wd/hub
[Appium] Welcome to Appium v2.0.0-beta.48 (REV 0ccd099bff8e384043883c4ae01b589794b13d72)
[Appium] Non-default server args:
[Appium] {
[Appium]   address: 'localhost',
[Appium]   basePath: '/wd/hub',
[Appium]   useDrivers: [
[Appium]     'uiautomator2'
[Appium]   ]
[Appium] }
[Appium] Attempting to load driver uiautomator2...
[debug] [Appium] Requiring driver at /Users/wasiqbhamla/.appium/node_modules/appium-uiautomator2-driver
[Appium] Appium REST http interface listener started on localhost:4723
[Appium] Available drivers:
[Appium]   - uiautomator2@2.12.1 (automationName 'UiAutomator2')
[Appium] No plugins have been installed. Use the "appium plugin" command to install the one(s) you want to use.
Enter fullscreen mode Exit fullscreen mode

Once the server starts, it’s ready to connect to this server instance, communicate with the device, and execute your test using this session.

To stop the server, you must press Ctrl + C.

Setting up the Android Device

The last step of starting with Android automation using Appium is setting up the device to make it ready for Appium to connect with the device. The device can be a virtual Emulator or your real device. Let’s see how to set up both kinds of devices properly.

Create Android Emulator

Let’s create an Android Emulator using Android Studio. Firstly open Android Studio and click More Actions > Virtual Device Manager as shown below:

image5

This will open up Device manager, which will contain a list of any existing virtual devices and provide an option to create new ones. This is what the device manager screen looks like:

image6

Start the Emulator

To start the emulator, you can click on the (▶️) button in the device manager screen corresponding to the device you want to start. Once you start the emulator, it will take some time to load. Check out a sample emulator screen below:

image7

Why use Cloud Platforms?

If you don’t want to set up a local emulator and still wish to inspect elements for the Android application, you can use cloud-based devices. Before we move ahead, let’s first understand what cloud providers are. Cloud providers are test orchestration & execution platforms like LambdaTest, which provide an online device farm of 3000+ real devices and operating systems to perform real device cloud testing at scale over an Appium grid. Using LambdaTest, you can perform app test automation on real Android and iOS devices.

Test your native, hybrid, and web apps across all legacy and latest mobile operating systems on the most powerful Android emulator online.

You can also subscribe to the LambdaTest YouTube Channel and stay updated with the latest tutorials around Selenium testing, Cypress E2E testing, CI/CD, and more.

Here are some of the features of LambdaTest Appium automation platform

  • Test native features of your mobile apps

  • Automated device testing on blazing fast test automation cloud.

  • Support for all Languages & Frameworks

  • Comprehensive test execution logs

  • Geolocation testing of mobile apps.

Setting up the Cloud Platform

For this blog on how to automate Android apps, we use the LambdaTest cloud platform. On the LambdaTest Dashboard, navigate to Real Device > App Automation on the left-hand panel. Once on that page, click Upload App to upload the application. Check out the upload app page shown below:

image8

Once you upload the application APK, LambdaTest will return you with a unique application URL in the format lt://, which you must copy and keep safe as it will be required later when you try to inspect element from the cloud or try running your Android test on the cloud.

Identifying Locators

The first step after you have done the setup on your machine is, identifying the element locators for the Application Under Test (AUT). Let’s look at how to inspect elements for Android applications.

Install Appium Server

To inspect elements, it’s better to use the Appium Server desktop application, which will give us plenty of server options that we can set up as per our requirements. To install the Appium Server application, you can download it from their GitHub Release page. From that page, download the application which is compatible with your machine. Since I am using a MacBook, I downloaded the .dmg installer file from this release page.

Once you have downloaded the installer compatible with your machine and installed the application, it will look like this:

image9

To start the Appium Server with default settings, press the startServer button. You can also modify server settings from the Advanced tab. You can save the server settings you modified for later use by clicking the Save as Preset button under the Advanced tab. These saved presets will be available under the Presets tab.

Install Appium Inspector

Next important tool is the Appium Inspector application itself. This is also a desktop-based application that you can use to connect to a local Appium Server session; we started using the Appium Server application and the local device (whether Emulator or Real device) or even a cloud-based device where it will install the application under test on the device, launch it and will help you inspect the elements of the application.

To download the Appium Inspector application, visit their GitHub Release page and download the application compatible with your machine’s operating system. Once the application is downloaded and installed, it will look like:

image10

On this screen, you can create desired capabilities for different devices and save them for later use.

With these capabilities, you can select any capability you want to run and the server instance where you want to run this capability. It can be either a local Appium Server or any of the supported cloud platforms, which you can select from the Select Cloud Provider tab, which will list all the supported providers.

Inspect the element on the device using the Inspector

To inspect the element, you will select the capability from the Appium Inspector and update the server details to connect to and then click on the Start Session button. Let’s see how this screen looks before you start the session.

image11

Here one thing to notice is the base path, which is provided as /wd/hub, and we don’t have to provide Remote Host and Remote Port as it defaults to the localhost and port is 4723 which is where you started the Appium Server using the server application.

Once the session starts, the Android Emulator will start as mentioned in the capability avd where you must mention the Emulator name you created using Android Studio’s Virtual device manager. This is how the inspector screen looks when the session is started.

image12

On this screen, you can click on the element on the application screen, mirrored on this inspector from the device. You will be able to see the properties of that element on the right-hand panel. You can see all the element hierarchies in the XML tree in the center panel.

Inspect Element on Cloud Device

To inspect an element on a cloud device, you must get your cloud credentials which you can get from the page when you visit Real Device > App Automation, which can be seen here below:

image13

You can copy the user name and access key by clicking on the copy button next to them. Now open the inspector window, click Select Cloud Providers, and select LambdaTest from the list of providers. Check out the screen below:

image14

When you select the desired cloud provider, you can see it in the main window tabs. Select that tab and add the desired capabilities for starting the session on LambdaTest. Let’s see the example in the next screenshot where I have selected LambdaTest and added all the desired capabilities along with additional LambdaTest-specific capabilities identified with the help of the LambdaTest Capabilities Generator.

image15

Once everything looks good, click Start Session. The Appium Inspector application will establish a connection on LambdaTest. Once the session is started, you will see the inspector screen as follows:

image16

**Note: **One thing to note here is, while setting the app capability in the inspector, is that I am passing the App URL provided by LambdaTest when the application was first uploaded on their servers.

You can confirm that the inspector session has started on LambdaTest by navigating to the LambdaTest dashboard and clicking on Real Devices > App Automation. You will see that the build and session you provided in the capability in the inspector will be visible running on the dashboard. The same is shown in the screenshot below:

image17

You can get more details about the session when you click on the session name.

image18

Run your Selenium Automation Testing scripts on the LambdaTest cloud grid. Test on 3000+ desktop & mobile environments. Try it for free.

Writing the Appium test for Android App

Since you are now aware of how to inspect elements, the final step is to write an Appium test for an Android application on an Android device. In this blog on how to automate Android apps, IntelliJ IDEA Community Edition is used. You are also suggested to use IntelliJ, but it’s up to you which IDE is your preferred one.

In this blog, the following test scenario will be covered, which will help you in getting a basic understanding of how to automate Android apps using Appium.

  • Use the proverbial application provided by LambdaTest and test the Hybrid page, which contains WebView, where we will enter a URL, navigate to that web page, and validate if we are on that page.

  • Run the test on a local emulator.

  • Run the test on LambdaTest cloud real device.

Creating a Maven Project

To create our project, let’s open IntelliJ IDEA and create a new project using Java 11 JDK and Maven. Make sure you have mentioned “group id” and “artifact id” in the Advance Setting section as shown below:

image19

Adding Dependencies

Once the project is created, open the pom.xml file and add the following dependencies:

. . .
<dependencies>
   <!-- https://mvnrepository.com/artifact/io.appium/java-client -->
   <dependency>
       <groupId>io.appium</groupId>
       <artifactId>java-client</artifactId>
       <version>8.3.0</version>
   </dependency>
   <!-- https://mvnrepository.com/artifact/org.testng/testng -->
   <dependency>
       <groupId>org.testng</groupId>
       <artifactId>testng</artifactId>
       <version>7.7.1</version>
       <scope>test</scope>
   </dependency>
   <!-- https://mvnrepository.com/artifact/com.google.truth/truth -->
   <dependency>
       <groupId>com.google.truth</groupId>
       <artifactId>truth</artifactId>
       <version>1.1.3</version>
       <scope>test</scope>
   </dependency>
   <!-- https://mvnrepository.com/artifact/com.google.guava/guava -->
   <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
       <version>31.1-jre</version>
   </dependency>
</dependencies>
. . .
Enter fullscreen mode Exit fullscreen mode

Let’s understand why we have used these dependencies:

  • Appium Java client: This dependency is required to automate Android apps.

  • TestNG: This dependency executes our tests on a local emulator and the cloud.

  • Google Truth: This dependency is used to assert our test to ensure validation of our test.

  • Guava: This is required for the Appium Java client to execute without any issues. Without this dependency, the Java client gives an Error while executing.

Starting Appium Server programmatically

When automating with Appium, it is essential to start the Appium Server from our test to control the test execution. To start an Appium Server programmatically, you must build the Appium service. Let’s see how to build the service:

private AppiumDriverLocalService buildAppiumService () {
   final var appiumPath = Path.of (System.getenv ("HOME"),
           ".nvm/versions/node/v16.19.0/lib/node_modules/appium/build/lib/main.js")
       .toFile ();
   final var logFile = Path.of (System.getProperty ("user.dir"), "logs", "appium.log")
       .toFile ();


   final var builder = new AppiumServiceBuilder ();
   return builder.withIPAddress (System.getProperty ("host", "127.0.0.1"))
       .usingPort (Integer.parseInt (System.getProperty ("port", "4723")))
       .withLogFile (logFile)
       .withAppiumJS (appiumPath)
       .withArgument (GeneralServerFlag.BASEPATH, "/wd/hub")
       .withArgument (GeneralServerFlag.USE_DRIVERS, "uiautomator2")
       .withArgument (GeneralServerFlag.SESSION_OVERRIDE)
       .withArgument (GeneralServerFlag.ALLOW_INSECURE, "chromedriver_autodownload")
       .build ();
}
Enter fullscreen mode Exit fullscreen mode

This method builds the AppiumServiceBuilder class instance with the required attributes per your machine. The attributes we set here are:

  • **host: **We get the hostname from the system property. If it is not set, we will use host 127.0.0.1 by default for localhost.

  • port: We set the port number from the system property. If it is not set, we will use port 4723, the default on which the Appium Server will start.

  • log file: We are setting the log file name where the Appium Server will save all the server logs in this file.

  • Appium JS path: We are setting the Appium main.js path from its installation folder. Normally when you install Node JS using NVM, then when you install Appium, its path is under the ‘.nvm’ directory.

  • Base path: The base path for the server, which is normally /wd/hub.

  • Use Drivers: We set all the drivers we will use here. In this example, we will be using uiautomator2.

  • Allow insecure: We will automate a WebView in a hybrid application in this example. So to automate the web view, we must set the insecure flag chromedriver_autodownload to allow the Appium Server to automatically download the Chrome driver compatible with your device’s web view.

Now to start the Appium Server, you need to call the start method as shown below:

this.service = buildAppiumService ();
this.service.start ();
Enter fullscreen mode Exit fullscreen mode

And to stop the Appium Server, you must call the stop method like:

if (this.service != null) {
   this.service.stop ();
}
Enter fullscreen mode Exit fullscreen mode

Start the session on Local Emulator

Now your Appium Server is ready to start and accept sessions and connect your tests with the running device. To start the session, you must first create a set of capabilities describing your test device and the application under test. Let’s see how to achieve this in the following code snippet:

private static final String DEVICE_NAME_KEY = "deviceName";
private static final String DEVICE_VERSION_KEY = "deviceVersion";
. . .
private Capabilities buildCapabilities () {
   final var deviceName = System.getProperty (DEVICE_NAME_KEY, "Pixel_6_Pro");
   final var deviceVersion = System.getProperty (DEVICE_VERSION_KEY, "11");
   final var options = new UiAutomator2Options ();
   options.setPlatformName ("Android")
       .setPlatformVersion (deviceVersion)
       .setDeviceName (deviceName)
       .setAvd (deviceName)
       .setApp (Path.of (System.getProperty ("user.dir"), "src/test/resources/proverbial.apk")
           .toString ())
       .setAutoGrantPermissions (true)
       .setIsHeadless (Boolean.parseBoolean (System.getProperty ("headless", "false")));
   return options;
}
. . .
Enter fullscreen mode Exit fullscreen mode

In Appium Java client v8.x.x, you can now use the UiAutomator2Options class instance to build the capabilities. In this example, we are setting:

  • Platform Name: This is set as Android as we automate Android apps.

  • **Platform Version: **This is to set the Android version passed from the system property or use 11 by default if the property is not set.

  • Device Name: To set the Android device name, which will be passed from the system property, or use Pixel_6_Pro by default. You must ensure that you pass the device name via system property as it may fail if not passed because you may not have the Emulator with the default name.

  • Avd Name: This is the same as the device name. When this capability is set with the correct Emulator name, Appium will launch the Emulator if it is not started already.

  • **App Path: **This is set as the application APK file path from your machine.

  • Auto Grant permission: This is set to true by default, allowing all the permissions required by the application under test.

  • Is Headless: This is set as the boolean value passed using system property to determine whether to run on the Emulator in a headless mode. If set to true, the Emulator UI will not be visible, and the emulator will run in the background. However, if the Emulator is already running and visible, this flag value will not be considered.

To start the session on the Appium Server, you must pass these capabilities to the AndroidDriver instance along with the server URL. Let’s see how to achieve this:

final Capabilities capabilities = buildCapabilities ();
final URL serverUrl = this.service.getUrl ();


this.driver = new AndroidDriver (serverUrl, capabilities);
this.driver.setSetting (Setting.IGNORE_UNIMPORTANT_VIEWS, true);
Enter fullscreen mode Exit fullscreen mode

You can get the server URL using the service instance we created earlier and pass the capabilities we built to the AndroidDriver instance a while ago. This will establish the connection between the Appium Server and the device. If not started already, it will launch the emulator and install and start the application under test on the device.

Pro Tip: We are updating the driver settings to set IGNORE_UNIMPORTANT_VIEWS as true. What this will do is it will clean up the element hierarchy of the element displayed on the screen. You will only see those elements in the hierarchy which are visible. This will speed up the process of finding the elements later on.

To disconnect the session with the Appium Server, you must call the quit method from the driver instance as shown below:

this.driver.quit ();
Enter fullscreen mode Exit fullscreen mode

Start the session on the Cloud Device

To connect our tests to run on LambdaTest cloud devices, you must first set a few environment variables on your machine which will be used in the test setup. Those environment variables can be set by adding the following lines in your .zshrc or .bash_profile file if you are on Mac, or an equivalent file on Linux or by manually adding to the Windows environment variable window:

export LT_USERNAME="your-user-name"
export LT_ACCESS_KEY="your-access-key"
export LT_APP_ANDROID="your-app-url"
Enter fullscreen mode Exit fullscreen mode

Once these is set, now let’s see how to set up the cloud capabilities below:

private static final String DEVICE_NAME_KEY = "deviceName";
private static final String DEVICE_VERSION_KEY = "deviceVersion";
. . .
private URL getCloudUrl () {
   final var cloudUrl = "@mobile-hub.lambdatest.com/wd/hub">https://{0}:{1}@mobile-hub.lambdatest.com/wd/hub";
   final var userName = Objects.requireNonNull (System.getenv ("LT_USERNAME"), "Cloud user name is required");
   final var key = Objects.requireNonNull (System.getenv ("LT_ACCESS_KEY"), "Cloud access key is required");
   final var path = MessageFormat.format (cloudUrl, userName, key);
   try {
       return new URL (path);
   } catch (final MalformedURLException e) {
       throw new UnsupportedOperationException (format ("URL malformed: {0}", path));
   }
}
. . .
private Capabilities buildCloudCapabilities () {
   final var deviceName = System.getProperty (DEVICE_NAME_KEY, "Pixel_6_Pro");
   final var deviceVersion = System.getProperty (DEVICE_VERSION_KEY, "11");
   final var options = new UiAutomator2Options ();
   final var ltOptions = new HashMap<> ();
   ltOptions.put ("w3c", true);
   ltOptions.put ("platformName", "Android");
   ltOptions.put (DEVICE_NAME_KEY, deviceName);
   ltOptions.put ("platformVersion", deviceVersion);
   ltOptions.put ("app", Objects.requireNonNull (System.getenv ("LT_APP_ANDROID"), "Cloud App URL is required"));
   ltOptions.put ("devicelog", true);
   ltOptions.put ("visual", true);
   ltOptions.put ("network", true);
   ltOptions.put ("video", true);
   ltOptions.put ("build", "Appium sample Build");
   ltOptions.put ("name", "Android Sample");
   ltOptions.put ("project", "Appium Sample Project");
   ltOptions.put ("autoGrantPermissions", true);
   ltOptions.put ("isRealMobile", true);
   options.setCapability ("lt:options", ltOptions);
   return options;
}
. . .
Enter fullscreen mode Exit fullscreen mode

Let’s break down this code snippet. First, we are building the cloud platform URL by concatenating our cloud user name and access key in the URL itself. Secondly, we have created the capabilities specific to the LambdaTest cloud and saved it as a Map, which is later passed on to the UiAutomator2Options instance class.

To know what capabilities are supported by LambdaTest, refer to the LambdaTest Capabilities Generator and play around to see what capabilities you want. The best thing about this is that it also generates a Java code snippet which you can refer to when writing your tests.

To connect your test to run on the cloud device, you need to pass the cloud URL and the capabilities we built in the previous step to the AndroidDriver instance as shown below:

`URL serverUrl = getCloudUrl ();
Capabilities capabilities = buildCloudCapabilities ();


this.driver = new AndroidDriver (serverUrl, capabilities);
Enter fullscreen mode Exit fullscreen mode

To stop the cloud session, you must call the quit method as demonstrated before for running on a local emulator.

Automate Cypress cloud tests and perform browser automation testing with LambdaTest. Our cloud infrastructure has 3000+ desktop & mobile environments. Try for free.

Creating Page Objects

Next step is creating a page object. Since we are looking into a hybrid screen in the Proverbial application used in this blog on how to automate Android apps using Appium, we will have this minimal page object just to understand the basic interaction Appium allows us to do:

import static org.openqa.selenium.support.ui.ExpectedConditions.visibilityOfElementLocated;


import io.appium.java_client.AppiumBy;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.WebDriverWait;


public class HybridPage {
   private final AndroidDriver driver;
   private final WebDriverWait wait;


   public HybridPage (final AndroidDriver driver, final WebDriverWait wait) {
       this.driver = driver;
       this.wait = wait;
   }


   public WebElement browserTab () {
       return this.wait.until (visibilityOfElementLocated (AppiumBy.accessibilityId ("Browser")));
   }


   public void navigateTo (final String url) {
       browserTab ().click ();
       url ().sendKeys (url);
       this.driver.hideKeyboard ();
       find ().click ();
   }


   public String webTitle () {
       return this.wait.until (visibilityOfElementLocated (By.tagName ("h1")))
           .getText ();
   }


   private WebElement find () {
       return this.wait.until (visibilityOfElementLocated (AppiumBy.id ("find")));
   }


   private WebElement url () {
       return this.wait.until (visibilityOfElementLocated (AppiumBy.id ("url")));
   }
}
Enter fullscreen mode Exit fullscreen mode

So, on the test screen, we click on the Browser tab to navigate to the hybrid screen of the application. It contains a text box where the user will enter the website address, which you want to navigate using the sendKeys method. Then click the Find button using the click method, which will load that website in the web view component below on that same screen.

In this page object, we have a method for all the elements we will interact with in the complete flow of the tests, which we will cover in the next section. We also have the navigateTo method, which will be called from the test with the intended URL passed as the parameter.

We also have a method called webTitle, which is nothing but the h1 tag of the website we will be visiting in our test, where we will assert the text of this title element by getting the text of the element using the getText method.

Writing Test Classes

Let’s put everything together in our test class. Following is the test class content:

import static com.google.common.truth.Truth.assertThat;


import java.time.Duration;


import com.github.wasiqb.pages.HybridPage;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;


public class AndroidTest {
   private AndroidDriver driver;
   private DriverManager driverManager;


   @Parameters ("isCloud")
   @BeforeTest (alwaysRun = true)
   public void setupTest (final boolean isCloud) {
       this.driverManager = DriverManager.createDriver (isCloud);
       this.driver = this.driverManager.getDriver ();
   }


   @AfterTest (alwaysRun = true)
   public void teardownTest () {
       this.driverManager.close ();
   }


   @Test
   public void testHybridScreen () {
       final var wait = new WebDriverWait (this.driver, Duration.ofSeconds (5));


       final var hybridPage = new HybridPage (this.driver, wait);
       hybridPage.navigateTo ("https://www.lambdatest.com");


       wait.until (d -> this.driver.getContextHandles ()
           .size () > 1);


       this.driver.context ("WEBVIEW_com.lambdatest.proverbial");


       assertThat (hybridPage.webTitle ()).isEqualTo ("Cross Browser\nTesting Cloud");


       this.driver.context ("NATIVE_APP");


       assertThat (hybridPage.browserTab ()
           .isEnabled ()).isTrue ();
   }
}
Enter fullscreen mode Exit fullscreen mode

First, in this test class, we have a setup method, where we initialize the driverManager class and specify where we intend to run the test on. If we want to run on a local emulator, we pass false in the parameter of the createDriver method, and when we want to run on the cloud instance, we pass true.

Next, we have a teardown method where we close the driver session, which internally quits the driver and closes the Appium Server on a local emulator.

Next, in our test method, we initialize the HybridPage instance, where we navigate to the browser tab, enter the URL https://www.lambdatest.com and click on the Find button. Later we verify the web page title to verify that the page is loaded correctly.

One thing to note is the context method, which tells Appium to switch its context from the native to the web view so we can find the elements from the web page visible in the web view on that screen.

You can get all the available contexts on the screen using the getContextHandles method, which will return the context names. This name you can use to switch the driver context according to your requirements.

Running Appium tests to automate Android Apps

Before you run the test, you must create the testng.xml file. In our case, we will create two files, one for local execution called testng-local.xml and another one called testng-cloud.xml for executing on the cloud platform.

Let’s check out one of the testng.xml files to understand how to set up TestNG to run our test:

<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Appium Android Suite" verbose="2">
   <test name="Appium Android Local Test">
       <parameter name="isCloud" value="false" />
       <classes>
           <class name="com.github.wasiqb.AndroidTest" />
       </classes>
   </test>
</suite>
Enter fullscreen mode Exit fullscreen mode

This file is for running on a local emulator. In the other file, we will have the value of the isCloud parameter to true.

Running tests on CLI using mvn

To run our tests using the Maven command line, we must first tell Maven what TestNG file needs to be executed and all the required system properties. For this, you must update your pom.xml file with the following build block as shown below:

<properties>
   . . .
   <argLine>-Dfile.encoding=UTF-8 -Xdebug -Xnoagent</argLine>
   <target>local</target>
</properties>
. . .
<build>
   <plugins>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-surefire-plugin</artifactId>
           <version>3.0.0-M5</version>
           <executions>
               <execution>
                   <goals>
                       <goal>test</goal>
                   </goals>
               </execution>
           </executions>
           <configuration>
               <useSystemClassLoader>false</useSystemClassLoader>
               <properties>
                   <property>
                       <name>usedefaultlisteners</name>
                       <value>false</value>
                   </property>
               </properties>
               <suiteXmlFiles>
                   <suiteXmlFile>testng-${target}.xml</suiteXmlFile>
               </suiteXmlFiles>
               <argLine>${argLine}</argLine>
           </configuration>
       </plugin>
   </plugins>
</build>
Enter fullscreen mode Exit fullscreen mode

Here we are using the maven-surefire-plugin plugin, and we specify the testng.xml file using the suiteXmlFile property. We are using the target property to differentiate which TestNG file to run, and we have declared the target property in the properties block with the default value as local. This means that if you don’t pass the system property of target, the local target will be used by default, and the local test will be executed.

Once this is setup, you can run the following command to run on the local emulator:

> mvn clean install -Dtarget=local -DdeviceName=<emulator_name>
-DdeviceVersion=<emulator_version>
Enter fullscreen mode Exit fullscreen mode

And run the following command to run on the cloud device:

> mvn clean install -Dtarget=cloud -DdeviceName=<emulator_name>
-DdeviceVersion=<emulator_version>
Enter fullscreen mode Exit fullscreen mode

Check out the execution of tests using the command mentioned above:

image21

Running tests on IDE

Now to run our test on the IDE, you can simply right-click on the testng.xml file and click on the Run option as shown below:

image22

When the test runs for the first time, it will fail because you have not yet set the system properties and specify the deviceName and deviceVersion. Let’s see how to update the system properties in the IDE.

You can edit the run configuration created when you first ran the test by clicking the “Edit Configurations…” option as shown below:

image23

This will open the configuration window, where you can mention the system properties required by your test. You can specify the system properties in the field as shown in the below screenshot:

image24

Once everything looks good, you can click on Apply and OK to save the configurations and then click on the (▶️) button next to the run configuration you saved, This will execute the tests in your IDE, and you will be able to see the run results in the corresponding panel in the IDE as shown below:

image25

Reporting of the test result on LambdaTest

When your run is started on the cloud device, you will be able to see the real-time test execution video streaming and steps being executed on the device from your tests on the LambdaTest Dashboard. To navigate your test:

image26

Log in to the dashboard and click Real Devices > App Automation on the left-hand side navigation panel. You will see the below screen:

image27

On this screen, you will see all the test executions you have ever run. To reduce the clutter, you can filter the records based on the “Project name” you mentioned in the cloud capabilities while executing the tests. Once the filter is applied, you will see only those tests which are a part of that project.

When a test is running, you will see it running in the right section of this screen with the status RUNNING. When you click it, you will be able to see all the real-time interactions of the test.

Once the test execution is completed, you can see loads of details about the test when you click and open the test from the right section. This is what you will see first when you open the test session:

image28

On this screen, you will see the video of the tests, all the test steps that were executed, and the time it took to run that step, along with the screenshots at the time of executing that step.

You can also see the device logs of the executed test when you click on the “Device Logs” tab as shown below:

image29

Similarly, you can see the network logs of the tests by clicking on “Network Logs” as shown below:

image30

And similarly, you can see the Appium Server logs from the cloud server by clicking on “Appium Logs” tab as shown below:

image31

Conclusion

To conclude and recap this Appium tutorial on how to automate Android apps using Appium, we learned about running Appium tests on an Android device on your local machine as well as on the LambdaTest cloud platform. We also learned how to use the new Appium 2.0 for automation, setting up our machine, setting up the required drivers, automating a hybrid app, and interacting with different elements like a button, text field, and web view. This example is enough for you to get started with Android automation and automate any type of application you may work on in the future.

Don’t forget to check out the GitHub repository used for this blog to automate Android apps.

If you liked this blog on how to automate Android apps, don’t forget to share it with your network, who may also benefit from it and help them learn about Appium.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .