How To Use Selenium for Mobile Cross Browser Testing

  January 21, 2016

As you know, Appium is based on the WebDriver JSON Wire Protocol and therefore works extremely well also for mobile web testing. Being a subset of the Selenium, it also provides infrastructure, platform and language-agnostic interfaces that are compatible with all major web browsers – also on Android and iOS. In this blog, I’ll walk you through a basic example of how to use Appium / Selenium for mobile cross browser testing using real Android and iOS devices and real web browsers on these platforms.

using selenium for mobile cross browser testing

As said, Appium works really well as a bridge between the mobile test automation approach and web testing done with Selenium WebDriver. With Appium, the power of Selenium in cross browser testing can be now taken on mobile devices and more importantly – mobile browsers and do mobile cross-browser testing across different browsers and device configurations. One of the greatest things with this kind of combination is that it fits perfectly into an agile process and makes full use of test automation – but now also for the mobile web. You can use Appium to write Selenium test scripts for mobile browsers and then easily scale the number of devices and browsers you use for testing up to hundreds.

Download The Guide to Succeed in Mobile Cross Brower Testing

Mobile Cross Browser Testing with Any Language for All Platforms

Another awesome aspect of Appium / Selenium for mobile cross browser testing is that it works with any programming language as well as both these major OS platforms (Android and iOS). This means you have more freedom on the language you use and you can build the same script for both of these OS platforms. The same test script, API and the workflow back up testing on native apps, mobile games, hybrid apps and the mobile web. Furthermore, your application either as APK or IPA doesn’t need any modifications or tweaks to make it testable with Appium.

As Appium is an open-source project that can be downloaded and use freely to run tests on your localhost with emulators and real devices, we always recommend using real devices and real browsers for testing efforts done on any sort of mobile product targeted for a mass audience. There are several things you should take into consideration whether using emulators or real devices, but the fact is that all end-users using your stuff will use those real devices. Getting something ‘verified’ on emulators, unfortunately, doesn’t mean much. In fact, it may be even difficult – if not impossible – to get certain mobile web browsers working on emulators.

There are different ways available for Appium test automation: client-side and server-side execution. The following picture illustrates the difference between these two:

client-side vs. server-side concept

The difference between running your test script from localhost and running it on Bitbar Testing is really small, but benefits are different. In both cases, your test script would run the app or website on those mobile devices (and web browser) we host at Bitbar Testing. In Server-Side Execution, you don’t need to configure desired capabilities but things work based on your preferences. For the cross-browser testing and having your website running on as many devices and browsers as possible before you launch or made something available for users is always highly recommended. And the good news is that both of these approaches are usable for your cross-browser testing.

Let’s look at the example of how a simple test can be created using Python and have it executed on a real device and a real browser on the cloud.

Python Example – Run Mobile Web Tests on Real Web Browser

I’ll be using Python here and if you need any instructions on how to set up Python, Selenium and any other required component, take a look at this. It provides step-by-step instructions on how to get everything properly installed.

First, in your test scrips import the following modules:

import os
import time
import unittest
from time import sleep
from selenium import webdriver
from device_finder import DeviceFinder

You can find device_finder.py at Github. Simply download it and locate this file on the same folder where you’ll be running your Python test script.

To make test script output real-time information about the progress or any information that you might need while the test is running, it’s a good idea to write few helper functions – for example, to output ‘debugging’ information to your console:

def log(msg):
    print (time.strftime("%H:%M:%S") + ": " + msg)

If you are running the test on server-side this data will be available on Appium log that you find under Device Run view on Bitbar Testing:

device files logs

When tests are executed simultaneously on a variety of different devices (regardless whether those are Android or iOS) you should always strive to take screenshots as they will illustrate how the app looks on the device and if there are any visual aspects to be fixed. Simply, create a function for taking and saving screenshots with the following function:

def screenshot(self, name):
    self.screenShotCount = 1
    screenshotName = str(self.screenShotCount) + "_" + name + ".png"
    log ("Taking screenshot: " + screenshotName)
    sleep(1) # wait for animations to complete before taking screenshot
    self.driver.save_screenshot(self.screenshotDir + "/" + screenshotName)
    self.screenShotCount += 1

After your test run is done the taken screenshots will be available on Test Run view:

screenshots for selenium tests on real mobile devices for cross browser testing

Or if you are using client-side execution and you want to fetch screenshots to your local environment, you defined this with TESTDROID_SCREENSHOTS environment variable:

self.screenshotDir = os.environ.get('TESTDROID_SCREENSHOTS') or "/Users/vvh/pywebtest/screenshots"

In order to establish a connection between your localhost and Bitbar Testing, you’ll need to configure these few parameters:

testdroid_url = os.environ.get('TESTDROID_URL') or "https://cloud.testdroid.com/"
testdroid_apiKey = os.environ.get('TESTDROID_APIKEY') or "123456789abcdefghijklmnopqrstuvx"
appium_url = os.environ.get('TESTDROID_APPIUM_URL') or 'http://appium.testdroid.com/wd/hub'

Note that we’re now using API Key to authorize access between the localhost and Bitbar Testing. The API Key can be fetched from Bitbar Testing -> your profile (top right corner) -> My account and API key. Simply copy that and paste into your testdroid_apiKey variable:

bitbar api key

The next thing to do is to secure any available device for your test session. We’ve built a basic device finder function to help in that and speed up the device acquisition for your test runs. Basically it will go through available devices and pick you the one. Furthermore, you can define the device with testdroid_device variable. You can find more information – as well as some tips and tricks using this function in this blog.

deviceFinder = None
testdroid_device = os.environ.get('TESTDROID_DEVICE') or "Samsung Galaxy Tab 3 10.1 GT-P5210 4.4.2"
deviceFinder = DeviceFinder(url=testdroid_url)
   if testdroid_device == "":
      # Loop will not exit until free device is found
      while testdroid_device == "":
            testdroid_device = deviceFinder.available_free_android_device()

If you want to find an available iOS device for your test session, you would use available_free_ios_device instead of deviceFinder.available_free_android_device() in that last line.

Setting Up Desired Capabilities

If you are using client-side execution you basically need to have all these desired capabilities properly configured in your test script. With the server-side execution, there is no need to configure any of those as the app and test are already uploaded on our server and it will fetch all this information based on your projects, device selections and test run preferences.

Here is the example of desired capabilities on client-side execution:

desired_capabilities_cloud = {}
desired_capabilities_cloud['testdroid_apiKey'] = testdroid_apiKey
desired_capabilities_cloud['testdroid_target'] = 'chrome'
desired_capabilities_cloud['testdroid_project'] = 'Appium Chrome Webtest Demo'
desired_capabilities_cloud['testdroid_testrun'] = 'Test Run 1'
desired_capabilities_cloud['testdroid_device'] = testdroid_device
desired_capabilities_cloud['platformName'] = 'Android'
desired_capabilities_cloud['deviceName'] = 'AndroidDevice'
desired_capabilities_cloud['browserName'] = 'chrome'
desired_caps = desired_capabilities_cloud;

These desired capabilities can be configured based on your preferences, how and on what device you want tests to be executed.

Using Real Mobile Devices with Selenium for Cross Browser Testing

To launch several simultaneous device runs (devices running your tests at the same time) you can build an instigator script with an array of devices to specify all devices you want to start your run on:

AndroidDeviceList = [“Acer Iconia Tab 8 A1-840FHD US”,
                        “Asus Google Nexus 7 ME370T 4.3 JWR66Y”,
                        “Dell Venue 8 3840 EU”,
                        “HTC One M7 5.0.2”,
                        “HTC One M9”,
                        “Huawei Honor 6 H60-L01”,
                        “LG Google Nexus 5 6.0”,
                        “Lenovo Lemon K3 K30-T”,
                        “Motorola DROID RAZR HD XT926”,
                        “Motorola Google Nexus 6 XT1100 5.1 EU”,
                        “NVIDIA Shield Tablet”,
                        “Samsung Galaxy Note 5 SM N920R4”,
                        “Samsung Galaxy S5 SM-G900T (T-Mobile) -US”,
                        “Samsung Galaxy Tab 4 10.1 SM-T530NU”,
                        “Sony Xperia Tablet Z”,
                        “Sony Xperia Z SO-02E (Sony Yuga)”,
                        “Xiaomi MI 3 (Tegra 4 powered)”,
                        “Xiaomi Redmi 2 LTE”,
                        “Yota Phone 2 YD201”,
                        “ZTE V5 Red Bull U9180”
]
...
for each device in AndroidDeviceList:
    testdroid_device =  DeviceFinder.getDevice(device)
       if testdroid_device is not None:
          break

With the server-side execution this would be very convenient as you can manually select on which device group you want to use for test session:

running selenium tests on real mobile devices for cross browser testing

Once the device selection is done, you can also specify which browser will be used for the test session (as set in ['browserName'] = 'chrome' variable). With Android, we support pretty much any browser available (however, typically the only meaningful ones are the Android Browser or Chrome) and on iOS Safari is pretty much the one you want to use for your test session.

Creating and Running A Mobile Browser Test

After all these steps have been done, let’s look at how to use WebDriver to get the test running. First, you need to initiate the WebDriver. Note that if you are using client-side execution this really may take some time as the device will be prepared for your session. If you didn’t use Finder Device, the device may not be either available and WebDriverException is thrown saying that the device could not be acquired at certain time.

log ("WebDriver request initiated. Waiting for response, this typically takes 2-3 mins")
self.driver = webdriver.Remote(appium_url, desired_caps)

To specify which web page will be used for testing will be done next, with the action to take a screenshot of it, as follows:

log ("Loading page https://bitbar.com/testing/")
self.driver.get("https://bitbar.com/testing/")
log ("Taking screenshot of home page: '1_home.png'")
self.driver.save_screenshot(self.screenshotDir + "/1_home.png")

Next you can call some interaction (e.g. click) on certain UI elements or links on that page – and take the screenshot of the view:

log ("Finding 'Solutions'")
elem = self.driver.find_element_by_xpath('//*[@id="menu"]/ul/li[1]/a')
log ("Clicking 'Solutions'")
elem.click()
log ("Taking screenshot of 'Products' page: '2_products.png'")
self.driver.save_screenshot(self.screenshotDir + "/2_products.png")

Furthermore, you can use XPath locators to find certain elements in that web page.

Quit the WebDriver Session

Finally, you can call tearDown to quit WebDriver:

def tearDown(self):
   log ("Quitting")
   self.driver.quit()

If you are interested to fetch this example we just walked through you can find the template at Github.

Happy Web Testing folks!