Get started with mobile automation: Appium & Python

Problem: There is a perception among testers that getting started with mobile automation is hard.

Why this post?

I strongly believe that a tester must have a wide range of skills. You do not need to be an expert in all of them, but it is extremely important to have contemplated a spectrum of concepts and explored a variety of tools. The context under which you test will inform you of the specific choice of testing methodology and test tools to choose. The more options you are aware of, the better your context-specific choice is going to be. In this regard, I began noticing that mobile testing has become somewhat of a niche among testers. Testers are reluctant to get started with mobile testing – probably because they think getting started involves a lot of time and effort. At Qxf2 Services, we have decided to tackle the problem head-on. This post is the second in a series of quick, easily consumable tutorials geared towards hands-on testers looking to start exploring the mobile testing landscape.

NOTE: In this post we are concentrating only on the “getting started” phase. The tools your test team uses to solve the specific and unique problems can greatly vary. There is no one silver bullet.


A little bit of history

On the eve of Christmas 2013, Selenium officially retired their own AndroidDriver and iPhoneDriver in favour of Selendroid, iosdriver and Appium. In an earlier post we explored using Selendroid and Python. In this post, we will help you get started with Appium.

Appium is an open-source tool you can use to automate mobile native, mobile web, and mobile hybrid applications on iOS and Android platforms. Appium is “cross-platform”: it allows you to write tests on multiple platforms (iOS, Android), using the same API. This enables a large or total amount of code reuse between iOS and Android test suites.


Appium setup

Here are the steps to setup Appium on Windows 7 and use it with Android emulator.
1. Download the latest Appium
I have used appium-desktop-Setup-1.5.0-ia32.exe. You can run the exe to install the appium desktop app
2. Download and Install Android Studio
Once you install Android Studio make sure the AVD Manager is also installed as we are going to run our tests on an emulator. Set ANDROID_HOME to be your Android SDK path and add the tools and platform-tools folders to your PATH variable. I could find the Android SDK installed on the below-mentioned path
$\AppData\Local\Android\Sdk

3. Install the Java JDK
Set JAVA_HOME to your JDK folder
4. Install the Python client library
There are client libraries (in Java, Ruby, Python, PHP, JavaScript, and C#) which support Appium’s extensions to the WebDriver protocol. When using Appium, you want to use these client libraries instead of your regular WebDriver client. I have used the Appium Python client available here. Assuming you have pip installed on your machine, you can use the following command to install it

pip install Appium-Python-Client

Woot! You are now set up. Next stop: launch the emulator and start the Appium server.

5. Start the Android Virtual Device (AVD) Manager
Start the Android Studio and launch the Android Virtual Device (AVD) Manager from by clicking on the link as shown in the screenshot below.
AVD_Manager

Create an emulator with the preferences you need and launch it using the start button
android_emulator
6. Start the Appium server console
Start the Appium server console by double clicking on the Appium file.

start_appium
7. Launch the Appium node server
Click on the ‘rocket’ icon to launch the Appium node server
Launch_Appium
appium_node_server_console


Your first test using Appium

For this test we will use one of my favorite Android apps – the highly recommended Chess Free application created by the UK based AI Factory. For this blog post, we will pretend that our test is to launch the application and click on “PLAY” button.

1. Obtain the .apk for the application under test
We obtained the .apk for Chess Free over here. Copy the chess application to a directory of your choice. I used ($Directory_Of_My_Choice\apps\Chess Free.apk )
2. Peek into the AndroidManifest.xml
To write the test, you need two pieces of information specific to your application:
a) Java package of the Android app you want to run
b) Activity name for the Android activity you want to launch your package

You can get this information by running the following command

ANDROID_HOME\sdk\build-tools\android-4.4.2>aapt dump badging path_to_apk_file

aapt_pkg_activity

Another approach is using the AndroidManifest.xml which is present in the root directory of all Android applications and has the information we need. You can use Android Studio to view the AndroidManifest.xml file. Go to Build/Analyze APK and select your apk. Then you can see the content of the AndroidManifset file.

package="uk.co.aifactory.chessfree" and 
android:name=".ChessFreeActivity"

3. Write the test
Create a test script (android_chess.py) in $Directory_Of_My_Choice based on the snippet below. Pay particular attention to the setup() method.

"""
Qxf2: Example script to run one test against the Chess Free app using Appium
The test will:
- launch the app
- click the 'PLAY!' button
"""
 
import os
import unittest
from appium import webdriver
from time import sleep
 
class ChessAndroidTests(unittest.TestCase):
    "Class to run tests against the Chess Free app"
    def setUp(self):
        "Setup for the test"
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '8.0'
        desired_caps['deviceName'] = 'Pixel'
        # Returns abs path relative to this file and not cwd
        desired_caps['app'] = os.path.abspath(os.path.join(os.path.dirname(__file__),'apps/Chess Free.apk'))
        desired_caps['appPackage'] = 'uk.co.aifactory.chessfree'
        desired_caps['appActivity'] = '.ChessFreeActivity'
        self.driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
 
    def tearDown(self):
        "Tear down the test"
        self.driver.quit()
 
    def test_single_player_mode(self):
        "Test the Chess app launches correctly and click on Play button"
        element = self.driver.find_element_by_id("uk.co.aifactory.chessfree:id/ButtonPlay")
        element.click()
        sleep(5)
 
#---START OF SCRIPT
if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(ChessAndroidTests)
    unittest.TextTestRunner(verbosity=2).run(suite)

4. Run the test
Run the script android_chess.py. The chess application is launched in the test emulator
Run_Chess_App
5. Check the result
appium_test_run

Celebrate a little – you just upgraded your skills by a little bit in a very short span of time!

There you have it! You have just run your first mobile automated test with Appium and Python. If you are looking for Python based mobile automation framework, check out our open-sourced GUI and API automation framework based on the page object model. Happy exploring from Qxf2 Services!

P.S.: As a chess fanatic, I think it is a crime to test chess applications in an automated fashion. I sincerely believe infinite manual testing is the only correct way to test chess applications 😉

P.P.S: We were pleasantly surprised by positive reaction we got to our last tutorial on mobile application testing with Selendroid. Please chime in on the direction you want our future blog posts to go. We will try our best to keep churning out useful posts for testers.


110 thoughts on “Get started with mobile automation: Appium & Python

  1. HI

    This was way beyond helpful. However im running into an issue while using appium behind a proxy wall. The error seems to start from line

    self.driver = webdriver.Remote(‘http://localhost:4723/wd/hub’, desired_caps)

    Im getting connection refused error. I used the same environment at home and worked perfectly. How can i take care of this ?

  2. Hi,

    I tried to execute below program:

    “””
    Qxf2: Example script to run one test against the Chess Free app using Appium
    The test will:
    – launch the app
    – click the ‘PLAY!’ button
    – choose single player mode
    “””

    import os
    import unittest
    from appium import webdriver
    from time import sleep

    class ChessAndroidTests(unittest.TestCase):
    “Class to run tests against the Chess Free app”
    def setUp(self):
    “Setup for the test”
    desired_caps = {}
    desired_caps[‘platformName’] = ‘Android’
    desired_caps[‘platformVersion’] = ‘4.2’
    desired_caps[‘deviceName’] = ‘Android Emulator’
    # Returns abs path relative to this file and not cwd
    desired_caps[‘app’] = os.path.abspath(os.path.join(os.path.dirname(__file__),’D:\Programs\myapp\Chess Free.apk’))
    desired_caps[‘appPackage’] = ‘uk.co.aifactory.chessfree’
    desired_caps[‘appActivity’] = ‘.ChessFreeActivity’
    self.driver = webdriver.Remote(‘http://localhost:4723/wd/hub’, desired_caps)

    def tearDown(self):
    “Tear down the test”
    self.driver.quit()

    def test_single_player_mode(self):
    “Test the Single Player mode launches correctly”
    element = self.driver.find_element_by_name(“PLAY!”)
    element.click()
    self.driver.find_element_by_name(“Single Player”).click()
    textfields = self.driver.find_elements_by_class_name(“android.widget.TextView”)
    self.assertEqual(‘MATCH SETTINGS’, textfields[0].text)

    #—START OF SCRIPT
    if __name__ == ‘__main__’:
    suite = unittest.TestLoader().loadTestsFromTestCase(ChessAndroidTests)
    unittest.TextTestRunner(verbosity=2).run(suite)

    Getting below error:

    test_single_player_mode (__main__.ChessAndroidTests)
    Test the Single Player mode launches correctly … ERROR

    ======================================================================
    ERROR: test_single_player_mode (__main__.ChessAndroidTests)
    Test the Single Player mode launches correctly
    ———————————————————————-
    Traceback (most recent call last):
    File “D:/Programs/myapp/android_chess.py”, line 26, in setUp
    self.driver = webdriver.Remote(‘http://localhost:4723/wd/hub’, desired_caps)
    File “D:\Programs\Python275\lib\site-packages\appium\webdriver\webdriver.py”, line 36, in __init__
    super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 92, in __init__
    self.start_session(desired_capabilities, browser_profile)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 179, in start_session
    response = self.execute(Command.NEW_SESSION, capabilities)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 236, in execute
    self.error_handler.check_response(response)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\errorhandler.py”, line 192, in check_response
    raise exception_class(message, screen, stacktrace)
    WebDriverException: Message: A new session could not be created. (Original error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c “java -jar D:\Programs\Appium\node_modules\appium\node_modules\appium-adb\jars\sign.jar “D:\Programs\myapp\Chess Free.apk” –override”
    java.util.zip.ZipException: error in opening zip file

    at java.util.zip.ZipFile.open(Native Method)

    at java.util.zip.ZipFile.(Unknown Source)

    at java.util.zip.ZipFile.(Unknown Source)

    at java.util.jar.JarFile.(Unknown Source)

    at java.util.jar.JarFile.(Unknown Source)

    at s.Sign.sign(Sign.java:441)

    at s.Sign.main(Sign.java:532)

    Would you please help me to solve this error?
    Thank you.

  3. Hi,

    Thanks for the nice post, its very useful.

    I am getting below error while running the same program mentioned in your post:
    ERROR: test_single_player_mode (__main__.ChessAndroidTests)
    Test the Single Player mode launches correctly
    ———————————————————————-
    Traceback (most recent call last):
    File “D:/Programs/myapp/android_chess.py”, line 26, in setUp
    self.driver = webdriver.Remote(‘http://localhost:4723/wd/hub’, desired_caps)
    File “D:\Programs\Python275\lib\site-packages\appium\webdriver\webdriver.py”, line 36, in __init__
    super(WebDriver, self).__init__(command_executor, desired_capabilities, browser_profile, proxy, keep_alive)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 92, in __init__
    self.start_session(desired_capabilities, browser_profile)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 179, in start_session
    response = self.execute(Command.NEW_SESSION, capabilities)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\webdriver.py”, line 236, in execute
    self.error_handler.check_response(response)
    File “D:\Programs\Python275\lib\site-packages\selenium\webdriver\remote\errorhandler.py”, line 192, in check_response
    raise exception_class(message, screen, stacktrace)
    WebDriverException: Message: A new session could not be created. (Original error: Command failed: C:\WINDOWS\system32\cmd.exe /s /c “java -jar D:\Programs\Appium\node_modules\appium\node_modules\appium-adb\jars\sign.jar “D:\Programs\myapp\Chess Free.apk” –override”
    java.util.zip.ZipException: error in opening zip file

    at java.util.zip.ZipFile.open(Native Method)

    at java.util.zip.ZipFile.(Unknown Source)

    at java.util.zip.ZipFile.(Unknown Source)

    at java.util.jar.JarFile.(Unknown Source)

    at java.util.jar.JarFile.(Unknown Source)

    at s.Sign.sign(Sign.java:441)

    at s.Sign.main(Sign.java:532)

    Would you please help me to solve this issue?
    Thank you.

  4. Hi, thanks a lot for the detailed explanation. Is there some reason you prefer Python over other languages? Because the Github repos of Appium Ruby & Java are updated frequently, whereas Appium python repo is not

    1. Chandra Sekar, We find the code in the Appium Python repo sufficient for our testing needs. So the regularity of the updates does not matter too much to us.

      Python, Ruby, Java are all good for what we are trying to do. There is no reason to get into a language flame war. Here is why we started with Python and continue to use it:

      1. We like Python. We are good with Python. We were used to Python.
      2. We found Python more than sufficient for our needs. A lot of the top companies (Google, Facebook, etc.) use Python extensively for their scripting needs.
      3. Python is easy to pick up. Most of our employees pick up Python after they join Qxf2.
      4. Python is portable and less susceptible to version changes.
      5. Python has a lot of potential. Python is becoming the industry’s top choice for scientific and mathematical programming. And those are areas we are interested in exploring.

      1. Awesome list! 🙂 love your answers.
        I am familiar with Python, while in my past life used C++. I am thinking of choosing Python now when deciding to start with Appium (as opposed to Java, that would seem close to C++, natural for me to pickup). Python is super friendly.

  5. Hi,

    I am new to this appium how to start with basics automation testing in android and ios and I am new to a programming language also

    1. Hi,
      The tutorials/examples in all our blogs are designed for anyone with beginner level of expertise in Python. Please follow the instructions in this blog,it will help you get the mobile automation environment setup and get you going with a basic mobile automation test.

  6. Hello,

    I have Appium version 1.6.5, when running example it reports error:
    InvalidSelectorException: Message: Locator Strategy ‘name’ is not supported for this session

    When narrow-down it seems that
    .find_element_by_name
    .find_elements_by_class_name
    are not supported in latest versions of Appium anymore.

    I was able to use this for the name:
    find_element_by_xpath(“//*[contains(@text, ‘PLAY!’)]”)
    but this doesn’t work for class_name.

    Any suggestions?
    I would really like to be able to complete the jump-start example 🙂

    Thanks a lot!
    Billiana

    1. Billiana, I haven’t tried this, but the general way to write an xPath based on class name would be:

      //class[@some_attribute="blah"] OR //class[contains(@some_attribute,"blah")]

      So, in your case, it is probably something like find_elements_by_xpath("//android.widget.TextView").

      Try it and let us know if it does not work. We can try the example out with Appium 1.6.5 and figure out the solution.

      1. This is great Arunkumar, thanks a lot for your support.
        Yes, your example worked perfectly. I was able to get list of all elements and then select one with actual attribute value afterwards.
        Alternatively, I have tried specifying text value inline, that worked too.
        Your blog is the best! simple and to the point, also fun. Keep up the great work.

  7. Hi, I am getting the below error. Please help
    from webdriver import WebDriver as Remote
    ModuleNotFoundError: No module named ‘webdriver’

    1. Hi SJ,
      From your question description, I see that you are importing webdriver incorrectly. It should be from appium import webdriver . If thats not the case then check whether appium is installed correctly and appium is started before you run your tests. If doing above changes don’t fix the issue then let us know the python version you are using.

  8. I want to start iOS mobile automation and have chosen Appium. I’m confused if I should use Appium-Java/Python. I know it’s a personal choice to choose a programming language. The major concern here is does the python client will have less API support compare to JAVA? I understand python is a lot easier than JAVA. I just don’t want to get stuck at some point when using python because it doesn’t have much API support.

    1. Hi Prameet,
      I don’t think that python client has less API support compared to Java. Yes, there may be less StackOverflow support.
      But here is why we started with Python and continue to use it:

      1. We like Python. We are good with Python. We were used to Python.
      2. We found Python more than sufficient for our needs. A lot of the top companies (Google, Facebook, etc.) use Python extensively for their scripting needs.
      3. Python is easy to pick up. Most of our employees pick up Python after they join Qxf2.
      4. Python is portable and less susceptible to version changes.
      5. Python has a lot of potentials. Python is becoming the industry’s top choice for scientific and mathematical programming. And those are areas we are interested in exploring.

      1. Thanks for your information. I am fine with there is a little less support. I like the way you described the use of python. My main focus at this moment is w.r.t appium python client for iOS mobile app automation. Have you personally experienced the usage of appium-python-client with mobile automation? I am personally more inclined to use python but due to less experience I find it a little difficult to take a decision on it. Just wanted to double-check if you reply specifically includes appium-python client.

        I appreciate your quick response.

      2. Yes, we used python appium client for all our mobile automation. That works fine for us.

        Thanks,
        Indira Nellutla

  9. Thanks you all for your response. One more question, is there any sample where I can see the current best practises being used to create a test suite model using pytest? I got this one “https://github.com/aws-samples/aws-device-farm-appium-python-tests-for-ios-sample-app/tree/master/tests”. Please do let me know if there is any other good resources.

Leave a Reply

Your email address will not be published.