跳转至

Android 测试框架 —— UI Automator

介绍

UI Automator 是 Google 在 Android 4.1 的时候推出的 Android UI 自动化测试框架。 它可以模拟用户操作(比如:点击、滑动、输入文本等)和获取应用程序的界面信息,帮助开发者构建可靠且高效的自动化测试脚本。

特点和优势

与其他的测试框架相比,UI Automator 具有以下这些特点和优势:

  1. 跨应用程序测试:UI Automator 可以跨应用程序进行自动化测试,可以获取和操作整个设备上的界面元素,而不仅仅局限于单个应用程序。
  2. 强大的界面元素查找能力:UI Automator 提供了丰富的 API 和机制来查找应用程序界面上的元素,可以根据属性、文本、ID 等条件进行准确的查找。
  3. 多种用户操作模拟:UI Automator 支持模拟用户的各种操作,如点击、滑动、长按、输入文本等,可以实现复杂的用户交互行为。
  4. 多设备支持:UI Automator 可以同时连接多个设备,并在这些设备上执行自动化测试。
  5. 异步任务处理:UI Automator 支持处理异步任务,可以等待应用程序加载完成或响应操作完成后再进行下一步操作。
  6. 丰富的日志和报告:UI Automator 提供了详细的日志和报告功能,可以帮助开发者定位问题、分析测试结果。

应用场景

下面是 UI Automator 的一些常见应用场景:

  1. 自动化测试:UI Automator 可以用于开发和执行自动化测试脚本,帮助开发者检测应用程序的功能、性能和稳定性。它可以自动模拟用户操作,执行各种测试用例,并生成详细的测试报告。
  2. UI 自动化验证:UI Automator 可以用于验证应用程序的用户界面是否正确显示和响应。它可以通过查找元素、获取属性和模拟用户操作来验证应用程序的界面元素、布局和交互逻辑。
  3. 多应用程序测试:UI Automator 可以跨应用程序进行测试,对多个应用程序的功能和集成进行验证。它可以在不同的应用程序之间切换,模拟用户在多个应用程序之间的操作和交互。
  4. 兼容性测试:UI Automator 可以在不同的设备和 Android 版本上执行自动化测试,帮助开发者确保应用程序在各种环境下的兼容性。它可以在多个真机和模拟器上运行测试用例,验证应用程序在不同设备上的表现。
  5. 性能测试:UI Automator 可以测量应用程序的性能指标,如启动时间、响应时间和内存占用等。它可以自动执行一系列操作和操作,并记录关键性能数据,以评估应用程序的性能表现。
  6. 用户体验测试:UI Automator 可以模拟用户的真实操作和使用场景,评估应用程序的用户体验。它可以模拟用户的滑动、点击、输入等操作,测试应用程序在不同用户交互情况下的响应和流畅度。

Warning

UI Automator 对于 WebView 构建的应用适配不是很好。

1.0 vs 2.0

UI Automator 主要版本有 1.0 和 2.0,现在大多使用的是 2.0 版本。可通过 UI Automator 官网 查看版本的变更历史。

类型 1.0 2.0
实现语言 Java Java
框架实现 基于 Instrumentation 框架实现 基于 Android 的 AccessibilityService 实现
支持范围 单应用 跨应用
API 功能 提供了一组用于模拟用户操作和获取界面元素信息的 API,如点击、滑动、查找元素等 在 1.0 的基础功能上进行了扩展,提供更多强大的 API 和功能,如通过 UISelector 搜索元素、设置忽略的控件、处理异步任务等。
兼容性 Android 4.1 及以上版本的设备上运行 Android 5.0 及以上的版本运行,相比1.0 版本,2.0 的兼容性更好

快速入门

安装 Android Studio

下载并安装 Android Studio

创建一个项目

在 Android Studio 中,androidTesttest 是两个常见的目录,它们分别用于不同类型的测试:

  1. androidTest:这个目录用于编写 Android UI 测试,通常用于运行 Instrumentation Tests(仪器化测试)。这些测试是针对 Android 应用的 UI 和功能进行的,依赖于 Android 设备或模拟器;
  2. test:这个目录用于编写 本地单元测试,这些测试通常是在本地 JVM 上运行的,与 Android 框架无关。它们用于测试 Java 或 Kotlin 代码的逻辑部分,而不涉及 UI 或设备相关的功能。

找到 build.gradle(Module :app) 添加依赖:

dependencies {
    ...
    androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0-alpha03'
}

编写测试用例

我们以 com.example.uiautomatordemo 作为项目包名,在 androidTest 目录下创建一个 Demo.java 文件用于开发 UI 测试:

app
├── java
│   ├── com.example.uiautomatordemo
│   ├── com.example.uiautomatordemo(androidTest)
│   │   └── Demo.java
│   └── com.example.uiautomatordemo(test)

这个例子中,我们以找到桌面的 Gmail 应用,让 UI Automator 打开这个测试应用:

@RunWith(AndroidJUnit4.class)
public class Demo {
    @Test
    public void openGmail() {
        // 创建一个 Device 对象,然后先返回桌面
        UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
        device.pressHome();

        // 从桌面上找到 Gmail 应用图标,然后点击
        UiObject2 gmail = device.findObject(By.text("Gmail"));
        Boolean opened = gmail.clickAndWait(Until.newWindow(), 3000);
        assertTrue(opened);
    }
}

编写完成后,点击 Android Studio 的运行按钮,可以看到 Gmail 应用启动了。

Warning

测试设备使用的是谷歌的原生机器,使用其他的机器,需要根据机器的应用和布局挑选出合适的应用。

核心类

UI Automator 提供了相关 API 文档 ,可以查询到常用的接口和核心类。

UiDevice

UiDevice 是 UI Automator 中的非常重要的类,用于与设备进行交互,模拟用户行为,以及访问设备的各种 UI 元素。UI Automator 允许开发人员编写测试脚本,通过模拟点击、滑动、输入文本等操作来验证应用程序的行为。

在使用 UiDevice 前,需要通过 UiDevice.getInstance() 获取先初始化 UiDevice

UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

当获取到 UiDevice 后,就可以获取到设备的信息和操作设备了:

UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// 获取屏幕尺寸
DisplayMetrics metrics = new DisplayMetrics();
device.getDisplayMetrics(metrics);

// 获取系统版本
String osVersion = device.getSystemVersion();

// 点击屏幕某个位置坐标
device.click(x, y);

// 滑动和滚动:其中 startX, startY 是滑动的起点坐标,endX, endY 是终点坐标,steps 是滑动的步数
device.swipe(startX, startY, endX, endY, steps);

// 滚动操作(在一个滚动视图中)
UiObject scrollable = device.findObject(new UiSelector().scrollable(true));
scrollable.scrollForward();  // 向前滚动

// 输入文本
UiObject editText = device.findObject(new UiSelector().className("android.widget.EditText"));
editText.setText("Hello, world!");

// 按键操作
// 按 Home 键:
device.pressHome();

// 按返回键:
device.pressBack();

// 按菜单键:
device.pressMenu();

// 按电源键:
device.pressPower();

// 获取设备屏幕截图:
File screenshot = new File("/path/to/save/screenshot.png");
device.takeScreenshot(screenshot);

// UiDevice 提供了等待方法,以确保 UI 元素在交互之前是可见的:
UiObject myButton = device.findObject(new UiSelector().text("Click me"));
myButton.waitForExists(5000);  // 等待最多 5 秒钟,直到按钮存在

UI 自动化测试依赖于页面加载的速度和UI元素的可见性。在查找元素时,使用 waitForExists() 或者 waitForSelector() 等方法来确保元素已经加载。同时,在自动化测试中,设备可能会锁屏,导致 UiDevice 无法操作。可以在测试开始时确保设备解锁:

if (!device.isScreenOn()) {
    device.wakeUp();
}

在一些设备上,可能需要授予应用程序特定的权限(如读取联系人、存储权限等)。在自动化测试中,确保权限已经授权,或者在测试中模拟用户授权。

查找元素

在 UI Automator 中,查找界面的元素的方式有以下三种:

  • 使用 UiSelector 查找元素。UiSelector 是 UI Automator 原生方法。
  • 使用 BySelector 查找元素。BySelectorUiSelector 的方法进行一次封装,使得查找元素更加方便。
  • 使用 By 查找元素。By 是对 BySelector 的再次封装和简化,两者的 API 基本相同。

Quota

谷歌对 ByBySelector 的解释:

By is a utility class which enables the creation of BySelectors in a concise manner. Its primary function is to provide static factory methods for constructing BySelectors using a shortened syntax. For example, you would use findObject(By.text("foo")) rather than findObject(new BySelector().text("foo")) to select UI elements with the text value "foo".

UiSelector

UiSelector 是 UI Automator 中的一个类,用于查找 Android 设备上的 UI 元素(如按钮、文本框、列表项等)。通过使用 UiSelector 搜索出符合要求的 UI 元素,然后与之进行交互(如点击、输入文本、检查文本等)。

// 通过文本查找
UiSelector selector = new UiSelector().text("Hello");

// 通过资源 ID 查找
UiSelector selector = new UiSelector().resourceId("com.example.app:id/button1");

// 通过类名查找
UiSelector selector = new UiSelector().className("android.widget.Button");

// 通过描述查找
UiSelector selector = new UiSelector().description("Submit");

// 通过父元素查找
UiSelector selector = new UiSelector().childSelector(new UiSelector().text("Next"));

// 查找启用状态为 true 的控件
UiSelector selector = new UiSelector().enabled(true);

// 查找可点击的控件
UiSelector selector = new UiSelector().clickable(true);

// 根据控件在父容器中的位置查找
UiSelector selector = new UiSelector().index(1);  // 查找父容器中第2个元素

// 查找包含特定文本的控件
UiSelector selector = new UiSelector().textContains("Submit");

// 使用正则表达式匹配文本内容
UiSelector selector = new UiSelector().textMatches(".*Submit.*");

// 查找具有指定坐标范围的控件。
UiSelector selector = new UiSelector().bounds("[0,0][100,100]");

通常,UiSelector 查找到的控件会与 UiDevicefindObject 方法结合使用,完成点击等动作:

UiSelector selector = new UiSelector().text("Next").clickable(true);
UiObject nextButton = device.findObject(selector);
nextButton.click();

Note

如果找不到符合条件的 UI 元素,UiObject 的相关方法可能会抛出 UiObjectNotFoundException。可以使用 exists() 等方法检查元素是否存在,或者通过 waitForExists() 等方法添加等待机制。

BySelector

UiSelector 的基础上,BySelector 对其所有的方法进行了一次封装,使得查找元素更加方便。

BySelector selector = new BySelector().text("foo");
UiObject foo = device.findObject(selector);
foo.click();

Warning

在最新版本的 UI Automator 上,BySelector 的构造方法标记了:

Clients should not instanciate this class directly. Use the By factory class instead.

谷歌推荐使用 By 方法代替 BySelector

By

UiSelector 的基础上,ByBySelector 再进行了一次封装。经过封装后的 By 缩短了 BySelector 的语法,提供了静态工厂方法来构造 BySelector 对象。

BySelector selector = By.text("foo");
UiObject foo = device.findObject(selector);
foo.click();

通过查看 By.text() 方法的实现,可以看到 By.text() 是对 BySelector 的一层封装。

public static @NonNull BySelector text(@NonNull String text) {
    return new BySelector().text(text);
}

UiObject

使用 UiSelector 或者 By 等方式,筛选出界面上的元素,再通过 UiDevice 执行查找操作后,返回的是一个 UiObject 对象。 UiObject 是 UI Automator 中用于表示和操作单个 UI 元素的类。通过 UiObject,可以与 UI 元素进行交互,如点击、输入文本、检查属性等。

// 获取 UiDevice 实例
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// 使用 UiSelector 查找一个文本为 "Submit" 的按钮,点击按钮
UiObject button = device.findObject(new UiSelector().text("Submit"));
button.click(); 

// 输入文本
UiObject editText = device.findObject(new UiSelector().className("android.widget.EditText"));
editText.setText("Hello, UI Automator!");  // 输入文本

// 获取文本内容
String text = button.getText();

// 获取元素的类名
String className = button.getClassName();  

// 获取元素的类名
if (button.exists()) {
    // 元素存在,可以继续操作
} else {
    // 元素不存在
}

// 长按按钮
button.longClick();  

// 滑动操作
UiObject scrollableList = device.findObject(new UiSelector().className("android.widget.ListView"));
scrollableList.scrollForward();  // 向前滚动

UiObject2

UiObject2 是 UI Automator 2.0 引入的新类,它是 UiObject 的升级版本,具有更多功能和更好的性能支持。UiObject2 对比 UiObject 提供了更高效的 UI 元素查找和操作,尤其是在涉及复杂的布局和动态更新的界面时,UiObject2 显得更加高效和稳定。同时, UiObject2 引入了基于 By 的查找方式,支持更灵活的定位方式,能够更快速地找到 UI 元素。

特性 UiObject UiObject2
引入版本 UI Automator 1.x UI Automator 2.0
查找方式 基于 UiSelector,支持简单查找方式 基于 By,支持多种查找方式,如 By.text()By.desc()
性能 相对较低,处理复杂布局时性能较差 性能较高,特别适用于复杂和动态更新的界面
支持视图 适用于简单 UI 元素操作 支持复杂视图,如 RecyclerViewListView
交互方式 基本的交互操作,如点击、输入文本等 更丰富的交互方式,支持更多UI组件操作
高级功能 功能较为基础,操作简单 支持更复杂的操作,如手势操作、元素滚动等
等待机制 提供基本的等待方法,如 waitForExists() 提供更强大的等待机制,支持更复杂的等待操作
容错性 对动态界面的容错能力较差 对动态界面和大量元素的操作更为稳定

UiObject2 的使用方式和 UiObject 基本相同,不同的是在使用完 findObject() 方法后,返回的是一个 UiObject2 对象:

// 获取 UiDevice 实例
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// 使用 By 查找一个按钮
UiObject2 button = device.findObject(By.text("Submit"));

UiCollection

UiCollection 是 UI Automator 2.0 提供的一种用于处理多个 UI 元素的集合的类。与 UiObjectUiObject2 聚焦于单一 UI 元素的操作不同,UiCollection 主要用于操作一个元素集合,它允许访问和操作一组 UI 元素,如 RecyclerView, ListView, GridView 等。UiCollectionUiObject2 配合使用时,可以更方便地操作复杂的界面组件, 例如在一个可滚动列表中查找多个元素, 或是对多个 RecyclerView 项进行操作。

// 获取 UiDevice 实例
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

// 查找一个包含多个项的集合
UiCollection recyclerView = device.findObject(By.clazz("androidx.recyclerview.widget.RecyclerView"));

// 遍历集合中的所有元素
UiCollection recyclerView = device.findObject(By.clazz("androidx.recyclerview.widget.RecyclerView"));

// 获取子元素的数量
int count = recyclerView.getChildCount();
if (count == 0) {
    Log.d("RecyclerView", "No items found");
}

// 遍历 RecyclerView 中的所有项
int itemCount = recyclerView.getChildCount();
for (int i = 0; i < itemCount; i++) {
    UiObject2 item = recyclerView.getChild(i);  // 获取第 i 项
    String text = item.getText();  // 获取每一项的文本
    Log.d("Item Text", text);
}

// 向下滚动 RecyclerView
recyclerView.scroll(Direction.DOWN, 1.0f);  // 向下滚动

// 获取 RecyclerView 中的第一个子项
UiObject2 firstItem = recyclerView.getChild(0);

// 点击第一个子项
firstItem.click();

UiScrollable

UiScrollable 是 UI Automator 中用于处理滚动操作的类。它通常与 UiCollection 一起使用,尤其是在需要滚动并交互的长列表或其他可滚动容器中。 UiScrollable 提供了方法来滚动到特定的位置、元素或方向,帮助模拟用户在长列表或分页界面中的滚动操作。

UiScrollable 支持向上、向下、向左、向右滚动,可以滚动到包含特定文本或特定属性的元素。在滚动的过程中,支持调整滚动的速度和步数。

UiScrollable scrollable = new UiScrollable(By.className("androidx.recyclerview.widget.RecyclerView"));
// 向下滚动内容直到找到某个元素:
scrollable.scrollTextIntoView("Target Item");

// 滚动指定的距离或到达指定的元素:
scrollable.scrollForward();  // 向下滚动一页
scrollable.scrollBackward(); // 向上滚动一页
scrollable.scroll(Direction.DOWN, 1.0f);  // 滚动一定比例,1.0f 表示滚动满屏

// 滚动并点击某个特定的元素:
UiObject2 targetItem = scrollable.getChild(By.text("Target Item"));
targetItem.click();

条件

Condition 是 UI Automator 中用于等待某些条件满足的机制。在动态加载或界面变化的场景中,Condition 可以帮助实现更为可靠的同步,避免因界面更新未完成而引发的错误。相比传统的自动化测试方法通常使用 Thread.sleep() 来等待一段固定时间, ,使用 Condition,只有在满足特定条件时才会继续执行,不会浪费不必要的时间。Condition 可以理解为 “等待条件”,它在某个条件达成以前不会执行后续的操作。例如,等待某个按钮可点击,或等待一个加载动画消失;等待某个按钮可点击或者等待一个加载动画消失。

Condition 是一个接口类,具体的实现类有 UiObject2ConditionSearchCondition

  • UiObject2Condition 用于检查 UiObject2 的状态。通常,两者结合使用。
  • SearchCondition 代表满足一定条件的,需要查找的 UI 元素,主要用于判断是否存在某个组件。

另外一个条件是 EventConditionEventCondition 是指依赖于某个事件或一系列事件已经发生的条件。EventCondition 也是一个抽象类, 它实现的不是 Condition 接口,而是 UiAutomation.AccessibilityEventFilter 接口。

UiObject2Condition and SearchCondition EventCondition

UiObject2Condition

UiObject2Condition 是一个条件类,用于定义某个 UI 对象(如按钮、文本框、列表项等)在特定情况下的状态。该类的作用是等待某个 UI 元素满足某些特定条件,以便进行下一步的操作。例如,它可以用来等待某个 UI 元素可见、启用或者可点击等。通常这种条件检查在自动化测试中非常有用,特别是在 UI 测试场景中,确保元素准备好再进行交互。

UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
BySelector selector = By.text("foo");
UiObject2 foo = device.findObject(selector);

// 等待控件的字体发生变化,变成成 `Hello World`
UiObject2Condition<Boolean> condition = new UiObject2Condition<>() {
    @Override
    public Boolean apply(UiObject2 args) {
        return Objects.equals(args.getText(), "Hello World");
    }
};

// UiObject2Condition 和 UiObject2 一同使用
foo.wait(condition, 1000);

SearchCondition

SearchCondition 主要用于描述查找某个 UI 元素时需要满足的条件。它可以包含一组条件判断,只有当这些条件都被满足时,才会认为查找的 UI 元素是符合要求的。通常,SearchCondition 不可以单独使用,因为 SearchCondition 的接口方法 Searchable 是一个保护的方法,外部无法直接初始化。

SearchCondition<Boolean> searchCondition = new SearchCondition<Boolean>() {
    @Override
    public Boolean apply(Searchable args) { // Searchable 会报无法找到的错误
        return null;
    }
};

SearchCondition 的初始化一般会通过 Until 类进行。在 Until 类中,定义了很多返回值为 SearchCondition 的静态方法:

Until.java
public static SearchCondition<Boolean> gone(@NonNull BySelector selector) {}
public static SearchCondition<Boolean> hasObject(@NonNull BySelector selector) {}
public static SearchCondition<UiObject2> findObject(@NonNull BySelector selector) {}
public static SearchCondition<List<UiObject2>> findObjects(@NonNull BySelector selector) {}
// 创建一个 Device 对象,然后先返回桌面
UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());

BySelector selector = By.text("foo");
UiObject2 foo = device.findObject(selector);
SearchCondition<UiObject2> searchCondition = Until.findObject(selector);

// 通过 UiDevice 进行等待
device.wait(searchCondition, 1000);
// 通过 UiObject2 进行等待
foo.wait(searchCondition, 1000);

不管是通过 UiDevice 进行等待还是通过 UiObject2 进行等待,最终走到的都是同一个 wait 方法:

public <U> U wait(Condition<? super T, U> condition, long timeout, long interval) {
    long startTime = SystemClock.uptimeMillis();

    U result = condition.apply(mObject);
    for (long elapsedTime = 0; result == null || result.equals(false);
            elapsedTime = SystemClock.uptimeMillis() - startTime) {

        if (elapsedTime >= timeout) {
            break;
        }

        SystemClock.sleep(interval);
        result = condition.apply(mObject);
    }
    return result;
}

EventCondition

EventCondition 是 Android UI 自动化测试框架中用于表示事件条件的类。它的主要作用是在测试中判断某些特定事件是否发生, 通常用于等待某些事件完成,或者某些特定的 UI 元素状态发生变化。 EventCondition 需要重写 getResultaccept 两个接口方法。

EventCondition<Boolean> eventCondition = new EventCondition<Boolean>() {
    @Override
    public Boolean getResult() {
        return null;
    }

    @Override
    public boolean accept(AccessibilityEvent accessibilityEvent) {
        return false;
    }
};

Until

Until 是一个条件工厂类,定义了很多方法的返回值为 UiObject2ConditionSearchConditionEventCondition 的方法:

Public Method 描述
static @NonNull UiObject2Condition<Boolean> checkable(boolean isCheckable) 返回一个条件,取决于 UiObject2 是否可选中。
static @NonNull UiObject2Condition<Boolean> checked(boolean isChecked) 返回一个条件,取决于 UiObject2 是否已选中。
static @NonNull UiObject2Condition<Boolean> clickable(boolean isClickable) 返回一个条件,取决于 UiObject2 是否可点击。
static @NonNull UiObject2Condition<Boolean> descContains(@NonNull String substring) 返回一个条件,当对象的描述包含给定的字符串时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> descEndsWith(@NonNull String substring) 返回一个条件,当对象的描述以给定的字符串结尾时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> descEquals(@NonNull String contentDescription) 返回一个条件,当对象的描述与给定的字符串完全匹配时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> descMatches(@NonNull Pattern regex) 返回一个条件,当对象的描述与给定的正则表达式匹配时。
static @NonNull UiObject2Condition<Boolean> descMatches(@NonNull String regex) 返回一个条件,当对象的描述与给定的正则表达式匹配时。
static @NonNull UiObject2Condition<Boolean> descStartsWith(@NonNull String substring) 返回一个条件,当对象的描述以给定的字符串开始时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> enabled(boolean isEnabled) 返回一个条件,取决于 UiObject2 是否启用。
static @NonNull SearchCondition<UiObject2> findObject(@NonNull BySelector selector) 返回一个搜索条件,当至少找到一个符合选择器的元素时满足该条件。
static @NonNull SearchCondition<List<UiObject2>> findObjects(@NonNull BySelector selector) 返回一个搜索条件,当至少找到一个符合选择器的元素时满足该条件。
static @NonNull UiObject2Condition<Boolean> focusable(boolean isFocusable) 返回一个条件,取决于 UiObject2 是否可聚焦。
static @NonNull UiObject2Condition<Boolean> focused(boolean isFocused) 返回一个条件,取决于 UiObject2 是否获得焦点。
static @NonNull SearchCondition<Boolean> gone(@NonNull BySelector selector) 返回一个搜索条件,当未找到任何符合选择器的元素时满足该条件。
static @NonNull SearchCondition<Boolean> hasObject(@NonNull BySelector selector) 返回一个搜索条件,当至少找到一个符合选择器的元素时满足该条件。
static @NonNull UiObject2Condition<Boolean> longClickable(boolean isLongClickable) 返回一个条件,取决于 UiObject2 是否可长按点击。
static @NonNull EventCondition<Boolean> newWindow() 返回一个条件,取决于是否出现了新窗口。
static @NonNull EventCondition<Boolean> scrollFinished(@NonNull Direction direction) 返回一个条件,取决于滚动操作是否在给定方向上完成。
static @NonNull UiObject2Condition<Boolean> scrollable(boolean isScrollable) 返回一个条件,取决于 UiObject2 是否可滚动。
static @NonNull UiObject2Condition<Boolean> selected(boolean isSelected) 返回一个条件,取决于 UiObject2 是否已被选中。
static @NonNull UiObject2Condition<Boolean> textContains(@NonNull String substring) 返回一个条件,当对象的文本包含给定的字符串时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> textEndsWith(@NonNull String substring) 返回一个条件,当对象的文本以给定的字符串结尾时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> textEquals(@NonNull String text) 返回一个条件,当对象的文本与给定的字符串完全匹配时(区分大小写)。
static @NonNull UiObject2Condition<Boolean> textMatches(@NonNull Pattern regex) 返回一个条件,当对象的文本与给定的正则表达式匹配时。
static @NonNull UiObject2Condition<Boolean> textMatches(@NonNull String regex) 返回一个条件,当对象的文本与给定的正则表达式匹配时。
static @NonNull UiObject2Condition<Boolean> textNotEquals(@NonNull String text) 返回一个条件,当对象的文本与给定的字符串不匹配时。

Configurator

Configurator 用于设置 UI Automator 测试的关键参数。设置后会立即生效,并且可以在测试运行期间随时更改。 修改参数前需要先通过调用 getInstance 获取一个实例。在使用修改后的参数运行测试后,务必恢复原始的参数值,否则这将影响其他测试用例。

Public Method 描述
long getActionAcknowledgmentTimeout() 获取等待 UiObject 点击确认的当前超时时间。
static @NonNull Configurator getInstance() 获取 Configurator 的单例实例。
long getKeyInjectionDelay() 此方法已废弃。此参数不再使用(文本直接设置,而非通过按键)。
long getScrollAcknowledgmentTimeout() 获取等待 UiScrollable 滚动操作确认的当前超时时间。
int getToolType() 获取用于运动事件的当前工具类型。
int getUiAutomationFlags() 获取用于获取 android.app.UiAutomation 实例的当前标志。
long getWaitForIdleTimeout() 获取在开始 UiAutomator 操作之前等待用户界面进入空闲状态的当前超时时间。
long getWaitForSelectorTimeout() 获取等待 UiObject 在用户界面中变为可见,以便能够通过 UiSelector 匹配的当前超时时间。
@NonNull Configurator setActionAcknowledgmentTimeout(long timeout) 设置等待 UiObject 点击确认的超时时间。
@NonNull Configurator setKeyInjectionDelay(long delay) 设置按键注入延迟(此方法已废弃)。
@NonNull Configurator setScrollAcknowledgmentTimeout(long timeout) 设置等待 UiScrollable 滚动操作确认的超时时间。
@NonNull Configurator setToolType(int toolType) 设置用于运动事件的工具类型。
@NonNull Configurator setUiAutomationFlags(int flags) 设置获取 android.app.UiAutomation 实例时使用的标志。
@NonNull Configurator setWaitForIdleTimeout(long timeout) 设置等待用户界面进入空闲状态的超时时间,在开始 UiAutomator 操作之前。
@NonNull Configurator setWaitForSelectorTimeout(long timeout) 设置等待 UiObject 在用户界面中变为可见的超时时间,以便能够通过 UiSelector 匹配。

Viewer

UI Automator Viewer

在 Android 的 SDK 中提供了一个用于查找 UI 界面元素的工具:uiautomatorviewer.bat。该工具的作用是可以通过连接的 Android 设备或模拟器截图当前应用的界面,方便开发者查看界面布局。

点击 uiautomatorviewer.batDevice Screenshot 按钮,工具就会展示 UI 元素的层级树(Hierarchy),并显示每个元素的属性,如 text(文本)、resource-id(资源ID)、class(类名)、content-desc(内容描述)等。开发者可以通过该工具查看 UI 元素的各种属性,进而编写精确的 UI 自动化测试脚本。通过查看 UI 元素的定位信息(如 ID、类名、文本等),可以帮助定位元素进行点击、输入等操作。

UI Automator Viewer

Danger

uiautomatorviewer.bat 在 Java 1.8 的环境下运行良好。在其他的 Java 版本上(比如 11、17、18 等)会出现闪退的情况。

Weditor

除了使用 Android 原生提供的 uiautomatorviewer.bat 工具,其他的三方也提供了类似功能的工具。比如 Python 的自动化框架提供的 ATX Weditor 工具。

安装和使用 ATX Weditor 的步骤如下:

Step 1:安装 Python,推荐安装 Python 3。不知道如何安装的话,可以参考 安装 Python 这篇文章。

python --version

Step 2:安装 weditor 工具:

pip install weditor

Step 3:手机连接电脑,确保 adb 可以识别到设备,然后执行:

python -m weditor

执行成功后,打开浏览器访问:http://localhost:17310/

Weditor

原文链接:https://blog.csdn.net/folcan/article/details/123441086

Warning

在安装过程中,若出现报错 UnicodeDecodeError: 'gbk' codec can't decode byte 0xad in position 825: illegal multibyte sequence 可以换一个版本安装:

pip install weditor==0.6.3

Warning

在启动 Weditor 后,点击浏览器报 AttributeError: 'Device' object has no attribute 'address' 时,可以修改 page.py 文件的 IP 地址:

\Lib\site-packages\weditor\web\handlers\page.py
81
82
83
84
if platform == "android":
# ws_addr = get_device(id).device.address.replace("http://", "ws://") # yapf: disable
ret['screenWebSocketUrl'] = "192.168.1.77" + "/minicap"
self.write(ret)