8个版本
0.2.2 | 2024年1月5日 |
---|---|
0.2.1 | 2024年1月5日 |
0.2.0 | 2023年9月12日 |
0.1.4 | 2023年8月25日 |
0.1.2 | 2023年2月8日 |
#107 in 测试
每月465次下载
165KB
2.5K SLoC
appium-client
Rust编写的Appium服务器客户端,用于自动化移动应用测试。它基于fantoccini。
Appium是一个用于自动化原生应用测试的工具。换句话说,它用于模拟应用中的用户活动。你告诉Appium在屏幕上寻找什么,点击什么,Appium会为你完成。
Appium由以下组成
- 一个Appium服务器,通过REST服务Appium API并将命令委派给驱动程序,
- Appium API,它是发送命令的统一方式,
- Appium驱动程序,它是一个库,知道如何与您要控制的设备进行通信。
这个库是一个Appium客户端。这意味着它向Appium服务器发送命令。您需要设置Appium才能使用此库。
文档主要关注整个工具的客户端方面。因此,如果您需要有关Appium服务器、驱动程序或设备设置的更多信息,请参阅Appium文档。
还可以查看示例。
功能
- 预定义的iOS和Android能力(至少其中一些)。
- 锁定和解锁屏幕。
- 获取设备/模拟器的当前时间。
- 获取设备的旋转和方向。
- 屏幕录制支持。
- 电池状态支持。
- Android网络状态。
- 更改设备设置。
- 推送和拉取文件。
- 获取应用程序字符串。
- 访问设备剪贴板。
- 模拟Touch ID和指纹认证。
- 键盘模拟。
- 使用未实现的功能和驱动程序的能力。
指南、教程和文档
快速指南
本快速指南假设您了解Appium的工作原理。它重点介绍了该库的关键功能。如果您需要更基础的指南,请参阅设置和编写第一个自动化脚本。
如何使用?
首先需要启动一个Appium服务器。您还需要将设备(或仿真器)连接到运行Appium服务器的机器。
如果您已正确设置Appium,则可以使用此库连接到服务器并控制设备。
要连接到Appium服务器,您需要创建一个Client
的实例。要做到这一点,创建适当的能力(例如,AndroidCapabilities::new_uiautomator()
),然后将它们提供给ClientBuilder
。
您需要一个Tokio异步运行时才能正常工作。
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut capabilities = AndroidCapabilities::new_uiautomator();
capabilities.app("https://github.com/appium/android-apidemos/releases/download/v3.1.0/ApiDemos-debug.apk");
let client = ClientBuilder::native(capabilities)
.connect("https://127.0.0.1:4723/")
.await?;
// now you can start testing
Ok(())
}
Appium使用DOM(文档对象模型)解释设备的屏幕。屏幕上的元素被转换成一种符合W3C Selenium标准的XML。
Appium是对此的某种扩展,具有允许控制移动设备、仿真器或桌面操作系统的驱动程序。
要查看Appium如何解释设备屏幕(并使用Appium与设备交互),您可以使用一个名为Appium Inspector的工具。这是一个非常有用的GUI工具,可以在自动化开发期间提供帮助。
如果这个库缺少某些功能怎么办?
您可以通过创建PR来添加缺少的功能。
如果您没有时间做这件事,您也可以直接发出命令,而不依赖于此库的特性。
例如,假设Appium添加了一个名为“在设备上模拟桶滚”的新功能。Appium服务器为此提供了一个新的API - POST /session/:sessionId/appium/device/barrel_roll
。我们可以在请求中指定设备将进行多少次桶滚 - {"times": number}
。
您不必等到我将其添加到库中。您可以发出自定义命令
client.issue_cmd(AppiumCommand::Custom(
Method::POST,
"appium/device/barrel_roll".to_string(),
Some(json!({
"times": 2
}))
)).await?;
如您所见,我没有添加原始端点的/session/:sessionId
。没有必要这样做 - Appium客户端会自动添加。
示例用法
创建客户端
创建将用于发出命令和定位元素的Appium客户端。
客户端是一个对象,用于管理到Appium服务器的连接并向其发出命令。因此,我们需要描述自动化环境和服务器URL的能力来创建客户端。
您可以在Appium文档中了解更多关于能力的信息。
use appium_client::ClientBuilder;
use appium_client::capabilities::*;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut capabilities = AndroidCapabilities::new_uiautomator();
capabilities.app("https://github.com/appium/android-apidemos/releases/download/v3.1.0/ApiDemos-debug.apk");
let client = ClientBuilder::native(capabilities)
.connect("https://127.0.0.1:4723/")
.await?;
Ok(())
}
在屏幕上定位元素
使用您喜欢的定位策略定位元素(例如,通过UiAutomator 2)。
还支持其他策略,如名称、XPath、iOS Class Chain等。
// you need this to use Appium locators with fantoccini's Client
use appium_client::find::{AppiumFind, By};
let element = client
.find_by(By::accessibility_id("Click this"))
.await?;
element.click().await?;
等待元素出现
如果元素没有立即出现在屏幕上,您可以等待元素。
默认情况下,等待时间为30秒。在等待期间,客户端会每250毫秒进行一次搜索,直到元素最终出现,或达到超时。
// you need these to use Appium-enhanced wait with fantoccini's Client
use appium_client::find::{AppiumFind, By};
use appium_client::wait::AppiumWait;
let element = client
.appium_wait()
.for_element(By::uiautomator("new UiSelector().className(\"android.widget.ImageView\");"))
.await?;
element.click().await?;
限制等待时间
您可以定义等待元素出现的时间长度以及检查频率。
这在您知道某物应该很快出现的情况下很有用。如果它没有出现,那么可能发生了其他事情,您不想等待完整的30秒超时。
搜索间隔也可以相应调整,以便Appium服务器有更多时间“呼吸”。
// you need these to use Appium-enhanced wait with fantoccini's Client
use appium_client::find::{AppiumFind, By};
use appium_client::wait::AppiumWait;
let element = client
.appium_wait()
.at_most(Duration::from_secs(20))
.check_every(Duration::from_millis(500))
.for_element(By::uiautomator("new UiSelector().className(\"android.widget.ImageView\");"))
.await?;
element.click().await?;
定位多个元素
要定位多个元素,请使用find_all_by
或.appium_wait().for_elements(..)
。
第一种方法的工作方式与find_by
相同 - 立即返回结果。第二种方法等待给定时间,直到至少出现一个元素。它的工作方式与上面的例子相同。
// you need these to use Appium-enhanced wait with fantoccini's Client
use appium_client::find::{AppiumFind, By};
use appium_client::wait::AppiumWait;
let result = client
.appium_wait()
.for_elements(By::class_name("android.widget.LinearLayout"))
.await?;
result.first().unwrap().click().await?;
嵌套搜索
您也可以在找到的元素内部进行搜索。
当您想首先找到父元素,然后在其内部找到特定子元素时,这很有用。无论听起来多么奇怪,这都是在处理DOM时非常有用的功能。
// you need this to use Appium locators with fantoccini's Client
use appium_client::find::{AppiumFind, By};
let element = client
.find_by(By::accessibility_id("Click this"))
.await?;
// now let's find a child of element
let image_child = element
.find_by(By::class_name("android.widget.ImageButton"))
.await?;
滚动
要滚动,您可以使用触摸操作。例如,让我们模拟向上滑动以进行滚动。
请记住,滑动会将屏幕“拉动”,因此您需要向下滑动以“拉动”屏幕,从而显示顶部内容。
let swipe_down = TouchActions::new("finger".to_string())
// position the finger first
.then(PointerAction::MoveTo {
duration: Some(Duration::from_millis(0)),
x,
y
})
// THEN touch the screen
.then(PointerAction::Down {
button: MOUSE_BUTTON_LEFT // believe me, it is not a mouse, but a simple touch
})
// THEN move the finger through the screen
.then(PointerAction::MoveTo {
duration: Some(Duration::from_millis(500)),
x,
y
});
client.perform_actions(swipe_down)
.await?;
示例
依赖项
~8–22MB
~361K SLoC