本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 Appium 与设备进行交互
创建远程访问会话后,该设备将可用于 Appium 测试。在远程访问会话期间,您可以在设备上运行任意数量的 Appium 会话,对使用的客户端没有限制。例如,您可以先使用 IDE 中的本地 Appium 代码运行测试,然后切换到使用 Appium Inspector 来解决遇到的任何问题。会话最多可持续 150 分钟。但是,如果超过 5 分钟(通过交互式控制台或 Appium 端点)没有任何活动,则会话超时。
在 Appium 会话中使用应用程序进行测试
有几种方法可以提供应用程序以供您的 Appium 会话使用:
-
将应用程序上传到设备农场并将其安装在会话中。
-
指定 HTTPS 网址或亚马逊简单存储服务 (Amazon S3) URI 作为appium:app功能。
-
按软件包名称引用已安装的应用程序(appium:appPackage在 Android 或 iOS appium:bundleId 上使用)。
-
通过指定browserName功能来测试 Web 应用程序(Chrome在 Android 上、Safari在 iOS 上)。
标准应用程序大小限制 (4 GB) 适用于所有应用程序源。
设备群不支持在远程访问会话appium:app期间传入本地文件系统路径。
上传、安装和使用应用程序
要在 Appium 会话中使用上传的应用程序,请按照以下步骤操作:
-
上传并安装您的应用程序
有两种方法可以将应用程序上传并安装到被测设备上:
-
使用已安装的应用程序
安装后,该应用程序将自动作为任何后续Appium会话的默认appium:app功能注入。如果您包含辅助应用程序,则将它们设置为appium:otherApps功能。
例如,如果您使用com.aws.dev.rproxy.goskope.comicefarm.sample作为应用程序和com.aws.dev.rproxy.goskope.comicefarm.other.sample辅助应用程序之一来创建远程访问会话,则当您创建 Appium 会话时,它将具有与以下类似的功能:
{
"value":
{
"sessionId": "abcdef123456-1234-5678-abcd-abcdef123456",
"capabilities":
{
"app": "/tmp/com.aws.dev.rproxy.goskope.comicefarm.sample.apk",
"otherApps": "[\"/tmp/com.aws.dev.rproxy.goskope.comicefarm.other.sample.apk\"]",
...
}
}
}
如果您在会话期间安装新应用程序,它将取代当前appium:app功能。如果先前安装的应用程序具有不同的软件包名称,则它会保留在设备上并移至该appium:otherApps功能。
例如,如果您最初在创建远程访问会话com.aws.dev.rproxy.goskope.comicefarm.sample时使用,但随后在会话com.aws.dev.rproxy.goskope.comicefarm.other.sample期间安装,则您的 Appium 会话将具有与以下类似的功能:
{
"value":
{
"sessionId": "abcdef123456-1234-5678-abcd-abcdef123456",
"capabilities":
{
"app": "/tmp/com.aws.dev.rproxy.goskope.comicefarm.other.sample.apk",
"otherApps": "[\"/tmp/com.aws.dev.rproxy.goskope.comicefarm.sample.apk\"]",
...
}
}
}
使用 HTTPS 网址
在创建 Appium 会话时,您可以将可公开访问的 HTTPS 网址指定为appium:app所需的功能。该 URL 必须直接指向可下载的应用程序文件(例如,.apk或.ipa文件)。Device Farm 从指定的 URL 下载应用程序并将其安装到被测设备上。
仅支持 HTTPS 网址。纯 HTTP 网址被拒绝。
例如,以下 Appium 会话创建请求从 HTTPS 网址下载应用程序:
{
"capabilities":
{
"alwaysMatch": {},
"firstMatch":
[
{
"appium:app": "https://example.com/path/to/MyApp.apk"
}
]
}
}
使用亚马逊 S3 URI
在创建 Appium 会话时,您可以将 Amazon S3 URI(例如s3://amzn-s3-demo-bucket/path/to/MyApp.ipa)指定为appium:app所需的功能。设备农场从指定的 Amazon S3 位置下载应用程序并将其安装到被测设备上。
要使用 Amazon S3 URI,必须满足以下要求:
-
远程访问会话必须从配置了 IAM 执行角色的项目启动。
-
IAM 执行角色的最大会话持续时间必须至少为 150 分钟。之所以如此,是因为该角色是在远程访问会话期间代入的。
-
IAM 执行角色必须有权调用 s3:GetObject URI 中指定的 S3 对象。此权限还授权对同一对象HeadObject进行 API 调用,这允许 Device Farm 在尝试下载之前验证该对象的存在。
例如,以下 Appium 会话创建请求从 Amazon S3 URI 下载应用程序:
{
"capabilities":
{
"alwaysMatch": {},
"firstMatch":
[
{
"appium:app": "s3://amzn-s3-demo-bucket/apps/MyApp.ipa"
}
]
}
}
以下是 IAM 权限策略示例,该策略授予从 Amazon S3 下载应用程序的推荐访问权限。该s3:GetObject权限还授权 HeadObject API 调用,该调用用于验证对象的存在。有关配置 IAM 执行角色的更多信息,请参阅使用 IAM 执行角色访问 AWS 资源。
例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/apps/*"
}
]
}
使用已安装的应用程序
如果您要测试的应用程序已安装在设备上,则可以直接通过其包名称引用它,而不必上传。在安卓系统上使用appium:appPackage和appium:appActivity功能,或在 iOS 上使用该appium:bundleId功能。
例如,以下 Appium 会话创建请求会启动已安装的 Android 应用程序:
{
"capabilities":
{
"alwaysMatch": {},
"firstMatch":
[
{
"appium:appPackage": "com.example.myapp",
"appium:appActivity": "com.example.myapp.MainActivity"
}
]
}
}
在 iOS 上,appium:bundleId改用:
{
"capabilities":
{
"alwaysMatch": {},
"firstMatch":
[
{
"appium:bundleId": "com.example.myapp"
}
]
}
}
测试 Web 应用程序
要测试 Web 应用程序,请在 Appium 会话创建请求中指定该browserName功能。Chrome在安卓设备或 iOS 设备Safari上使用。
例如,以下请求在安卓设备上打开 Chrome:
{
"capabilities":
{
"alwaysMatch": {},
"firstMatch":
[
{
"browserName": "Chrome"
}
]
}
}
如何使用 Appium 端点
以下是从控制台、和软件开发工具包访问会话的 Appium 端点的 AWS CLI步骤。 AWS
这些步骤包括如何使用各种 Appium 客户端测试框架开始运行测试:
- Console
-
-
在 Web 浏览器中打开远程访问会话页面:
-
要使用 Appium 检查器运行会话,请执行以下操作:
-
选择设置 Appium 会话。
-
按照页面上的说明使用 Appium 检查器启动会话。
-
要从本地 IDE 运行 Appium 测试,请执行以下操作:
-
选择 Appium 端点 URL 旁边的复制图标。
-
将复制的 URL 粘贴到您当前指定远程地址或命令执行器的本地 Appium 代码中。有关特定语言的示例,请参阅本节中的其他选项卡。
- AWS CLI
-
首先,通过下载和安装最新 AWS CLI 版本来验证您的版本是否为最新版本。
Appium 终端节点字段在较早版本的中不可用。 AWS CLI
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
$ aws devicefarm get-remote-access-session \
--arn "arn:aws:devicefarm:us-west-2:123456789876:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"
这将显示如下输出:
{
"remoteAccessSession": {
"arn": "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000",
"name": "Google Pixel 8",
"status": "RUNNING",
"endpoints": {
"remoteDriverEndpoint": "https://devicefarm-interactive-global.us-west-2.api.aws/remote-endpoint/ABCD1234...",
...
}
无论您当前在何处指定远程地址或命令执行器,都可以在本地 Appium 代码中使用此 URL。有关特定语言的示例,请单击此示例窗口中您选择的语言的选项卡之一。
有关如何直接从命令行与端点交互的示例,您可以使用命令行工具 curl 直接调用 WebDriver端点:
$ curl "https://devicefarm-interactive-global.us-west-2.api.aws/remote-endpoint/ABCD1234.../status"
这将显示如下输出:
{
"value":
{
"ready": true,
"message": "The server is ready to accept new connections",
"build":
{
"version": "2.5.1"
}
}
}
- Python
-
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
# To get the URL
import sys
import boto3
from botocore.exceptions import ClientError
def get_appium_endpoint() -> str:
session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"
device_farm_client = boto3.client("devicefarm", region_name="us-west-2")
try:
resp = device_farm_client.get_remote_access_session(arn=session_arn)
except ClientError as exc:
sys.exit(f"Failed to call Device Farm: {exc}")
remote_access_session = resp.get("remoteAccessSession", {})
endpoints = remote_access_session.get("endpoints", {})
endpoint = endpoints.get("remoteDriverEndpoint")
if not endpoint:
sys.exit("Device Farm response did not include endpoints.remoteDriverEndpoint")
return endpoint
# To use the URL
from appium import webdriver
from appium.options.android import UiAutomator2Options
opts = UiAutomator2Options()
driver = webdriver.Remote(get_appium_endpoint(), options=opts)
# ...
driver.quit()
- Java
-
注意:此示例使用 AWS 适用于 Java v2 的软件开发工具包,并且与 JDK 版本 11 及更高版本兼容。
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
// To get the URL
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.devicefarm.DeviceFarmClient;
import software.amazon.awssdk.services.devicefarm.model.GetRemoteAccessSessionRequest;
import software.amazon.awssdk.services.devicefarm.model.GetRemoteAccessSessionResponse;
public class AppiumEndpointBuilder {
public static String getAppiumEndpoint() throws Exception {
String session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";
try (DeviceFarmClient client = DeviceFarmClient.builder()
.region(Region.US_WEST_2)
.credentialsProvider(DefaultCredentialsProvider.create())
.build()) {
GetRemoteAccessSessionResponse resp = client.getRemoteAccessSession(
GetRemoteAccessSessionRequest.builder().arn(session_arn).build()
);
String endpoint = resp.remoteAccessSession().endpoints().remoteDriverEndpoint();
if (endpoint == null || endpoint.isEmpty()) {
throw new IllegalStateException("remoteDriverEndpoint missing from response");
}
return endpoint;
}
}
}
// To use the URL
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.options.UiAutomator2Options;
import java.net.URL;
public class ExampleTest {
public static void main(String[] args) throws Exception {
String endpoint = AppiumEndpointBuilder.getAppiumEndpoint();
UiAutomator2Options options = new UiAutomator2Options();
AndroidDriver driver = new AndroidDriver(new URL(endpoint), options);
try {
// ... your test ...
} finally {
driver.quit();
}
}
}
- JavaScript
-
注意:此示例使用 AWS 适用于 v JavaScript 3 的 SDK 和使用节点 18+ 的 WebDriverIO v8+。
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
// To get the URL
import { DeviceFarmClient, GetRemoteAccessSessionCommand } from "@aws-sdk/client-device-farm";
export async function getAppiumEndpoint() {
const sessionArn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";
const client = new DeviceFarmClient({ region: "us-west-2" });
const resp = await client.send(new GetRemoteAccessSessionCommand({ arn: sessionArn }));
const endpoint = resp?.remoteAccessSession?.endpoints?.remoteDriverEndpoint;
if (!endpoint) throw new Error("remoteDriverEndpoint missing from response");
return endpoint;
}
// To use the URL with WebdriverIO
import { remote } from "webdriverio";
(async () => {
const endpoint = await getAppiumEndpoint();
const u = new URL(endpoint);
const driver = await remote({
protocol: u.protocol.replace(":", ""),
hostname: u.hostname,
port: u.port ? Number(u.port) : (u.protocol === "https:" ? 443 : 80),
path: u.pathname + u.search,
capabilities: {
platformName: "Android",
"appium:automationName": "UiAutomator2",
// ...other caps...
},
});
try {
// ... your test ...
} finally {
await driver.deleteSession();
}
})();
- C#
-
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
// To get the URL
using System;
using System.Threading.Tasks;
using Amazon;
using Amazon.DeviceFarm;
using Amazon.DeviceFarm.Model;
public static class AppiumEndpointBuilder
{
public static async Task<string> GetAppiumEndpointAsync()
{
var sessionArn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000";
var config = new AmazonDeviceFarmConfig
{
RegionEndpoint = RegionEndpoint.USWest2
};
using var client = new AmazonDeviceFarmClient(config);
var resp = await client.GetRemoteAccessSessionAsync(new GetRemoteAccessSessionRequest { Arn = sessionArn });
var endpoint = resp?.RemoteAccessSession?.Endpoints?.RemoteDriverEndpoint;
if (string.IsNullOrWhiteSpace(endpoint))
throw new InvalidOperationException("RemoteDriverEndpoint missing from response");
return endpoint;
}
}
// To use the URL
using OpenQA.Selenium.Appium;
using OpenQA.Selenium.Appium.Android;
class Example
{
static async Task Main()
{
var endpoint = await AppiumEndpointBuilder.GetAppiumEndpointAsync();
var options = new AppiumOptions();
options.PlatformName = "Android";
options.AutomationName = "UiAutomator2";
using var driver = new AndroidDriver(new Uri(endpoint), options);
try
{
// ... your test ...
}
finally
{
driver.Quit();
}
}
}
- Ruby
-
会话启动并运行后,Appium 终端节点 URL 将通过 API 调用的响应remoteDriverEndpoint中命名的字段提供:GetRemoteAccessSession
# To get the URL
require 'aws-sdk-devicefarm'
def get_appium_endpoint
session_arn = "arn:aws:devicefarm:us-west-2:111122223333:session:abcdef123456-1234-5678-abcd-abcdef123456/abcdef123456-1234-5678-abcd-abcdef123456/00000"
client = Aws::DeviceFarm::Client.new(region: 'us-west-2')
resp = client.get_remote_access_session(arn: session_arn)
endpoint = resp.remote_access_session.endpoints.remote_driver_endpoint
raise "remote_driver_endpoint missing from response" if endpoint.nil? || endpoint.empty?
endpoint
end
# To use the URL
require 'appium_lib_core'
endpoint = get_appium_endpoint
opts = {
server_url: endpoint,
capabilities: {
'platformName' => 'Android',
'appium:automationName' => 'UiAutomator2'
}
}
driver = Appium::Core.for(opts).start_driver
begin
# ... your test ...
ensure
driver.quit
end