Flutter页面对象模型插件page_object的使用

Flutter页面对象模型插件page_object的使用

page_object 是一个用于在 Flutter 应用中实现页面对象模式(Page Object Pattern)的包。阅读更多关于该模式的信息可以在这里查看:Page Object 模式

该包与我们的 given_when_then 包结合使用时,可以显著提高测试的可读性。

以下是一个简单的示例:

void main() {
  // 测试不使用PageObject的情况
  testWidgets('My home widget has a title and message, NOT using PageObject',
      (WidgetTester tester) async {
    await tester.pumpWidget(const MyApp(MyWidget(title: 'T', message: 'M')));
    final titleFinder = find.descendant(
      of: find.descendant(
        of: find.byType(MyApp),
        matching: find.byType(MyWidget),
      ),
      matching: find.byKey(MyWidget.titleKey),
    );
    final messageFinder = find.descendant(
      of: find.descendant(
        of: find.byType(MyApp),
        matching: find.byType(MyWidget),
      ),
      matching: find.byKey(MyWidget.messageKey),
    );
    expect(titleFinder, allOf(findsOneWidget, _HasText('T')));
    expect(messageFinder, allOf(findsOneWidget, _HasText('M')));
  });

  // 测试使用PageObject的情况
  testWidgets('My home widget has a title and message, using PageObject',
      (WidgetTester tester) async {
    await tester.pumpWidget(const MyApp(MyWidget(title: 'T', message: 'M')));
    final app = MyAppPageObject();
    expect(app.home.title, allOf(findsOneWidget, _HasText('T')));
    expect(app.home.message, allOf(findsOneWidget, _HasText('M')));
  });
}

/// 这是一个应用程序中的根部件,用于演示嵌套的 [PageObject]
class MyApp extends StatelessWidget {
  const MyApp(this.home);
  final MyWidget home;

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(home: home);
  }
}

/// 这只是一个简单的部件,用于展示 [PageObject] 的概念
class MyWidget extends StatelessWidget {
  const MyWidget({
    Key key,
    @required this.title,
    @required this.message,
  }) : super(key: key);
  final String title;
  final String message;

  static const Key titleKey = Key('MyWidget.title');
  static const Key messageKey = Key('MyWidget.message');

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: Scaffold(
        appBar: AppBar(
          title: Text(
            title,
            key: titleKey,
          ),
        ),
        body: Center(
          child: Text(
            message,
            key: messageKey,
          ),
        ),
      ),
    );
  }
}

/// 这是应用程序根部件的一个 [PageObject] 示例。
/// 在这里,`MyAppPageObject` 可以作为一个 [Finder],并且它包含一个子 [PageObject]。
class MyAppPageObject extends PageObject {
  MyAppPageObject() : super(find.byType(MyApp));

  MyWidgetPageObject get home => MyWidgetPageObject(this);
}

/// 这是 [PageObject] 的一个示例。在这里,`MyWidgetPageObject` 可以作为一个 [Finder],
/// 并且它可以包含子查找器或其他 [PageObject]。
class MyWidgetPageObject extends PageObject {
  MyWidgetPageObject(Finder finder)
      : super(find.descendant(of: finder, matching: find.byType(MyWidget)));

  Finder get title =>
      find.descendant(of: this, matching: find.byKey(MyWidget.titleKey));

  Finder get message =>
      find.descendant(of: this, matching: find.byKey(MyWidget.messageKey));
}

/// 为了使测试更像一个真实场景,这里添加了一个例子。
class _HasText extends CustomMatcher {
  _HasText(dynamic matcher) : super('Text data', 'data', matcher);

  [@override](/user/override)
  Object featureValueOf(dynamic actual) {
    if (actual is Finder) {
      final element = actual.evaluate().single;
      final widget = element.widget;
      if (widget is Text) {
        return widget.data;
      } else {
        throw Exception('_HasText matcher can\'t be applied to $element');
      }
    } else {
      throw Exception(
          '_HasText matcher can only be applied to a Finder object');
    }
  }
}

更多关于Flutter页面对象模型插件page_object的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter页面对象模型插件page_object的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


page_object 是一个用于 Flutter 的页面对象模型(Page Object Model, POM)插件,旨在帮助开发者更好地组织和管理 UI 测试代码。通过使用页面对象模型,你可以将页面的元素和操作封装在一个类中,从而提高测试代码的可读性、可维护性和可重用性。

安装 page_object 插件

首先,你需要在 pubspec.yaml 文件中添加 page_object 插件的依赖:

dev_dependencies:
  page_object: ^1.0.0

然后运行 flutter pub get 来安装插件。

基本用法

1. 创建一个页面对象类

页面对象类通常包含页面的元素定位符和操作这些元素的方法。例如,假设你有一个登录页面,你可以创建一个 LoginPage 类:

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

class LoginPage extends PageObject {
  LoginPage(WidgetTester tester) : super(tester);

  // 定位用户名输入框
  Finder get usernameField => find.byKey(Key('usernameField'));

  // 定位密码输入框
  Finder get passwordField => find.byKey(Key('passwordField'));

  // 定位登录按钮
  Finder get loginButton => find.byKey(Key('loginButton'));

  // 输入用户名
  Future<void> enterUsername(String username) async {
    await tester.enterText(usernameField, username);
  }

  // 输入密码
  Future<void> enterPassword(String password) async {
    await tester.enterText(passwordField, password);
  }

  // 点击登录按钮
  Future<void> clickLoginButton() async {
    await tester.tap(loginButton);
    await tester.pump();
  }
}

2. 在测试中使用页面对象

在测试中,你可以使用页面对象类来执行页面的操作。例如:

import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/login_page.dart'; // 假设你的登录页面类在 login_page.dart 文件中

void main() {
  testWidgets('Login test', (WidgetTester tester) async {
    // 初始化页面对象
    final loginPage = LoginPage(tester);

    // 加载登录页面
    await tester.pumpWidget(MyApp());

    // 输入用户名和密码
    await loginPage.enterUsername('testuser');
    await loginPage.enterPassword('password123');

    // 点击登录按钮
    await loginPage.clickLoginButton();

    // 验证登录成功后的页面
    expect(find.text('Welcome, testuser!'), findsOneWidget);
  });
}
回到顶部