Appium 2.0 Android Native Application Test using JUnit 5

March 25, 2023
 
Creating an automated test to launch and interact with a Native Application on Android
This article is part of a series which provides sample Java code to run a JUnit 5 tests that will interact with mobile devices and simulators using Appium 2.0 to perform automated testing:

Appium

The first step is to ensure that Appium is running. If you need assistance, you can refer to this article. Appium will provide the means to communicate with your Android device. In this example I will be accessing an Android Pixel 3a running Android version 12L.

Start Appium

After installing and verifying that Appium was installed successfully, you can start it to automatically download appropriate chrome web drivers as follows:

appium --allow-insecure chromedriver_autodownload

Create Project in Eclipse

You can build your project in your IDE of choice, in this example we will be using Eclipse.
Launch Eclipse and create a new gradle project by clicking on File | New | Other... | Gradle | Gradle Project

This will create an empty project with a sample class and test in the src/main/java and src/test/java respectively. It will also include the gradle configurations.

Gradle

We will be using gradle to install our dependencies. Please update your build.gradle to match the xml below. The only section that should be different should be the dependencies.
/*
 * User Manual available at https://docs.gradle.org/7.4.2/userguide/building_java_projects.html
 * Source: https://www.code-gorilla.com/
 */

plugins {
    // Apply the java-library plugin for API and implementation separation.
    id 'java-library'
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

def jUnitVersion = '5.8.1'
def appiumVersion = '8.3.0'
dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation "org.junit.jupiter:junit-jupiter:${jUnitVersion}"
    testImplementation "io.appium:java-client:${appiumVersion}"

    //Start: Binding slf4j to an implementation
    testImplementation 'org.slf4j:slf4j-jdk14:2.0.6'

    // This dependency is exported to consumers, that is to say found on their compile classpath.
    api 'org.apache.commons:commons-math3:3.6.1'

    // This dependency is used internally, and not exposed to consumers on their own compile classpath.
    implementation 'com.google.guava:guava:30.1.1-jre'
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}
Gradle Refresh
After you have updated the build.gradle file you will want to synchronize gradle to install the dependencies.
You can do this by right clicking anywhere in the editor window | right click | Gradle | Refresh Gradle Project

Android Debug Bridge (adb)

Please run the following command at the terminal to get your active devices:
adb devices

My results looked like this, yours may be different:
List of devices attached
emulator-5554 device
emulator-5556 device

To get the device name that we will be using in the code you can run the following command:
adb -s emulator-5556 shell getprop
Note the -s emulator-5556 is specifying the device I am interested in getting the information for.
If you only have one active device you can omit the -s emulator-5556 parameter. You will most likely need to update it to match your device name.


Here is the value you will be interested in. This result will match the device name in the code.
[ro.boot.qemu.avd_name]: [Pixel_3a_API_32_arm64-v8a]

Create New Test Package

Before creating the class I would recommend creating a new package within the src/test/java folder to put your new class into. This is an optional step, but a recommended one. When you create the new package, it is recommended to name it with your domain name backwards. For example, com.code_gorilla.appium is what I will be using in this demonstration.
You can do this by right clicking on src/test/java | New | Package

Create New Test Class

If you created a new package, create a new class within that package; otherwise put it anywhere within src/test/java.
You can do this by right clicking on your package | New | Class

I will be using AndroidWebTest as follows:
package com.code_gorilla.appium;

import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.remote.DesiredCapabilities;

import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.remote.AutomationName;
import io.appium.java_client.remote.MobileCapabilityType;

/**
 * Appium 2.0 JUnit 5 automated test launching Chrome on Android
 * @author Tom Snyder
 * 
 * References:
 * https://www.code-gorilla.com/view-article/appium-2.0-android-web-test-using-junit-5
 * https://appium.github.io/appium/docs/en/2.0/intro/
 * https://junit.org/junit5/
 */
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class AndroidWebTest {
	private static AndroidDriver driver = null;
	private static int APPIUM_VERSION = 2; // ONLY 1 and 2 are valid options for major releases.

	@BeforeAll
	 public static void beforeAll() throws Exception {
		System.out.println("Initializing Appium Connection...");
		    
		DesiredCapabilities capabilities = new DesiredCapabilities();
		capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "Pixel_3a_API_32_arm64-v8a");
		capabilities.setCapability(MobileCapabilityType.PLATFORM_VERSION, "12L");
		capabilities.setCapability(MobileCapabilityType.PLATFORM_NAME, "Android");
		capabilities.setCapability(MobileCapabilityType.BROWSER_NAME, "Chrome");	
		capabilities.setCapability(MobileCapabilityType.AUTOMATION_NAME, AutomationName.ANDROID_UIAUTOMATOR2);
	    
		URL conn = null;
		if (APPIUM_VERSION == 2) {
			conn = new URL("http://0.0.0.0:4723/");
		} else {
			conn = new URL("http://0.0.0.0:4723/wd/hub");
		}
		
	    driver = new AndroidDriver(conn, capabilities);
	 }

	@AfterAll
	public static void afterAll() throws Exception {
		if (driver != null)
			driver.quit();
	}
	
	@Test
	@Order(1)  
	@DisplayName("Code-Gorilla Home Page Test")
	void codeGorillaNav() throws Exception {
		System.out.println("code-gorilla home page Test");
		String testUrl = "https://www.code-gorilla.com/";
		driver.get(testUrl);

		System.out.println("Presenting for 2 seconds...");
		TimeUnit.SECONDS.sleep(2);

		// This is a deliberate success to show on report.
		// This logo IS displayed on the target page.
		assertTrue(driver.findElement(By.id("code-gorilla-header-logo")).isDisplayed());
		System.out.println("Presenting for 1 seconds...");
		TimeUnit.SECONDS.sleep(1);
	}
	
	@Test
	@Order(3)  
	@DisplayName("Code-Gorilla Display Test")
	void codeGorillaDisplay() throws Exception {
		System.out.println("Code-Gorilla Display Test");
		String testUrl = "https://www.code-gorilla.com/view-article/appium-2.0-android-web-test-using-junit-5";
		driver.get(testUrl);

		System.out.println("Presenting for 5 seconds...");
		TimeUnit.SECONDS.sleep(5);

		// This is a deliberate failure to show on report.
		// This logo is NOT displayed on the target page.
		assertTrue(driver.findElement(By.id("code-gorilla-header-logo")).isDisplayed());
		System.out.println("Presenting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);
	}
	
	@Test
	@Order(2)  
	@DisplayName("USPS Browser Test")
	void zipCodeNav() throws Exception {
		System.out.println("USPS Browser Test");
		String testUrl = "https://tools.usps.com/zip-code-lookup.htm";
		driver.get(testUrl);

		System.out.println("Presenting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);

		WebElement element = driver.findElement(By.className("zip-code-cities"));
		if (element != null) {
			element.click();
		}

		System.out.println("Presenting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);

		System.out.println("Sending Zip Code characters...");
		WebElement zipText = driver.findElement(By.id("tZip"));
		zipText.sendKeys("18504");

		System.out.println("Presenting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);

		// Click on the submit button
		System.out.println("Clicking on button...");
		driver.findElement(By.id("cities-by-zip-code")).click();

		// Note: You need to wait to ensure the page is loaded to get the elements.
		System.out.println("Waiting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);

		System.out.println("Looking for a match...");
		boolean isFound = false;
		List cityList = driver.findElements(By.className("row-detail-wrapper"));
		if (cityList == null || cityList.size() < 1) {
			System.out.println("Couldn't find row-detail-wrapper items.");
		} else {
			for (WebElement cityName : cityList) {
				String cityText = cityName.getText();
				System.out.println("Comparing City: " + cityText);
				if (cityText.equalsIgnoreCase("SCRANTON PA"))
				{
					isFound = true;
				}
			}
		}
		assertTrue(isFound);

		// assertTrue(driver.findElement(By.id("code-gorilla-header-logo")).isDisplayed());
		System.out.println("Presenting for 3 seconds...");
		TimeUnit.SECONDS.sleep(3);
	}

}

Here is a high level overview of the code above:
  • The annotation @BeforeAll will be run before all of the tests. This is a good place to connect to your Appium server.
  • The annotation @AfterAll will run after all of the tests complete. This is a good place to clean up and disconnect from the Appium server.
  • This test is running locally, so the Appium 2.0 server address is http://0.0.0.0:4723/. If you were using Appium 1.0 it would be http://0.0.0.0:4723/wd/hub.

References

 
Return to articles