Mobly Automation Framework
Mobly is an open-source, Python-based test framework for host-driven, end-to-end automated testing, specializing in scenarios requiring multiple devices, complex environments, or custom hardware setups. It is currently at version 1.13 and has a regular release cadence, with recent releases focusing on improvements, bug fixes, and Python 3.11+ compatibility.
Common errors
-
ModuleNotFoundError: No module named 'mobly.snippet_client'
cause Using the old, deprecated `snippet_client` import path which was removed after Mobly v1.12.fixChange the import to `from mobly.controllers.android_device_lib import snippet_client_v2` and update code to use `SnippetClientV2`. -
AttributeError: 'AndroidDevice' object has no attribute 'snippet_client'
cause Attempting to access `ad.snippet_client` on an `AndroidDevice` object after the `snippet_client` module was removed and replaced by `snippet_client_v2`.fixEnsure you are importing and using `snippet_client_v2` correctly. The common pattern is `self.dut.load_snippet('your_snippet_name', 'com.your.package.name')` which internally uses `snippet_client_v2`. -
mobly.controllers.android_device.Error: Android device serial "<SERIAL>" is specified in config but is not reachable.
cause The specified Android device (by serial or wildcard '*') is not detected by `adb devices` or is not in a ready state (e.g., USB debugging disabled, device offline).fixVerify `adb` is installed and working (`adb devices`), confirm USB debugging is enabled on the device, and ensure the device is properly connected and recognized. Check `adb logcat` for device-side issues. -
RuntimeError: Python version must be >= 3.11
cause Running Mobly with an older Python version than required.fixUpgrade your Python environment to version 3.11 or newer. You can use `pyenv` or `conda` for managing Python versions.
Warnings
- breaking Python 2 support was completely removed in Mobly v1.11. All legacy Python 2 specific workarounds and APIs are no longer available.
- breaking The minimum required Python version for Mobly was bumped to 3.11 in v1.12.3.
- deprecated The old Android snippet client (`snippet_client`), `snippet_event`, and `callback_handler` were deprecated in v1.12 and subsequently removed. The new generic Mobly snippet base client and Android snippet client (`snippet_client_v2`, `callback_handler_v2`) are now in use.
- deprecated The `get_available_host_port` function was deprecated in v1.12.3.
- breaking All SL4A (Scripting Layer for Android) related code was removed in Mobly v1.13.
- gotcha Errors raised from `teardown_class` methods do not trigger the `on_fail` callback.
Install
-
pip install mobly
Imports
- BaseTestClass
from mobly import base_test
- test_runner
from mobly import test_runner
- AndroidDevice
from mobly.controllers import android_device
- snippet_client_v2
from mobly.controllers.android_device_lib import snippet_client
from mobly.controllers.android_device_lib import snippet_client_v2
- callback_event
from mobly import snippet_event
from mobly.snippet import callback_event
- callback_handler_v2
from mobly import callback_handler
from mobly.controllers.android_device_lib import callback_handler_v2
Quickstart
# sample_config.yml
TestBeds:
- Name: SampleTestBed
Controllers:
AndroidDevice: '*'
# hello_world_test.py
from mobly import base_test
from mobly import test_runner
from mobly.controllers import android_device
class HelloWorldTest(base_test.BaseTestClass):
def setup_class(self):
# Registering android_device controller declares the test's dependency on Android devices.
# By default, we expect at least one device is found.
self.ads = self.register_controller(android_device)
self.dut = self.ads[0] # Get the first AndroidDevice object
# Start Mobly Bundled Snippets (MBS) if needed, using the updated MBS_PACKAGE constant
# You may need to install MBS on your device:
# https://github.com/google/mobly-bundled-snippets
try:
self.dut.load_snippet('mbs', android_device.MBS_PACKAGE)
except Exception as e:
self.log.warning(f"Could not load MBS snippet. Make sure it's installed: {e}")
def test_hello(self):
if hasattr(self.dut, 'mbs'):
self.dut.mbs.makeToast('Hello Mobly World!')
else:
self.log.info('MBS not loaded, skipping makeToast. Device detected.')
if __name__ == '__main__':
# To run, save config as sample_config.yml and this file as hello_world_test.py
# Then execute: python hello_world_test.py -c sample_config.yml
test_runner.main()