Pytest plugin for Appium device scheduling and driver lifecycle management.
Project description
pytest-appium-scheduler
pytest-appium-scheduler is a pytest plugin for Appium test execution with:
- device-aware scheduling
pytest-xdistparallel executionfunctionandsessiondriver lifecycle control- per-test device targeting via markers
- debug and trace logs for worker/device visibility
The package is published as pytest-appium-scheduler. After publishing, both of these forms work with pip:
pip install pytest-appium-scheduler
Features
distributedmode: spread Appium tests across available devicesallmode: run each Appium test on every matching device@pytest.mark.device(...)and@pytest.mark.devices(...)- shared device pool with worker-safe leasing
driveranddevicefixtures- extensible hooks:
pytest_appium_create_driverpytest_appium_modify_caps
- compact debug output via
--appium-debug - verbose lifecycle tracing via
--appium-trace
Installation
pip install pytest_appium_scheduler
This installs:
pytestpytest-xdistPyYAMLappium-python-client
Quick Start
Create a device config, for example from device.example.yaml:
devices:
- name: emulator-5554
url: http://127.0.0.1:4723
caps:
platformName: Android
automationName: UiAutomator2
udid: emulator-5554
systemPort: 8201
appPackage: com.android.settings
appActivity: .Settings
- name: emulator-5556
url: http://127.0.0.1:4723
caps:
platformName: Android
automationName: UiAutomator2
udid: emulator-5556
systemPort: 8202
appPackage: com.android.settings
appActivity: .Settings
Write tests:
import pytest
def test_open_app(driver):
assert driver.session_id
def test_device_fixture(device):
assert device.name
@pytest.mark.device("emulator-5556")
def test_only_on_specific_device(driver):
assert driver.session_id
@pytest.mark.device(platform="Android")
def test_only_android(driver):
assert driver.session_id
class TestNoDevice:
def test_plain_pytest_case(self):
assert True
Run in distributed mode:
pytest tests \
--appium-config=device.yaml \
--appium-mode=distributed \
-n 2
Run in all mode:
pytest tests \
--appium-config=device.yaml \
--appium-mode=all \
-n 2
Scheduling Modes
distributed
Use devices as a shared execution pool.
- Appium tests are scheduled onto matching devices
- when workers are more than devices, extra workers can stay idle
- non-Appium tests can still run on idle workers
- when workers are fewer than devices, workers will rotate across devices instead of permanently starving one
all
Run every matching Appium test on every matching device.
- each device gets its own execution stream
- workers do not compete for the same device at the same time
- non-Appium tests can still run on idle workers
Fixtures
driver
Provides an Appium driver.
device
Provides the selected device model:
def test_device(device):
assert device.name
assert device.url
assert device.caps
Markers
Limit a test to one or more devices:
@pytest.mark.device("pixel_7")
def test_only_pixel(driver):
...
@pytest.mark.devices(["pixel_7", "iphone_14"])
def test_specific_devices(driver):
...
@pytest.mark.device(platform="iOS")
def test_only_ios(driver):
...
Behavior:
- unmarked tests: all configured devices are eligible
- unknown device marker: skipped with warning
- unmatched filter: skipped with warning
CLI Options
--appium-mode=distributed|all
--appium-config=PATH
--appium-device=NAME
--appium-driver-scope=function|session
--appium-retry-session=1
--appium-debug
--appium-trace
Useful examples
Select one device only:
pytest tests \
--appium-config=device.yaml \
--appium-device=huawei_p60
Reuse one driver per device session:
pytest tests \
--appium-config=device.yaml \
--appium-driver-scope=session
Show compact scheduling logs:
pytest tests \
--appium-config=device.yaml \
--appium-mode=distributed \
--appium-debug \
-n 2 -q -s
Show verbose lifecycle trace:
pytest tests \
--appium-config=device.yaml \
--appium-mode=distributed \
--appium-trace \
-n 2 -q -s
Custom Hooks
Modify capabilities
def pytest_appium_modify_caps(caps):
updated = dict(caps)
updated["newCommandTimeout"] = 120
return updated
Create your own driver
pytest_appium_modify_caps is applied before pytest_appium_create_driver, so your custom driver hook receives the updated capabilities.
def pytest_appium_create_driver(device):
from appium import webdriver
from appium.options.common.base import AppiumOptions
options = AppiumOptions()
options.load_capabilities(device.caps)
return webdriver.Remote(device.normalized_url(), options=options)
Debug Output
With --appium-debug:
[appium] gw0 target=huawei_p60 device=huawei_p60 PASSED tests/test_real_device.py::test_open_app session-123
With --appium-trace:
[pytest-appium-scheduler] action=device-acquire worker=gw0 target=huawei_p60 device=huawei_p60 details=nodeid=...
Development
Create a local environment:
python3 -m venv .venv
source .venv/bin/activate
pip install -e .
Run tests:
.venv/bin/python -m pytest tests/test_plugin.py -q
Build distributions:
.venv/bin/python -m pip install build
.venv/bin/python -m build
License
MIT. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pytest_appium_scheduler-0.1.1.tar.gz.
File metadata
- Download URL: pytest_appium_scheduler-0.1.1.tar.gz
- Upload date:
- Size: 22.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9270c32a75be3516fb6d64b2d6e2e44f8bcc67b49200cff130b90d34b9ec01de
|
|
| MD5 |
b683a102aceb74b324a565b676118300
|
|
| BLAKE2b-256 |
de5d3ec782ca31f4b32cdf87db8748de0b43c0cf9dd344cd8bc61bfee1c2886b
|
File details
Details for the file pytest_appium_scheduler-0.1.1-py3-none-any.whl.
File metadata
- Download URL: pytest_appium_scheduler-0.1.1-py3-none-any.whl
- Upload date:
- Size: 21.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
300b1f9d7d8a7c285eda45fcd4c7e115cc8238c2313ba4e78a153988e8c9a718
|
|
| MD5 |
dd70ea627028b9f076e3de99a3d6e129
|
|
| BLAKE2b-256 |
1e8025ec626ba1d0536be5e49bbe3a304719691ca87f062e53db7e8d64413c6e
|