4 Tips for Better Mobile App Testing
Adam Creamer
Appium, a popular tool for automating mobile app testing, offers a variety of features and capabilities that can significantly enhance testing efficiency and effectiveness. In this article, we delve into the world of Appium, exploring a range of tips and tricks designed to maximize your potential of this powerful tool.
Whether you’re a beginner or an experienced tester, these insights will help you streamline your testing process, troubleshoot common challenges, and harness the full power of Appium in your mobile application development cycle.
How to check whether an Android app is already installed or not?
There are scenarios in which you want to check out whether your Android app is already installed on the device or not, but why would you need that? A very simple (but common!) use case requires testing a part of the app that is only accessible to logged-in users. So every time you execute your test case, the first step would be to login which is a time consuming operation (from an execution perspective). We can skip the login if we’ve already logged in on the previous test execution, as it takes unnecessary time. We can do 2 things:
Now the question is how would you fire this command within your programming language? In Java this is done using the ProcessBuilder class: String line; Process p = Runtime.getRuntime().exec(“adb shell pm list packages”); BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream())); while ((line = input.readLine()) != null) { System.out.println(line); } input.close();
How to enable mouse pointer location on Android at runtime?
If there is no unique locator assigned to a UI element, then the only option is to tap on a particular point. By enabling “pointer location” in developer options in Android, we can get the x, y coordinates for any point. Moreover, having the mouse pointer location helps so much in debugging, especially, whenever you are dealing with swipe, touch, and scroll functions in Appium. But what if you are dealing with remote devices (such as Kobiton or BrowserStack devices)? There are case in which you cannot access the remote device before executing the automation test cases. So, you will need some way to enable the pointer location on that devices at run time. If you want to enable mouse pointer location using the terminal then fire command: $ adb shell settings put system pointer_location 1 [Use 0 for disable] In Java you can use this code: public static void main(String[] args) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(“adb”, “shell”, “settings”, “put”, “system”, “pointer_location”, “1”); Process pc = pb.start(); pc.waitFor(); System.out.println(“Finish!”); } You can find this example on our github page: https://github.com/appiumbook/appiumbook/blob/master/Chapter13-Appium%20Tips%20and%20Tricks/src/test/java/testcases/AndroidADBCommands.java
How to capture Screenshots On Test Failure?
This is the most vital feature of Appium (and Selenium). Practically speaking, with automation, you are not observing the execution of all test cases, so in case a failure occurs you won’t have the exact details of the failure. That’s why this feature comes in handy, because it will capture the screenshot whenever a failure occurs. And by looking at the screenshot sometimes you can quickly figure out the failure cause without taking a look at the error log.
Note: Cloud device platforms like Kobiton offer the ability to automatically take not only screenshots of every action, but also record full video of your test sessions as well as detailed Appium and device logs. Below is the code you use to capture a screenshot: private void takeLocalScreenshot(String imageName) throws IOException { File scrFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE); FileUtils.copyFile(scrFile, new File(“failureScreenshots/” + imageName + “.png”)); } But we need to call this method only if test cases are failing or being skipped. Thus we need to check the status of the test case, and, as we are using the TestNG test framework, we can use its methods to check the status of the executing test case.
@AfterMethod(alwaysRun = true) public void afterMethod(final ITestResult result) throws IOException { if (result.getStatus() == ITestResult.FAILURE || result.getStatus() == ITestResult.SKIP) { takeScreenshot(result.getMethod().getMethodName().toLowerCase() + “_” + System.currentTimeMillis()); } This code example works for both iOS and Android.
How to dismiss dialogs/alerts automatically?
In mobile application notifications, popups and dialogs occur at random. In order to access the app, we must handle that immediately as soon as they appear. Appium can handle the system dialogs/alerts in 2 ways:
Auto Accept the Alerts: capabilities.SetCapability(“autoAcceptAlerts”, true); Auto Dismiss the Alerts: capabilities.SetCapability(“autoDismissAlerts”, true); In some scenarios, when you are not able to get the dialog elements, you can leverage the Appium image comparison feature and find the element by image. We will look more into that feature in a subsequent chapter.
How to handle notifications in Android?
Push notification assertion is a common exercise you need to be familiar with because many apps send a push notification while you are accessing the app. Appium provides a super easy way to open notifications – you just have to call the openNotifications() method. You can get the title of the notification using android:id/title and the content of the notification using android:id/text locators.
For example: driver.openNotifications(); List titleElement = driver.findElements(By.id(“android:id/title”)); List contentElement = driver.findElements(By.id(“android:id/text”)); for (int i = 0; i < titleElement.size(); i++) { System.out.println(titleElement.get(i).getText() + ” : ” + contentElement.get(i).getText()); } See AndroidTricks.java on our github repository. NOTE: driver.openNotifications() method only applies to AndroidDriver object. It is not available for IOSDriver.
How to make test cases fail fast in order to quickly get an error message?
As strange as the name of this trick may sound, there are cases when you want to fail your test cases faster in order to get the error message to fix the test case. Using the newCommandTimeout desired capability you can specify the time in seconds for which Appium will wait for a new command from the client before assuming the client quit and ending the session. capabilities.setCapability(“newCommandTimeout”, 15); If you are executing the test cases locally, you want them to fail quickly.
Ideally, you should wait for 10 to 20 seconds (depends on app) because during that time, the app will load all the resources. With remote devices, due to network latency and other reasons, apps on remote device may take more time to load the resources. So, for remote execution, that time period should be closer to 60 seconds.
How to handle the hide_keyboard() method?
Essentially, it’s as simple as calling hide_keyboard(). However, the hide_keyboard() method works differently on iOS and Android because the internal architecture of the soft keyboard on both platforms is not the same. It also depends on the physical device model and its operating system version. Therefore, the standard practice is you should put the hide_keyboard() method in a try/catch block. try { driver.hide_keyboard(); } catch(Exception e) {}
How can you write test cases faster?
How to handle to mobile data, wifi and airplane mode in Android?
In order to automate various connectivities such as mobile data, wifi and airplane mode, Appium provides a ConnectionState class for setting and getting the network connection for a connected android device/emulator. For example if you want to turn on only wifi (Not mobile data and airplane mode), you can use this command: ConnectionState state = driver.setConnection(new ConnectionStateBuilder() .withWiFiEnabled() .build()); You can see the example on: Example link This API works based on the android device OS versions so please go through the official appium documentation in order to get more information. NOTE: The above mentioned APIs are not available for iOS.
How to switch context?
There are two main types of context in Appium:
While we are working with a native application, the context will be NATIVE. And when webview is being used on some screen, it will have the WEBVIEW context. Sometimes, you actually have both in a single application. You might have experienced the webview when you are dealing with payments in an application- generally the payments page is integrated the in form of webview (being provided by the payment gateway). So, in that case, you need to change the application context from NATIVE to WEBVIEW in order to get control of WEBVIEW elements.
Using the code below, you can get the current context of your app: String context = driver.getContext(); In a similar way, you can get the all contexts available to automate using: Set contextNames = driver.getContextHandles(); And by using this code, you can change the context to WEBVIEW: driver.context(“WEBVIEW”); You can use the this method in order to change the context to WEBVIEW if it is found: public void changeDriverContextToWebView(AppiumDriver driver) { Set contextHandles = driver.getContextHandles(); for (String name: contextHandles) { if (name.equals(“WEBVIEW”)) driver.context(name); } }
How can you minimize and reopen the app again?
There are some scenarios where you need to minimize the application and need to re open it without killing the current session. Using the runAppInBackground(Duration time) method, you can hide your application for a particular duration. For example, if you want to minimize application for 5 seconds, then you might use: driver.runAppInBackground(Duration.ofSeconds(5));
How to start Appium Server programmatically?
In all our examples up until now, we have presumed that you have started the Appium server explicitly using the command line or using the Appium Desktop application. Now, when you are thinking to integrate Appium UI test cases with Jenkins (or generally within in a CI/CD pipeline), you have two options to start the Jenkins server:
Here, option 1 is not advisable because if a test failure occurs then the Appium server will be continuously running and occupying memory of the physical server. While in option 2, we have server quit code written at the end of execution, so even if failure occurs, it will quit the Appium server and free the space in memory. You can start the server using 2 classes:
So let’s look into the example of both classes: AppiumDriverLocalService: AppiumDriverLocalService appiumDriverLocalService = AppiumDriverLocalService.buildDefaultService(); public void setUpPage() throws IOException { AppiumDriverLocalService appiumDriverLocalService = AppiumDriverLocalService.buildDefaultService(); appiumDriverLocalService.start(); } public void tearDownAppium() { super.tearDownAppium(); appiumDriverLocalService.stop(); } In the above example Appium will start the server using default url and port. You can find this example at: AppiumDriverLocalServiceTest.javaAppiumServiceBuilder: AppiumServiceBuilder builder; AppiumDriverLocalService appiumDriverLocalService; public DesiredCapabilities getDesiredCapabilities() { DesiredCapabilities desiredCapabilities = new DesiredCapabilities(); … return desiredCapabilities; } public void startServer() throws IOException { DesiredCapabilities desiredCapabilities = getDesiredCapabilities(); AppiumServiceBuilder builder = new AppiumServiceBuilder(); builder.withIPAddress(“127.0.0.1”); builder.usingPort(4729); builder.withCapabilities(desiredCapabilities); builder.withArgument(GeneralServerFlag.SESSION_OVERRIDE); builder.withArgument(GeneralServerFlag.LOG_LEVEL, “error”); appiumDriverLocalService = AppiumDriverLocalService.buildService(builder); appiumDriverLocalService.start(); } public void stopServer() { appiumDriverLocalService.stop(); } Here as you can see appium will use Port: 4729, URL: 127.0.0.1 with some Desired Capabilities and flags. You can find this code at: AppiumServiceBuilderTest.java
Hopefully you found (or will find!) these tips and tricks useful as you progress your journey of being an Appium expert. The Appium community is constantly expanding and you’ll find tremendous tips and tricks shared by other developers and testers. Keep reading forums and blogs to keep your knowledge up to date.