Skip to content

How to test an iOS app on a real device without a device farm

Test on the iPhone you already have. Pair it with your Mac. Turn on Developer Mode. Run your XCUITests on it with xcodebuild test -destination 'platform=iOS,name=Test iPhone'. Mobster runs saved checks on the same phone with mobster test --device "Test iPhone". Add --sim to include simulators in the same run and report. Mobster hosts no phones. On a two-step check in a test app on an iPhone 15 Pro with iOS 26.0.1 over USB, the median is 17.7 s for fresh runs and 10.3 s for replay. Replay makes no model call.

Prepare the iPhone

  1. Connect the iPhone to your Mac with a cable. When the phone asks, tap Trust.
  2. Start pairing in Xcode. The Developer Mode switch appears on the phone only after you start pairing, or if the phone was paired to a Mac before.
  3. On the phone, turn on Settings › Privacy & Security › Developer Mode and tap Restart. After the restart, tap Enable and enter your passcode.
  4. Sign in to Xcode with your Apple Account in Xcode’s Settings. A personal Apple Account works.
  5. In your target’s Signing & Capabilities, turn on Automatically manage signing, choose your team and enter a unique bundle ID. Xcode registers the iPhone and creates the development provisioning profile.

Run XCUITest on the phone

List the destinations your scheme can use, then run the tests on the phone by its name:

xcodebuild -showdestinations -scheme YourAppxcodebuild test -scheme YourApp \  -destination 'platform=iOS,name=Test iPhone' \  -resultBundlePath build/phone.xcresult \  -allowProvisioningUpdates
  • -destination takes the phone’s name or its id, never both.
  • -allowProvisioningUpdates lets xcodebuild create and update profiles for automatically signed targets.
  • -resultBundlePath saves the test results. Available attachments depend on your capture settings and what the run records. How to get video and screenshots of an iOS UI test failure exports them.

To install a build without running tests, devicectl takes the phone’s name too:

xcrun devicectl device install app --device "Test iPhone" \  build/Build/Products/Debug-iphoneos/YourApp.app

Run saved checks on the same phone with Mobster

A Mobster check is a YAML file: the app, the steps in plain English, and what must be on screen at the end. Mobster checks the saved assertions.

# .mobster/checks/task-done.yamlversion: 1name: Marking a task done lowers the countapp:  bundle: com.yourname.yourapp.devsteps:  - Tap the first task to mark it done.expect:  - visible: { id: task_1, selected: true }  - value: { id: done_count }    equals: 1  - value: { id: tasks_left }    equals: 2

Mobster for Mac sets the phone up for you. Use Mobster to build, sign and install the helper app that reads the screen (a WebDriverAgent build). Setup from install to a ready helper takes 5 min 26 s on a never-used iPhone 16 with iOS 18.3.1 over USB. It excludes your taps for Trust and Developer Mode.

mobster devices lists each device by name, with its state. Then run the checks on the phone:

mobster test --device "Test iPhone"

Mobster installs the check’s app.path when it is an .ipa or a build for devices. Otherwise it uses the build already on the phone, when devicectl lists it as built by a developer. The exit code is the verdict: 0 passed, 1 failed, 2 needs review, 3 couldn’t run.

A check with steps runs on your Claude or OpenAI API key until it passes once. Then Mobster replays the recorded steps with no model call. For the two-step test-app check on an iPhone 15 Pro with iOS 26.0.1 over USB, model cost is $0 per replay and about $0.017 per fresh run. A launch-only check, with no steps, never calls a model.

To cover more hardware with no farm:

  • mobster test --device all runs on every iPhone that is plugged in, unlocked and set up, and writes one report.
  • --spread with two or more devices runs each check once, on whichever device is free.
  • --sim "iPhone 17 Pro" --sim "iPhone SE (3rd generation)" adds simulators of the sizes and iOS versions you don’t own.

What Mobster does on your phone, and what it leaves alone

  • It drives only your own build. An App Store app is refused: “Mobster tests your own apps on your iPhone. Instagram is from the App Store.”
  • It never clears the app’s data on a phone. A check with reset: data runs with reset: none, and the report says so.
  • Smart steps never send, buy, post or delete on a phone. Mobster refuses those actions.
  • Of the device conditions, it sets only appearance and locale on a phone. You see in the report that Mobster skips the other conditions.
  • It runs one check at a time on each phone. On the command line, you select a phone with --device.
  • It can’t get past Face ID or your passcode. Keep the phone unlocked.

What it costs

Mobster for Mac is free on simulators and iPhones. Mobster hosts no phones, so a farm still fits when you must cover many models you don’t own. To run your checks on every pull request, Run iOS UI checks in CI without a device farm puts your phone on a Mac mini runner.

Questions

  • Do I have to register my iPhone and set up app signing myself?

    No. Apple's docs say to sign in to Xcode with an Apple Developer Program account or a personal Apple Account. With automatic signing, Xcode registers the iPhone and creates the development provisioning profile.

  • Can I test on several iPhones at once without a farm?

    Yes, on the iPhones plugged into your Mac. mobster test --device all runs your checks on every ready iPhone, one check at a time on each, and writes one report.

  • When is a device farm still the better tool?

    When you need many iPhone models and iOS versions that you don't own. Mobster tests the iPhones on your desk and the simulators on your Mac. It hosts no phones.

Sources