Mobile Test Orchestrator (MTO) provides APIs to orchestrate test execution against Android devices. It allows users to define a test plan, which is a test suites collection. The test plan can be executed on Android emulators, as well as real devices. The API provides the fundamentals to have seamless user experience to run distributed test on real devices or emulators.
Key features include:
- Capture of full logcat during execution of the test plan.
- File position within the logcat file to mark the beginning and end of a test suite, and each test.
- Monitor specific tags from logcat during execution.
A test plan is an iterator over a collection of test suites, which can be created out of androidtestorchestrator.TestSuite
class
from androidtestorchestrator import TestSuite
# arguments to be passed to the am instrument command, run as "am instrument -w -r [arguments] <package>/<runner> "
test_suite = TestSuite(name='test_suite1', arguments=["--package", "com.some.test.package"])
test_plan = iter([test_suite])
An orchestrator can execute the test plan. A androidtestorchestrator.TestListener
will report the test result as execution proceeds.
A androidtestorchestrator.Device
is intended to be a direct bridge to the same functionality as adb, with minimized embellishments.
from androidtestorchestrator import AndroidTestOrchestrator, TestSuite, TestRunListener
from androidtestorchestrator.device import Device
from androidtestorchestrator.application import TestApplication
device = Device(device_id="emulator-5554")
test_application = TestApplication.from_apk(apk_path="/some/test.apk", device=device) # installs the given apk
class Listener(TestRunListener):
def test_ended(self, class_name: str, test_name: str, **kwargs) -> None:
print("Test %s passed" % test_name)
def test_failed(self, class_name: str, test_name: str, stack_trace: str) -> None:
print("Test %s failed" % test_name)
def test_ignored(self, class_name: str, test_name: str) -> None:
print("Test %s ignored" % test_name)
def test_assumption_failure(self, class_name: str, test_name: str, stack_trace: str) -> None:
print("Test assumption failed, %s skipped" % test_name)
def test_run_started(self, test_run_name: str, count: int = 0) -> None:
print("Test execution started: " + test_run_name)
def test_run_ended(self, duration: float = -1.0, **kwargs) -> None:
print("Test execution ended")
def test_run_failed(self, error_message: str) -> None:
print("Test execution failed with error message: %s" % error_message)
with AndroidTestOrchestrator(artifact_dir=".") as orchestrator:
test_suite = TestSuite('test_suite1', ["--package", "com.some.test.package"])
test_plan = iter([test_suite])
orchestrator.execute_test_plan(test_application, test_plan, Listener())
# or
orchestrator.execute_test_suite(test_suite, Listener())
A sample expected test result output based on the same Listener above will be
Test execution started: test_suite1
Test testFoo passed
Test testBar failed
Test testBaz skipped
Test execution endded: test_suite1
docs
: contains documentation in .rst formatorchestrator
: Python code to provide an API to orchestrate test executiontestsupportapps
: A sample Android apps with Espresso tests is used solely for testing
Please set ANDROID_SDK_ROOT to point to your Android SDK location
For testing, $ANDROID_SDK_ROOT/tools/emulator -list-avds
should show at least one emulator definition; the first will
be used for testing purposes.
If you do not have an emulator listed, you can do the following to create a simple one:
(1) Issue the following command to install an compatible Android system image with the SDK manager, in this example, Android 28
$ $ANDROID_SDK_ROOT/tools/bin/sdkmanager "system-images;android-28;default;x86_64"
(2) Issue the following command to create a basic emulator with the system image defined in the previous step:
$ $ANDROID_SDK_ROOT/tools/bin/avdmanager create avd -n MTO_emulator -k "system-images;android-28;default;x86_64"
From the orchestrator directory, run:
$ python setup.py install
This will (in addition to normal Python setup.py "stuff"):
#. package it as a resource with the distro
Set up a virtual env and ensure pytest and apk-bitminer are installed.
To run tests, ensure environment as above and in the orchestrator/test directory:
$ pytest -s .
This will build debug versions of the test butler app, and test support apps used during testing.
Test py files directly in the orchestrator/test
are unit-test-like.
Those in orhcestrator/tst/test_system_integration
test a fully integrated system and execution across host,
test butler service on the emulator, and a test app on the device. These are progressively more complex and longer time-running tests and pytest should execute them from faster-running to
the more slower-running integration tests
Recommend setting PYTHONASYNCIODEBUG
to 1
to use asyncio's debug output
Currently, if any breakpoints are set it causes problems in IntelliJ as under the hoods in places asyncio/subprocess uses multiprocessing module and fake KeyboardInterrupts get generate/picked up :-(. pytest staright-up works though. If you turn off all breakpoints, then you can at least get orderly output in PyChram/IntelliJ