If you have fast machine and recent Google Chrome or Safari installed, please check a bit more "moving" version of that presentation

Otherwise, scroll down to see the slides

Writing Monkeyrunner Tests

in Python

What is android monkeyrunner ?

Monkeyrunner

Python script in PC

Communicate with monkey daemon on device via adb

Control Android device

Multiple device control

Functional testing

Extensible automation

Example


# Import monkeyrunner
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice

# Get the android device
device = MonkeyRunner.waitForConnection()

# Install apk to device
device.installPackage('myproject/bin/MyApp.apk')
# Start a new activity
device.startActivity(component='com.myapp/.MainActivity')

# Press down/up menu key
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
# Take snapshot and save it to file
result = device.takeSnapshot()
result.writeToFile('myproject/shot1.png','png')
  

How to manage tests ?

Encapsulate tests using unittest module !

Example

Using unittest to manage monkeyrunner tests


# Import TestCase
from unittest import TestCase

class MyTest(TestCase):
  def setUp(self):
    # setup code here
    pass

  def test_LoopLaunch(self):
    # testing code here
    # ......
    device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
  

Assert what ?

Comparing snapshot !

and OCR !

Recording snapshot & OCR firstly.

Comparing snapshot & OCR while testing.

ONE test script for both recording and testing.

Methods need to be implemented


# assert current screen with recorded one
assertCheckImage(...)
# wait for recorded screen or timeout
assertWaitForScreen(...)
# assert OCR text
assertCheckString(...)
# wait for recorded OCR text
assertWaitForString(...)
  

Example


def test_example(self):
  # some test steps
  device.press(...)
  sleep(...) # sleep until phone gets response
  # and then assert/recording
  self.assertCheckImage(...)
  # other steps like above
  # ......
  

That’s what we have done before.

How about next ?

Is there a readable way to write test steps ?

Chained invocation !

User input serial is likely to be method invocation chain.


def test_example(self):
  # some test steps
  device.shell(...) \
        .startActivity(...) \
        .press(...) \
        .tap(...) \
        .expectImage(...) \
        .press(...) \
        .expectImageUntilTimeout(...)
  

Maintainable code architecture !

Packaging !


# file: package/__init__.py
__all__=["BaseClass", ...]

import impl.BaseClassImpl1 as BaseClass
# We may have other impl of BaseClass, but here we only
# export impl.BaseClassImpl1 as BaseClass.
  

Mixin !


# file: package/impl.py
__all__ = ["BaseClassImpl1", "BaseClassImpl2"]

class BaseClassImpl1(Base, AssertImpl1, DevImpl):
  pass
class BaseClassImpl2(Base, AssertImpl2, DevImpl, ReportImpl):
  pass
# Here AssertImpl1/AssertImpl2, DeviceImpl, ReportImpl are
# mixins. We can using mixin to add new feature to the class
# or replace old mixin with new one.
  

Pub/Sub !

Cross module communication:

Send message cross Test, TestRunner, DataUploader, DeviceMonitor, etc.


# module a.py
from pubsub import pub
def listener1(arg1, arg2=None):
    print 'received:  arg1="%s"  arg2="%s"' % (arg1, arg2)
pub.subscribe(listener1, 'rootTopic')
  

# module b.py
from pubsub import pub
pub.sendMessage('rootTopic', arg1=123, arg2={'a':'abc'})
  

Other thoughts

Assert on View Hierarchy


from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
from com.android.monkeyrunner.easy import EasyMonkeyDevice
from com.android.monkeyrunner.easy import By

device = MonkeyRunner.waitForConnection()
# Use the EasyMonkey API, all methods on device are available
# in easy_device.
easy_device = EasyMonkeyDevice(device)

if not easy_device.visible(By.id('id/all_apps_button')):
    raise Error('Could not find the "all apps" button')

print "Location of element:", 
print easy_device.locate(By.id('id/all_apps_button'))

easy_device.touch(By.id('id/all_apps_button'), 'DOWN_AND_UP')
  

Upload all test data to server.

Thanks & QA

Use a spacebar or arrow keys to navigate