Flutter机器人控制插件flutter_robot的使用

Flutter机器人控制插件flutter_robot的使用

简介

flutter_robot 是一个用于创建页面测试的插件,通过模拟多设备屏幕大小、iOS主按钮、状态栏和键盘打开等场景,验证控制器(如Cubit/Bloc/MobX等)与视图之间的正确交互。

安装

首先,在项目的 pubspec.yaml 文件中添加 flutter_robot 作为开发依赖项:

$ dart pub add dev:flutter_robot

创建第一个机器人测试

第一步 - 创建机器人

在项目中创建两个文件:{page_name}_robot.dart{page_name}_test.dart。我们以 my_feature_page_robot.dartmy_feature_page_test.dart 为例。

my_feature_page_robot.dart

class MyFeaturePageRobot extends Robot {
  MyFeaturePageRobot({
    required super.tester,
  });

  @override
  Widget build() {
    // 返回要测试的页面或小部件
    return const MyFeaturePage();
  }

  Future<void> assertScreen() {
    // 捕获当前屏幕快照
    return takeSnapshot('MyFeaturePage_screen');
  }

  // 创建其他方法来与 'WidgetTester' API 交互,如 tap、enterText 等。
  // 或者使用 RobotElement 查找小部件并与其交互。
}

第二步 - 创建测试

my_feature_page_test.dart

import 'package:flutter_robot/flutter_robot.dart';
import 'package:flutter_test/flutter_test.dart';

import 'my_feature_page_robot.dart';

void main() {
  // 设置机器人
  setUpRobot(
    (tester) => MyFeaturePageRobot(tester: tester),
  );

  // 运行测试
  testRobot<MyFeaturePageRobot>(
    'Should show page correctly',
    (robot) async {
      await robot.assertScreen();
    },
  );
}

创建黄金文件

运行以下命令更新黄金文件:

$ flutter test --update-goldens

如果一切正常,测试将通过并生成名为 golden_files 的文件夹,并在其中创建 MyFeaturePage_screen.png 文件。

使用场景

第一步 - 创建场景

my_feature_page_scenarios.dart 中定义场景:

abstract class MyFeaturePageScenarios extends RobotScenario {
  @override
  FutureOr<void> injectDependencies() {}

  @override
  FutureOr<void> mockScenario() {}
}

第二步 - 实现基础机器人文件

my_feature_page_robot.dart

class MyFeaturePageRobot extends Robot<MyFeaturePageScenarios> {
  MyFeaturePageRobot({
    required super.tester,
    required super.scenario,
  });

  @override
  Widget build() {
    return const MyFeaturePage();
  }

  Future<void> assertSuccessScreenGolden() {
    // 捕获成功场景的快照
    return takeSnapshot('MyFeaturePage_success');
  }
}

第三步 - 创建测试

my_feature_page_test.dart

import 'package:flutter_test/flutter_test.dart';

import 'my_feature_page_robot.dart';
import 'my_feature_page_scenarios.dart';

void main() {
  // 设置机器人
  setUpRobot(
    (tester) => MyFeaturePageRobot(
      tester: tester,
    ),
  );

  // 运行测试
  testRobot<MyFeaturePageRobot>(
    'Should show the success case correctly',
    (robot) async {
      await robot.assertSuccessScreenGolden();
    },
    scenario: MyFeaturePageSuccess(), // 定义成功的场景
  );
}

在多设备上运行测试

为了在多设备上运行测试,可以传递 devices 参数给 testRobot 方法:

void main() {
  // 设置机器人
  setUpRobot(
    (tester) => MyFeaturePageRobot(
      tester: tester,
    ),
  );

  // 运行测试
  testRobot<MyFeaturePageRobot>(
    'Should run in all devices',
    (robot) async {
      await robot.assertScreen();
    },
    devices: [
      RobotDevice.small(),
      RobotDevice.medium(),
      RobotDevice.large(),
      RobotDevice(
        name: 'custom',
        sizeScreen: const Size(800, 800),
        withStatusBar: true,
        withKeyboard: true,
        withIOSHomeButton: true,
      ),
    ],
  );
}

使用 RobotElement

RobotElement 可帮助你查找和与小部件树中的特定元素进行交互。

my_feature_page_robot.dart

class MyFeaturePageRobot extends Robot {
  MyFeaturePageRobot({
    required super.tester,
  });

  @override
  Widget build() {
    return const MyFeaturePage();
  }

  // 通过键获取特定元素
  RobotElement get submitButton => RobotElement.byKey(Key('submit_button'), tester);

  // 通过类型获取元素
  RobotElement get textField => RobotElement.byType(TextField, tester);

  // 通过文本获取元素
  RobotElement get welcomeText => RobotElement.byText('Welcome!', tester);

  // 通过图标获取元素
  RobotElement get settingsIcon => RobotElement.byIcon(Icons.settings, tester);
}

my_feature_page_test.dart

void main() {
  // 设置机器人
  setUpRobot(
    (tester) => MyFeaturePageRobot(tester: tester),
  );

  // 运行测试
  testRobot<MyFeaturePageRobot>(
    'Should interact with the elements',
    (robot) async {
      await robot.submitButton.scrollTo();
      await robot.submitButton.tap();
      await robot.welcomeText.assertIsVisible();
      await robot.settingsIcon.longPress();
      await robot.textField.enterText('Test input');
    },
  );
}

加载字体

要加载字体以在黄金文件中显示文本和图标,可以使用 RobotFontLoaderManager

flutter_test_config.dart

import 'dart:async';

import 'package:flutter_robot/flutter_robot.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  RobotFontLoaderManager().add(MyCustomIconFontLoader());
  return testMain();
}

或者覆盖 Robot 类中的 fontLoaders 方法:

import 'dart:async';

import 'package:flutter_robot/flutter_robot.dart';

class MyRobot extends Robot {
  List<RobotFontLoader> get fontLoaders => [
    MyCustomIconFontLoader(),
  ];
}

加载资源

Robot 会尝试加载小部件树中的所有 ImageProvider。如果需要手动加载资源,可以调用 loadAsyncImageProvider

黄金文件差异阈值

为了处理在不同操作系统上的差异,可以设置 threshold 来避免小差异导致测试失败。

flutter_test_config.dart

import 'dart:async';

import 'package:flutter_robot/flutter_robot.dart';

Future<void> testExecutable(FutureOr<void> Function() testMain) async {
  RobotFileComparator.thresholdDefault = 0.05; // 5%
  return testMain();
}

也可以为特定的 Robot 设置 threshold

class ExamplePageRobot extends Robot {
  ExamplePageRobot({
    required super.tester,
    required super.scenario,
  }) : super(goldenThreshold: 0.05);

  ...
}

更多关于Flutter机器人控制插件flutter_robot的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter机器人控制插件flutter_robot的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于Flutter中的flutter_robot插件(请注意,flutter_robot并非一个广泛认知的官方或主流插件,这里假设它是一个自定义或特定领域的插件,用于机器人控制),我可以提供一个假设性的代码示例来展示如何在Flutter应用中集成和使用这样一个插件。

首先,假设flutter_robot插件提供了基本的机器人控制功能,比如移动、旋转、抓取等。以下是一个简化的示例,展示如何在Flutter中使用这个插件。

1. 添加依赖

首先,你需要在pubspec.yaml文件中添加对flutter_robot插件的依赖(假设它已经在pub.dev上发布,或者你已经将其作为本地包包含在内)。

dependencies:
  flutter:
    sdk: flutter
  flutter_robot: ^1.0.0  # 假设版本号为1.0.0

2. 导入插件

在你的Dart文件中导入flutter_robot插件。

import 'package:flutter_robot/flutter_robot.dart';

3. 初始化机器人控制器

假设flutter_robot提供了一个RobotController类来处理与机器人的通信。

class _MyHomePageState extends State<MyHomePage> {
  late RobotController _robotController;

  @override
  void initState() {
    super.initState();
    // 初始化机器人控制器,这里可能涉及到连接到实际的机器人硬件或模拟环境
    _robotController = RobotController.instance;
    _robotController.connect(); // 假设有一个connect方法用于建立连接
  }

  @override
  void dispose() {
    _robotController.disconnect(); // 断开连接
    super.dispose();
  }

4. 使用控制器控制机器人

现在你可以使用_robotController来发送控制命令给机器人。

void _moveForward() {
  _robotController.move(direction: Direction.forward, speed: 50); // 假设有一个move方法,接受方向和速度参数
}

void _rotateLeft() {
  _robotController.rotate(direction: Rotation.left, speed: 30); // 假设有一个rotate方法,接受旋转方向和速度参数
}

void _grabObject() {
  _robotController.grab(action: GrabAction.open); // 打开抓手
  Future.delayed(Duration(seconds: 1), () { // 延迟1秒后执行抓取动作
    _robotController.grab(action: GrabAction.close); // 关闭抓手
  });
}

5. 在UI中调用控制方法

最后,在你的Flutter UI中添加按钮来触发上述控制方法。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: Text('Robot Control'),
    ),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          ElevatedButton(
            onPressed: _moveForward,
            child: Text('Move Forward'),
          ),
          ElevatedButton(
            onPressed: _rotateLeft,
            child: Text('Rotate Left'),
          ),
          ElevatedButton(
            onPressed: _grabObject,
            child: Text('Grab Object'),
          ),
        ],
      ),
    ),
  );
}

注意事项

  • 上述代码是一个假设性的示例,实际使用时需要根据flutter_robot插件提供的API进行调整。
  • 连接和控制真实机器人硬件可能需要处理更多的细节,比如错误处理、状态反馈、安全机制等。
  • 如果flutter_robot是一个私有或特定领域的插件,确保你有正确的访问权限和文档。

希望这个示例能帮助你理解如何在Flutter中集成和使用一个假设的机器人控制插件。如果你有具体的flutter_robot插件文档或源代码,进一步定制和扩展这个示例将会更加直接和有效。

回到顶部