Implement a Mobile-First Design Strategy: A Comprehensive Guide
Frank Moyer
Welcome to the enthralling journey of mastering test automation with Appium! In this blog post, we’ll walk through writing your very first test case. Whether you’re a novice or a seasoned developer, the simplicity and effectiveness of Appium will quickly become evident. We’re going to cover a lot of ground and by the end of this article, you’ll have grasped the basics of Appium and writing test cases.
Appium is a powerful tool for automating tests on various applications – native, hybrid, and web-based – offers a unique advantage: it’s OS-agnostic. This means your Appium scripts can run on any device or platform, whether it’s a real device, a simulator, or an emulator, without any dependency on the mobile OS or the application itself.
Under the hood, Appium is just wrapper that translates Selenium Webdriver commands into XCUITest for iOS and UiAutomator2 for Android. XCUITest and UiAutomator2 are Test frameworks for XCode and Android Studio respectively. Appium supports all the programming languages which Selenium supports such as Java, C#, Python, Ruby, Javascript with Node.js etc.
For the examples that follow, we will be using Java, since Appium was written in Java. You can find many resources online on Appium (download our free eBook here) and Java, which make your learning journey a little easier. In our examples, we will be using a Mac, but of course, you will be fine on any supported operating system.
Please make sure you followed the previous blog and installed Appium properly. Now that Appium is installed, we’ll be installing our development environment. If you already have a development environment installed, you can skim through the steps that follow. However, it may be easier for you to follow these instructions and have your environment mimic ours for easier reference. Start your free trial today.
Note: The steps may seem a little daunting, especially when you want to write a simple test case. However, this is really a one-time effort. Once your environment is configured and you’re comfortable with concepts, such as dependency management, you’ll find that writing the Appium scripts is a relatively straightforward task. So stay with us through this section, and it will get easier, we promise.
We will start by installing an IDE to create Java based Appium Scripts. You can either select IntelliJ IDEA or Eclipse IDE (or any IDE of your choice). We will be using IntelliJ.
To summarize, we will use the following to create our Appium Script:
There are 2 primary things to accomplish in this chapter:
In order to sethup the IDE you need to:
Figure-1: Installation of IntelliJ IDEA Community Edition.
Figure-2: Complete the Installation.
Figure-3: Policy Agreement.
Figure-4: Set UI Theme.
By default the TestNG plugin is installed in IntelliJ IDEA. You can check it in several ways but the best way is to check it is in Plugins.
Figure-5: Go to IntelliJ IDEA Plugins.
Figure-6: Check IntelliJ Plugin.
We need to create a new project and than need to setup the Automation script, so we can divide this into 2 sections:
Figure-7: Create New Project.
Figure-8: Create New Project.
Figure-9: Enter GropuId, ArtifactId and Version.
NOTE: For better project management it is better to give a proper Group Id and Artifact Id.
Click here to learn more about it.
Figure-10: Select ‘Use default gradle wrapper (recommended)’
Figure-11: Confirm Project Details.
Now, we are ready to add Appium dependencies and then start coding the first automation test case.
Figure-12: IntelliJ IDEA: Project – First Automation Test
The first step of any project setup is to download and link the needed libraries/files referred to as dependencies. Gradle and Maven are dependency management tools and have a large number of remote dependencies.
So let’s understand how Gradle works:
Figure-13: Gradle Build System
Declaring a concrete version of a dependency:
build.gradle:
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.14.0'
}
The above code snippet declares a compile-time dependency of Selenium library(.JAR file), So when you build the project Gradle will download the Selenium library having version 3.14.0 from mavenCentral(remote registry) and store it in the Gradle cache, so when you mention this same library with the same version next time on a different project, Gradle will link the library from the Gradle cache.
Here we need 2 dependencies:
Now continue to our project, open build.gradle file and add the following dependencies to the build.gradle file.
dependencies {
testCompile group: 'io.appium', name: 'java-client', version: '6.1.0'
testCompile group: 'org.testng', name: 'testng', version: '6.14.3'
}
NOTE-1: As we already have the TestNG plugin installed, we don’t need to mention the TestNG dependency but to be on the safer side and so that this project can also be imported to other IDEs such as Eclipse, and to run through the command line we need to have the dependency mentioned in build.gradle.
NOTE-2: We will be adding the Automation script under src/test directory, so in order to link the Appium and TestNG dependencies to that directory, we need to use the testCompile keyword instead of the compile keyword(which compiles the dependencies and made them accessible to src/main directory).
After mentioning the dependencies in the build.gradle, the project will be built and the mentioned dependencies will be downloaded, so now you can use Appium and TestNG classes inside the test directory.
Figure-14: build.gradle
After dependency management we need to start working on our Appium script. We will start by setting the correct set of Desired Capabilities.
What is “Desired capabilities”?
Desired Capabilities are core to Appium. They are actually a set of keys and values sent to the Appium server to tell the server what kind of automation session should be started. There are various capabilities to modify the behavior of the server during automation.
We have a dedicated chapter on desired capabilities where we will explore them in-depth, but for the sake of getting our first case test we’ll use the following desired capabilities:
Android:
{
"platformName": "Android",
"platformVersion": "8.0",
"app": "/Users/username/Downloads/sample.apk",
"deviceName": "c4e3f3cda"
}
iOS:
{
"platformName": "iOS",
"platformVersion": "11.4.1",
"app": "/Users/username/Downloads/sample.ipa",
"deviceName": "John’s iPhone",
"udid": "bea36e2b0262ae4b77bd3463bd462922ee935d24"
}
Now let’s understand these capabilities:
We will look at both an Android and iOS test case. However, please review both sections even if you are not testing on a particular platform. For each, we explore a different scenario and you will be exposed to different features. If you don’t have the specific platform, just read along so that you can get the gist of what we are doing.
AndroidDriver is the main class we will be working with. We will create an instance of AndroidDriver and we will interact with all the UI Elements of the app using that object every time.
And as we are using the TestNG framework we will put these initialization steps before the test starts, so our code will look like this:
Figure-15: AndroidDriver initialization and Desired Capabilities.
TestNG provides annotations such as @BeforeTest, @BeforeMethod, @AfterTest, @AfterMethod, @Test etc.
In the above screenshot, @BeforeTest means that the method will be called before the test, and only once. So it is standard practice to put the AndroidDriver initialization code over there, so the object of AppiumDriver becomes accessible at the end of that method and before the test.
The @Test annotation(provided by TestNG) is used to create the individual test case. So in the below code firstTest is an individual test case
@Test
public void firstTest(){}
Figure-16: Android – Sample App.
This code will find the Login Screen textview locator and simply click on it:
driver.findElement(By.id("Login Screen")).click();
Now our First Appium Automation Script is ready to execute, below is the complete code:
import io.appium.java_client.AppiumDriver;
import io.appium.java_client.android.AndroidDriver;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
import java.net.URL;
public class AndroidSampleTest {
public AndroidDriver driver;
@BeforeTest
public void setUp() throws MalformedURLException {
String appiumServerURL = "https://127.0.0.1:4723/wd/hub";
DesiredCapabilities dc = new DesiredCapabilities();
dc.setCapability("platformName", "Android");
dc.setCapability("platformVersion", "8.0");
dc.setCapability("app", "/Users/test/Downloads/FirstAutomationTest/src/test/resources/DemoApp.apk");
dc.setCapability("deviceName", "c4e3f3cd");
dc.setCapability("automationName", "UiAutomator2");
driver = new AndroidDriver(new URL(appiumServerURL), dc);
}
@Test
public void firstTest() throws InterruptedException {
driver.findElement(By.id("Login Screen")).click();
}
}
Figure-17: Appium Server is Running on 0.0.0.0:4723
Figure-18: Android device is connected.
Figure-19: Run the test case.
Figure-20: Test Result
Although we will be turning to iOS next, be sure to read this section even if you are not doing iOS testing. In this example, we get just a little more sophisticated with our test and also expose you to using an assert statement.
Figure-21:iOSDriver initialization and Desired Capabilities.
Figure-22: iOS Sample Application
The steps to automate this would be:
1. Find the locator of TextField A and enter the value (ie. Send keys) from the keyboard.
driver.findElement(By.id("IntegerA")).sendKeys(5 + "");
NOTE: The sendKeys() method accepts only String parameter, so we have converted the Integer value to a String by appending a blank String value.
2. Find the locator of TextField B and enter the second value from the keyboard.
driver.findElement(By.id("IntegerB")).sendKeys(10 + "");
3. Find the locator of ‘Compute Sum’ and click on it, so the result would be displayed below the ‘Compute Sum’ textview.
driver.findElement(By.id("ComputeSumButton")).click();
String answer = driver.findElement(By.id("Answer")).getText();
NOTE: The getText() method is used to get the Text(in String format) from UI Elements.
4. Get the text of the result and compare it with the expected result, so if you enter 5 into TextField A, 10 into TextField B and when you click on ‘Compute Sum’ textview the result 15 should be displayed under ‘Compute Sum’.
Assert.assertEquals(answer, 15 + "", "Expected and Actual Result didn't match!");
NOTE: Assert.assertEquals(expected, actual, error_message) is a TestNG method used to compare the Expected and Actual values. This is the most important step of any test case, because this is how automation test will know whether values are being rendered on UI is correct and as expected or not. You will see us using Assertions throughout this guide.
TestNG is the Testing framework and work best with Appium (Mobile Automation) and Selenium (Website Automation), you can learn more about the TestNG Annotations and methods here.
5. Below is the full code of our test which will enter 2 values into text fields. Click on ‘Compute Result’, get the result from app, and compare it with the expected result.
import io.appium.java_client.ios.IOSDriver;
import io.appium.java_client.ios.IOSElement;
import org.openqa.selenium.By;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.net.MalformedURLException;
import java.net.URL;
public class iOSSampleTest {
public IOSDriver<IOSElement> driver;
@BeforeTest
public void setUp() throws MalformedURLException {
String appiumServerURL = "https://127.0.0.1:4723/wd/hub";
DesiredCapabilities dc = new DesiredCapabilities();
dc.setCapability("platformName", "iOS");
dc.setCapability("platformVersion", "11.4");
dc.setCapability("app", "/Users/pratik/Downloads/FirstAutomationTest/src/test/resources/DemoApp-iPhoneSimulator.app");
dc.setCapability("deviceName", "iPhone X");
driver = new IOSDriver<IOSElement>(new URL(appiumServerURL), dc);
}
@Test
public void secondTest() throws InterruptedException {
int a = 5;
int b = 10;
driver.findElement(By.id("IntegerA")).sendKeys(a + "");
driver.findElement(By.id("IntegerB")).sendKeys(b + "");
driver.findElement(By.id("ComputeSumButton")).click();
String answer = driver.findElement(By.id("Answer")).getText();
Assert.assertEquals(answer, a + b + "", "Expected and Actual Result didn't match!");
}
}
You can get this example code on our github page.
Phew! We covered a lot of material in this article.
We learned the following:
Along the way you learned a little bit about desired capabilities, locators and assertions. All of this is a great grounding to continue your education into the world of Automated testing and Appium.
To learn more, download our free eBook, Make the Move to Automation With Appium.