AWS Device Farm: Complete Guide to Mobile App Testing
AWS Device Farm lets you run tests on real Android and iOS devices hosted in AWS data centers. Instead of managing a physical device lab, you upload your app and test scripts, pick devices, and run tests in parallel.
This guide covers how Device Farm works, how to set it up, and how to integrate it into your CI/CD pipeline.
What AWS Device Farm Offers
Real device testing: Tests run on physical hardware — not simulators. This matters for GPS, Bluetooth, camera, biometrics, and real-world performance.
Device selection: 200+ device configurations covering Android phones and tablets, iPhones, and iPads across multiple OS versions and manufacturers.
Two test modes:
- Automated testing — run your test framework scripts (Appium, XCTest, Espresso, Calabash, built-in fuzz)
- Remote access — interact with a real device via browser in real time for manual testing and debugging
Parallel execution: Run the same test suite on 10+ devices simultaneously. A suite that would take 4 hours on one device completes in 20 minutes.
Supported Test Frameworks
| Framework | Platform |
|---|---|
| Appium (Java, Python, Node, Ruby) | Android + iOS |
| XCTest / XCUITest | iOS |
| Espresso | Android |
| Calabash | Android + iOS |
| Built-in (fuzz) | Android + iOS |
| Custom (any framework via custom test environment) | Android + iOS |
If you're starting fresh, Appium is the most portable choice — same test code runs on Android and iOS.
Setting Up Your First Test Run
Prerequisites
- AWS account with Device Farm enabled (available in us-west-2 region)
- Android APK or iOS IPA file
- Test package (test code + dependencies bundled as ZIP)
Using the AWS Console
- Go to AWS Device Farm > Mobile Testing
- Create a project
- Click Create a new run
- Upload your app (APK/IPA)
- Select test framework and upload test package
- Choose devices from the device pool
- Configure execution settings (test timeout, device state)
- Run
Packaging Appium Tests
Device Farm requires tests packaged in a specific ZIP structure:
For Appium + Python:
# Install dependencies locally
pip install appium-python-client pytest -t ./vendor
# Create requirements file
pip freeze > requirements.txt
# Package
zip -r test-package.zip tests/ vendor/ requirements.txtFor Appium + Java (Maven):
mvn clean package -DskipTests
# Upload target/zip-with-dependencies.zipDevice Farm requires the Maven dependency ZIP plugin:
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals><goal>copy-dependencies</goal></goals>
</execution>
</executions>
</plugin>Test File Structure (Appium Python)
# tests/test_login.py
import pytest
from appium import webdriver
from appium.options import AppiumOptions
@pytest.fixture(scope="function")
def driver():
options = AppiumOptions()
# Device Farm injects capabilities automatically
# Just specify your app-specific caps
options.set_capability("appActivity", "com.yourapp.MainActivity")
options.set_capability("appPackage", "com.yourapp")
driver = webdriver.Remote(
command_executor="http://localhost:4723/wd/hub",
options=options
)
yield driver
driver.quit()
def test_login_success(driver):
username = driver.find_element("id", "com.yourapp:id/username")
username.send_keys("testuser@example.com")
password = driver.find_element("id", "com.yourapp:id/password")
password.send_keys("TestPassword123")
driver.find_element("id", "com.yourapp:id/login_button").click()
assert driver.find_element("id", "com.yourapp:id/dashboard_title").is_displayed()CI/CD Integration
Using AWS CLI
# Create a run
aws devicefarm create-upload \
--project-arn "arn:aws:devicefarm:us-west-2:123456789:project:abc123" \
--name "my-app.apk" \
--type ANDROID_APP \
--region us-west-2
# Upload the file (use the presigned URL from the response)
curl -T my-app.apk "https://presigned-upload-url..."
# Create test package upload
aws devicefarm create-upload \
--project-arn "arn:aws:devicefarm:us-west-2:123456789:project:abc123" \
--name "test-package.zip" \
--type APPIUM_PYTHON_TEST_PACKAGE \
--region us-west-2
# Schedule a run
aws devicefarm schedule-run \
--project-arn "arn:..." \
--app-arn "arn:..." \
--device-pool-arn "arn:..." \
--test "type=APPIUM_PYTHON,testPackageArn=arn:..." \
--region us-west-2GitHub Actions
name: Mobile Testing - AWS Device Farm
on:
push:
branches: [main]
jobs:
device-farm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2
- name: Build APK
run: ./gradlew assembleDebug
- name: Package Tests
run: |
pip install appium-python-client pytest -t vendor/
zip -r test-package.zip tests/ vendor/ requirements.txt
- name: Run Device Farm Tests
uses: aws-actions/aws-devicefarm-mobile-testing@v1
with:
project-arn: ${{ secrets.DEVICE_FARM_PROJECT_ARN }}
app-file: app/build/outputs/apk/debug/app-debug.apk
app-type: ANDROID_APP
test-type: APPIUM_PYTHON
test-package-file: test-package.zip
device-pool-arn: ${{ secrets.DEVICE_FARM_DEVICE_POOL_ARN }}
timeout: 1800Device Pools
Device pools determine which devices your tests run on. Device Farm has built-in pools:
- Top Devices — most popular Android and iOS devices
- All Devices — every available device
For most teams, custom pools are better:
# Create a custom pool via AWS CLI
aws devicefarm create-device-pool \
--project-arn "arn:..." \
--name "Critical Devices" \
--rules '[
{"attribute": "PLATFORM", "operator": "EQUALS", "value": "ANDROID"},
{"attribute": "OS_VERSION", "operator": "GREATER_THAN_OR_EQUALS", "value": "11"},
{"attribute": "MANUFACTURER", "operator": "IN", "value": "[\"Samsung\", \"Google\"]"}
]' \
--region us-west-2Recommended device selection strategy:
- Latest 2 Android OS versions × top 3 manufacturers (Samsung, Google Pixel, OnePlus)
- Latest 2 iOS versions × iPhone 13/14/15
- One older mid-range Android (to catch performance issues)
Reading Test Results
After a run completes, Device Farm provides:
Artifacts for each device:
- Screenshots at each test step
- Video recording of the full test run
- Device logs (logcat for Android, device console for iOS)
- Test framework logs
- Performance data (CPU, memory, network, FPS)
Common failure patterns:
NoSuchElementException— element locators are wrong or timing issue (add explicit waits)SessionNotCreatedException— app failed to install (check APK target API level vs. device OS)- Timeout failures — tests taking too long (reduce scope or increase timeout)
Remote Access for Debugging
When automated tests fail, use Remote Access to debug:
- In Device Farm console: Remote Access > Create Session
- Select a specific device
- Access via browser — real-time screen, touch input, keyboard
- Install your APK directly, run through the failure manually
- Access device logs in real time
Remote access sessions are billed per minute (typically $0.17/minute).
Cost Optimization
Device Farm pricing:
- Metered: ~$0.17/device-minute
- Unmetered plans: flat monthly fee for unlimited minutes on a fixed device pool
Cost reduction tactics:
- Run full device matrix weekly; run critical device subset on every PR
- Use device slots (reserved capacity) if you run tests multiple times daily
- Set aggressive test timeouts to avoid paying for hung tests
- Use simulators (free in Device Farm) for smoke tests; real devices for release candidates
AWS Device Farm vs. Local Simulators
| Factor | AWS Device Farm | Local Simulator |
|---|---|---|
| Hardware accuracy | Real device | Simulated |
| Setup cost | None | Developer time |
| Per-run cost | $0.17/min | None (after setup) |
| Device variety | 200+ devices | Limited to installed SDKs |
| Parallel execution | Yes | Limited |
| CI/CD integration | Native | Manual setup |
For most teams: simulators for fast feedback during development, Device Farm for pre-release validation on real hardware.
Summary
AWS Device Farm removes the need to manage a physical device lab. The trade-off is per-minute cost, but for teams that run tests a few times per week rather than continuously, it's usually cheaper and simpler than maintaining hardware.
Start with a small device pool (5–8 devices), integrate with your CI/CD pipeline, and expand coverage as your test suite matures.