插件介绍

espresso 是一个为 Flutter 应用提供 Espresso 测试绑定的包,它允许开发者从原生 Espresso 测试中驱动 Flutter 小部件。这个包主要用于 Android 平台的端到端测试,提供了一种无缝集成原生 Android 测试框架 Espresso 和 Flutter 应用的方式。

主要特点:

  • 跨框架测试:允许在原生 Espresso 测试中与 Flutter 小部件进行交互
  • 丰富的匹配器:提供了多种匹配器来定位 Flutter 小部件,如 withTextwithTooltipwithValueKey
  • 完整的操作集:支持对 Flutter 小部件执行点击、输入等操作
  • 断言功能:可以验证 Flutter 小部件的状态和属性

在鸿蒙平台上使用 espresso 包,可以结合鸿蒙的测试框架和 Espresso 测试框架,为 Flutter 应用提供更全面的端到端测试能力。

如何使用插件

包的引入

由于这是一个为鸿蒙平台定制修改的版本,需要以 git 形式引入。在项目的 pubspec.yaml 文件中添加以下依赖配置:

dev_dependencies:
  espresso:
    git:
      url: "https://gitcode.com/openharmony-tpc/flutter_packages.git"
      path: "packages/espresso"

注意:espresso 包通常作为开发依赖(dev_dependency)引入,而不是运行时依赖。

添加依赖后,运行 flutter pub get 命令来获取包:

flutter pub get

配置 Android 项目

由于 espresso 包是基于 Android 的 Espresso 测试框架,需要在 Android 项目中进行一些配置:

  1. android/app/src/main/AndroidManifest.xml 文件中添加以下配置(建议在 debug 或 androidTest 目录下的 AndroidManifest.xml 中添加):
<application android:usesCleartextTraffic="true">
  <!-- 其他配置 -->
</application>
  1. android/app/build.gradle 文件中添加以下依赖:
dependencies {
    testImplementation 'junit:junit:4.13.2'
    testImplementation "com.google.truth:truth:1.0"
    androidTestImplementation 'androidx.test:runner:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    api 'androidx.test:core:1.2.0'
}

创建测试文件

  1. 在 Android 项目中创建测试目录和文件:

    创建 android/app/src/androidTest/java/com/example/ 目录(根据你的包名调整),并创建测试文件,例如 MainActivityTest.java

  2. 编写 Espresso 测试代码:

package com.example.espresso_example;

import static androidx.test.espresso.flutter.EspressoFlutter.onFlutterWidget;
import static androidx.test.espresso.flutter.action.FlutterActions.click;
import static androidx.test.espresso.flutter.assertion.FlutterAssertions.matches;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withText;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withTooltip;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withValueKey;

import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Before
    public void setUp() throws Exception {
        ActivityScenario.launch(MainActivity.class);
    }

    @Test
    public void performClick() {
        // 点击具有 "Increment" 提示的 Flutter 按钮
        onFlutterWidget(withTooltip("Increment")).perform(click());
        // 验证具有 "CountText" key 的文本小部件内容是否符合预期
        onFlutterWidget(withValueKey("CountText")).check(matches(withText("Button tapped 1 time.")));
    }
}
  1. 创建测试驱动程序:

    在项目的 test_driver/ 目录下创建测试驱动文件,例如 integration_test.dart

import 'package:flutter_driver/driver_extension.dart';
import 'package:<app_package_name>/main.dart' as app;

void main() {
  enableFlutterDriverExtension();
  app.main();
}

<app_package_name> 替换为你的应用包名。

运行测试

使用以下命令运行 Espresso 测试:

./gradlew app:connectedAndroidTest -Ptarget=`pwd`/../test_driver/integration_test.dart

API 的调用

espresso 包提供了一系列 API 用于在 Espresso 测试中与 Flutter 小部件进行交互:

定位 Flutter 小部件

  • withText(String text):根据文本内容查找小部件
  • withTooltip(String tooltip):根据提示文本查找小部件
  • withValueKey(String key):根据键值查找小部件
  • withType(String type):根据小部件类型查找小部件
  • isDescendantOf(FlutterMatcher ancestorMatcher):查找特定父小部件的子小部件

执行操作

  • click():执行点击操作
  • syntheticClick():执行合成点击操作
  • enterText(String text):输入文本
  • scrollTo():滚动到小部件

验证断言

  • matches(FlutterMatcher matcher):验证小部件是否匹配指定条件

完整的 API 示例

// 定位并点击具有特定文本的按钮
onFlutterWidget(withText("Submit")).perform(click());

// 定位文本输入框并输入文本
onFlutterWidget(withValueKey("EmailInput")).perform(enterText("test@example.com"));

// 定位文本小部件并验证内容
onFlutterWidget(withValueKey("WelcomeText")).check(matches(withText("Welcome to the app!")));

// 定位列表项并滚动到它
onFlutterWidget(withText("Item 100")).perform(scrollTo());

// 组合匹配器:查找特定类型的子小部件
onFlutterWidget(isDescendantOf(withType("ListView"))).check(matches(withText("Item 5")));

完整示例

以下是一个完整的示例,展示了如何在鸿蒙应用中使用 espresso 包:

1. Flutter 应用代码(main.dart)

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Espresso Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(title: 'Espresso Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              key: const ValueKey('CountText'),
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

2. 测试驱动程序(test_driver/integration_test.dart)

import 'package:flutter_driver/driver_extension.dart';
import 'package:espresso_demo/main.dart' as app;

void main() {
  enableFlutterDriverExtension();
  app.main();
}

3. Espresso 测试(android/app/src/androidTest/java/com/example/espresso_demo/MainActivityTest.java)

package com.example.espresso_demo;

import static androidx.test.espresso.flutter.EspressoFlutter.onFlutterWidget;
import static androidx.test.espresso.flutter.action.FlutterActions.click;
import static androidx.test.espresso.flutter.assertion.FlutterAssertions.matches;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withText;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withTooltip;
import static androidx.test.espresso.flutter.matcher.FlutterMatchers.withValueKey;

import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class MainActivityTest {

    @Before
    public void setUp() throws Exception {
        ActivityScenario.launch(MainActivity.class);
    }

    @Test
    public void incrementCounter() {
        // 初始状态验证
        onFlutterWidget(withValueKey("CountText")).check(matches(withText("0")));
        
        // 点击增加按钮
        onFlutterWidget(withTooltip("Increment")).perform(click());
        
        // 验证计数器是否增加到 1
        onFlutterWidget(withValueKey("CountText")).check(matches(withText("1")));
        
        // 再次点击增加按钮
        onFlutterWidget(withTooltip("Increment")).perform(click());
        
        // 验证计数器是否增加到 2
        onFlutterWidget(withValueKey("CountText")).check(matches(withText("2")));
    }
}

注意事项

  1. 平台限制espresso 包主要针对 Android 平台设计,在鸿蒙平台上使用时需要确保兼容性。

  2. 依赖配置:需要正确配置 Android 项目的依赖和权限,特别是 android:usesCleartextTraffic="true" 配置。

  3. 测试驱动程序:必须创建并使用测试驱动程序来启用 Flutter Driver 扩展。

  4. 小部件键值:为了便于测试,建议为需要测试的 Flutter 小部件添加唯一的 ValueKey

  5. 测试环境:需要在连接的设备或模拟器上运行测试,确保设备已启用开发者选项和 USB 调试。

  6. 版本兼容性:确保使用与 Flutter SDK 版本兼容的 espresso 包版本。

  7. 鸿蒙适配:由于是在鸿蒙平台上使用,可能需要根据鸿蒙的特殊要求进行额外的适配和测试。

总结

espresso 是一个功能强大的 Flutter 包,它允许开发者在原生 Espresso 测试中与 Flutter 小部件进行交互,为 Flutter 应用提供了更全面的端到端测试能力。

在鸿蒙平台上使用 espresso 包,可以:

  1. 结合鸿蒙的测试框架和 Espresso 测试框架,为 Flutter 应用提供更全面的测试覆盖
  2. 使用丰富的匹配器、操作和断言 API,实现对 Flutter 小部件的精确控制和验证
  3. 编写清晰、可维护的测试代码,提高应用的质量和稳定性

虽然 espresso 包主要针对 Android 平台设计,但通过适当的配置和适配,可以在鸿蒙平台上使用它来测试 Flutter 应用。对于需要在鸿蒙平台上开发高质量 Flutter 应用的开发者来说,espresso 包是一个非常有价值的测试工具。

需要注意的是,随着鸿蒙平台的不断发展和完善,可能需要对 espresso 包进行进一步的适配和优化,以充分利用鸿蒙平台的特性和优势。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐