In Appium, how can a test drive the emulator or simulator itself rather than the app under test?
answer
- commands aimed at the machine
- an emulator console channel
- Xcode's own simulator tooling
- one execute method, one parameter map
- no physical-device twin
basics
~20 sThrough driver execute methods aimed at the virtual machine, not the UI. The Android drivers expose mobile: execEmuConsoleCommand for a running emulator's console channel; the XCUITest driver exposes mobile: simctl for a booted Apple simulator.
solid answer
~40 sBoth platforms give the session an escape hatch to the virtual device itself, and they are different commands with different reach. On Android the drivers expose **`mobile: execEmuConsoleCommand`**, which sends a command down the running emulator's console channel; the console-backed family (`mobile: gsmCall`, `mobile: sendSms`, `mobile: powerAc`, `mobile: sensorSet`, and the measured emulator-only `mobile: networkSpeed`) rides the same channel. On Apple the XCUITest driver exposes **`mobile: simctl`**, which runs an Xcode simulator-control subcommand against the booted simulator. Both are posted the same way — `POST /session/:sessionId/execute/sync` with a `mobile:` name and one parameter map — and both act on the machine rather than through the accessibility layer, so neither has a physical-device twin.
go deeper
Know that a virtual target can be driven as a machine, not only through the app, and be able to name one such command per platform without mixing the two up.
Explain how they reach the driver — an execute method with a mobile: name and one parameter map — and which driver owns each, since neither name exists on the other platform.
Show that you treat these as precondition-seeding tools with a portability price, and that you check the server's insecure-feature allowances before a suite depends on them.
Argue where the line sits between a case that legitimately requires a virtual target and a suite that has drifted into being unable to run anywhere else.
## Driving the machine, not the app Almost every Appium command is aimed at the app: find an element, tap it, read an attribute. A virtual target adds a second class of command aimed at the **device itself** — the emulator or simulator as a piece of software running on your host. These commands are worth knowing precisely because they exist only on a virtual target, which makes them both powerful and a portability hazard for a hearing-aid fitting suite that must also run on real hardware. The two platforms solve this the same way in shape and completely differently in detail. ## Android: the emulator console A running Android emulator exposes a console channel of its own, and the Android drivers expose **`mobile: execEmuConsoleCommand`** to send a command down it. That single method is the general form. Beside it sits a family of named methods backed by the same channel, each modelling hardware state a virtual device can fake and a real phone cannot be made to produce on demand: - `mobile: gsmCall`, `mobile: gsmSignal`, `mobile: gsmVoice` — telephony state. - `mobile: sendSms` — deliver a message to the device. - `mobile: powerAc`, `mobile: powerCapacity` — charging and battery state. - `mobile: sensorSet` — sensor values. - `mobile: networkSpeed` — measured **emulator-only**, simulating a link speed. Note that these belong to *the Android drivers*, not to the UiAutomator2 repository specifically: the Android base driver carries the large device-facing surface and whichever driver you name in `appium:automationName` inherits it. ## Apple: simctl from inside the session The XCUITest driver's counterpart is **`mobile: simctl`**, which runs an Xcode simulator-control subcommand against the booted simulator. `simctl` is the same tool the driver used to boot the target in the first place, so this is genuinely an escape hatch to host tooling rather than a device API. There is no equivalence to draw between the two commands beyond that shape. `mobile: execEmuConsoleCommand` speaks to a running emulator's console; `mobile: simctl` invokes Xcode tooling that manages simulators. Their vocabularies, argument shapes and failure modes have nothing in common, and a suite that pretends otherwise is hiding the divergence rather than handling it. ## How both arrive at the driver Both are **execute methods**, not endpoints of their own. A client sends them to `POST /session/:sessionId/execute/sync` with the `mobile:` name and a single parameter map, which is why a language client such as java-client or the Python client needs no dedicated helper for either. In practice that means: 1. The method name identifies the driver that owns it — say the platform whenever you write one down. 2. Adding a new one to a suite is a data change, not a client upgrade. 3. An unknown `mobile:` name fails at the driver, mid-run, rather than at session start. ## The two costs The first cost is **portability**. Every one of these calls is a step your suite can take on a virtual target and cannot take on a physical one. A fitting flow that seeds a low-battery state through the emulator console has quietly become an emulator-only case. That is a legitimate choice; it is not a legitimate accident. The second cost is **trust in the host**. These methods reach outside the app and outside the device's own automation surface, and Appium keeps host-reaching features behind insecure-feature gating — the same mechanism that guards the Android drivers' shell access with `--allow-insecure=uiautomator2:adb_shell`. Before a suite leans on either method, confirm what the server it will run against actually allows. ## When it is the right tool - When the state you need is a property of the machine — battery, telephony, sensors — and no in-app path can produce it. - When you are seeding a precondition rather than asserting on one, so the virtual-only path never becomes the thing under test. - When the alternative is a manual step that would keep the case out of the suite entirely. And when not to: if the same precondition can be set through an ordinary driver command that works on every target, prefer that command. The escape hatch should be the smallest possible part of a suite's surface, because every use of it narrows where the suite can run.
- How does a client send either of these commands to the server?As an execute method: `POST /session/:sessionId/execute/sync` carrying the `mobile:` name and one parameter map. There is no dedicated endpoint and no client helper to wait for, which is why adding one to a suite is a data change rather than a client upgrade. The name itself identifies the owning driver.
- What does using these commands cost a suite that also runs on real devices?Portability. Anything reached through the emulator console or through `mobile: simctl` is a step only a virtual target can perform, so the case silently becomes virtual-only. Use them to seed preconditions rather than to assert behaviour, and mark the cases that depend on them so a hardware lane can skip them deliberately.
saying these in an interview costs you the question
- Calls mobile: simctl an Android command
- Thinks the emulator console works on a physical phone
- Expects a shared command name across both platforms
- Assumes these are REST endpoints rather than execute methods
- Ignores that host-reaching features may be gated by the server