如何测试 Flutter 应用

Flutter 是 Google 的界面工具包,用于通过单一代码库针对移动设备、Web 和桌面设备构建经过原生编译的精美应用。

在此 Codelab 中,您将构建和测试一个简单的 Flutter 应用。该应用将使用 Provider 软件包来管理状态。

学习内容

  • 如何使用微件测试框架创建微件测试
  • 如何通过 integration_test 软件包创建用于测试应用界面和性能的集成测试
  • 如何在单元测试的帮助下测试数据类(提供器)

构建内容

在此 Codelab 中,您首先要构建一个包含内容列表的简单应用。我们为您提供了源代码,以便您直接进行测试。该应用支持以下操作:

  • 将内容添加到收藏夹
  • 查看收藏列表
  • 从收藏夹列表中移除内容

该应用完成后,您将编写以下测试:

  • 用于验证添加和移除操作的单元测试
  • 针对首页和收藏夹页面的微件测试
  • 用于使用集成测试测试整个应用的界面和性能测试

在 Android 上运行的应用的 GIF

您想通过此 Codelab 学习哪些内容?

我不熟悉这个主题,想好好了解一下。 我对这个主题有所了解,但想复习并深入了解一下。 我在寻找示例代码以用到我的项目中。 我在寻找有关特定内容的说明。

您需要使用两款软件才能完成此 Codelab:Flutter SDK一款编辑器

您可以使用以下任意设备运行此 Codelab:

  • 连接到计算机并设为开发者模式的实体设备(Android 或 iOS)。
  • iOS 模拟器(需要安装 Xcode 工具)。
  • Android 模拟器(需要在 Android Studio 中进行设置)。

创建新的 Flutter 应用并更新依赖项

此 Codelab 将重点介绍如何测试 Flutter 移动应用。您将通过您复制和粘贴的源代码文件快速创建要测试的应用。然后,此 Codelab 的其余部分将重点介绍不同类型的测试。

b2f84ff91b0e1396.png 按照您的第一个 Flutter 应用入门指南中的说明创建一个简单的模板化 Flutter 应用。将项目命名为 testing_app(而不是 myapp)。您将通过修改此起始应用来创建最终应用。

b2f84ff91b0e1396.png在 IDE 或编辑器中,打开 pubspec.yaml 文件。添加下列标记为 new 的依赖项,然后保存该文件(您可以删除注释,提高该文件的可读性)。

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.3
  provider: ^4.1.3            # new

dev_dependencies:
  flutter_test:
    sdk: flutter
  integration_test: ^1.0.1    # new
  test: ^1.14.4               # new
  1. 点击 IDE 中的 Pub get 按钮,或在命令行中,从项目顶部运行 flutter pub get

如果出现错误,请使用空格(而不是制表符)确保 dependencies 代码块中的缩进与上面显示的完全相同。YAML 文件对空格很敏感。

接下来,您需要构建应用,以便进行测试。该应用包含以下文件:

  • lib/main.dart - 应用启动所在的主文件
  • lib/screens/home.dart - 用于创建内容列表
  • lib/screens/favorites.dart - 用于为收藏夹列表创建布局
  • lib/models/favorites.dart - 用于为收藏夹列表创建模型类

替换 lib/main.dart 的内容

b2f84ff91b0e1396.pnglib/main.dart 的内容替换为以下代码:

lib/main.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';
import 'package:testing_app/screens/home.dart';

void main() {
  runApp(TestingApp());
}

class TestingApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: MaterialApp(
        title: 'Testing Sample',
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        routes: {
          HomePage.routeName: (context) => HomePage(),
          FavoritesPage.routeName: (context) => FavoritesPage(),
        },
        initialRoute: HomePage.routeName,
      ),
    );
  }
}

lib/screens/home.dart 中添加首页

b2f84ff91b0e1396.pnglib 目录下创建一个新目录 screens,并在新创建的目录下创建一个名为 home.dart 的新文件。在 lib/screens/home.dart 中,添加以下代码:

lib/screens/home.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';

class HomePage extends StatelessWidget {
  static String routeName = '/';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Testing Sample'),
        actions: <Widget>[
          TextButton.icon(
            style: TextButton.styleFrom(primary: Colors.white),
            onPressed: () {
              Navigator.pushNamed(context, FavoritesPage.routeName);
            },
            icon: Icon(Icons.favorite_border),
            label: Text('Favorites'),
          ),
        ],
      ),
      body: ListView.builder(
        itemCount: 100,
        cacheExtent: 20.0,
        padding: const EdgeInsets.symmetric(vertical: 16),
        itemBuilder: (context, index) => ItemTile(index),
      ),
    );
  }
}

class ItemTile extends StatelessWidget {
  final int itemNo;

  const ItemTile(
    this.itemNo,
  );

  @override
  Widget build(BuildContext context) {
    var favoritesList = Provider.of<Favorites>(context);

    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('icon_$itemNo'),
          icon: favoritesList.items.contains(itemNo)
              ? Icon(Icons.favorite)
              : Icon(Icons.favorite_border),
          onPressed: () {
            !favoritesList.items.contains(itemNo)
                ? favoritesList.add(itemNo)
                : favoritesList.remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text(favoritesList.items.contains(itemNo)
                    ? 'Added to favorites.'
                    : 'Removed from favorites.'),
                duration: Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

lib/screens/favorites.dart 中添加“收藏夹”页面

b2f84ff91b0e1396.pnglib/screens 目录下再创建一个名为 favorites.dart 的新文件。在该文件中,添加以下代码:

lib/screens/favorites.dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';

class FavoritesPage extends StatelessWidget {
  static String routeName = '/favorites_page';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Favorites'),
      ),
      body: Consumer<Favorites>(
        builder: (context, value, child) => ListView.builder(
          itemCount: value.items.length,
          padding: const EdgeInsets.symmetric(vertical: 16),
          itemBuilder: (context, index) => FavoriteItemTile(value.items[index]),
        ),
      ),
    );
  }
}

class FavoriteItemTile extends StatelessWidget {
  final int itemNo;

  const FavoriteItemTile(
    this.itemNo,
  );

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: ListTile(
        leading: CircleAvatar(
          backgroundColor: Colors.primaries[itemNo % Colors.primaries.length],
        ),
        title: Text(
          'Item $itemNo',
          key: Key('favorites_text_$itemNo'),
        ),
        trailing: IconButton(
          key: Key('remove_icon_$itemNo'),
          icon: Icon(Icons.close),
          onPressed: () {
            Provider.of<Favorites>(context, listen: false).remove(itemNo);
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Removed from favorites.'),
                duration: Duration(seconds: 1),
              ),
            );
          },
        ),
      ),
    );
  }
}

最后,在 lib/models/favorites.dart 中创建 Favorites 模型

b2f84ff91b0e1396.png 创建一个新目录 models,并在该目录下创建一个名为 favorites.dart 的新文件。在该文件中,添加以下代码:

lib/models/favorites.dart

import 'package:flutter/material.dart';

/// The [Favorites] class holds a list of favorite items saved by the user.
class Favorites extends ChangeNotifier {
  final List<int> _favoriteItems = [];

  List<int> get items => _favoriteItems;

  void add(int itemNo) {
    _favoriteItems.add(itemNo);
    notifyListeners();
  }

  void remove(int itemNo) {
    _favoriteItems.remove(itemNo);
    notifyListeners();
  }
}

该应用现已完成创建,但尚未经过测试。

b2f84ff91b0e1396.png 点击编辑器中的 Run 图标 6869d41b089cc745.png 运行应用。第一次运行应用可能需要一些时间。在后续步骤中,应用的运行速度会变快。它应如下列屏幕截图所示:

be938199b599b605.png

该应用会显示内容列表。点按任意一行上的心形图标,即可填满心形图标并将该内容添加到收藏夹列表。点击 AppBar 上的 Favorites 按钮可进入另一个包含收藏夹列表的屏幕。

该应用现在即可进行测试。您将从下一步开始测试。

首先,对 favorites 模型进行单元测试。什么是单元测试?单元测试可验证软件的每个单元(通常是函数)能否正确执行其预期任务。

Flutter 应用中的所有测试文件(集成测试除外)都位于 test 目录下。

移除 test/widget_test.dart

b2f84ff91b0e1396.png 在开始测试之前,请删除 widget_test.dart 文件。您将添加自己的测试文件。

创建新的测试文件

首先,您需要在 Favorites 模型中测试 add() 方法,以验证是否已将新内容添加到该列表中,并且该列表反映了相应更改。按照惯例,test 目录下的目录结构与 lib 目录下的一致,Dart 文件的名称相同,但以 _test 结尾。

b2f84ff91b0e1396.pngtest 目录下创建一个 models 目录。在这个新目录下,创建一个包含以下内容的 favourites_test.dart 文件:

test/models/favorites_test.dart

import 'package:test/test.dart';
import 'package:testing_app/models/favorites.dart';

void main() {
  group('App Provider Tests', () {
    var favorites = Favorites();

    test('A new item should be added', () {
      var number = 35;
      favorites.add(number);
      expect(favorites.items.contains(number), true);
    });
  });
}

通过 Flutter 测试框架,您可以将彼此相关的类似测试绑定为一组。单个测试文件中可以有多个组,用于测试 /lib 目录下对应文件的不同部分。

test() 方法采用两个位置参数:测试的 description 和用于实际编写测试的 callback

b2f84ff91b0e1396.png 测试从列表中移除某项内容。在同一测试组中复制并粘贴以下测试。将以下代码添加到测试文件中:

test/models/favorites_test.dart

test('An item should be removed', () {
  var number = 45;
  favorites.add(number);
  expect(favorites.items.contains(number), true);
  favorites.remove(number);
  expect(favorites.items.contains(number), false);
});

运行测试

b2f84ff91b0e1396.png 如果您的应用在模拟器或设备上运行,请先将其关闭,然后再继续操作。

b2f84ff91b0e1396.png 在命令行中,转到项目的根目录并输入以下命令:

$ flutter test test/models/favorites_test.dart

如果一切正常,您应该会看到类似于以下内容的消息:

00:06 +2: All tests passed!

完整的测试文件:test/models/favorites_test.dart

如需详细了解单元测试,请参阅单元测试简介

在此步骤中,您将执行微件测试。微件测试是 Flutter 独有的测试,用于测试您选择的每个微件。此步骤将分别测试屏幕(HomePageFavoritesPage)。

微件测试使用 testWidget() 函数,而不是 test() 函数。它还采用了两个参数:description,callback。但在这里,回调将 WidgetTester 作为参数。

微件测试使用 TestFlutterWidgetsBinding 类;这个类可为您的微件提供与运行中应用相同的资源(屏幕尺寸相关信息以及动画调度功能等),但没有实际的应用。相反,您需要使用虚拟环境运行微件,对其进行测量等,然后测试结果。在此示例中,pumpWidget 启动此流程的方式是让框架装载和测量一个特定微件,就像在完整的应用中所做的那样。

微件测试框架提供了用于查找微件的查找器(例如 text()byType()byIcon())以及用于验证结果的匹配器。

首先测试 HomePage 微件。

创建新的测试文件

第一个测试可验证滚动 HomePage 的操作能否正常执行。

b2f84ff91b0e1396.pngtest 目录下创建一个新文件,将其命名为 home_test.dart。在新创建的文件中,添加以下代码:

test/home_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/home.dart';

Widget createHomeScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) => Favorites(),
      child: MaterialApp(
        home: HomePage(),
      ),
    );

void main() {
  group('Home Page Widget Tests', () {
    testWidgets('Testing Scrolling', (tester) async {
      await tester.pumpWidget(createHomeScreen());
      expect(find.text('Item 0'), findsOneWidget);
      await tester.fling(find.byType(ListView), Offset(0, -200), 3000);
      await tester.pumpAndSettle();
      expect(find.text('Item 0'), findsNothing);
    });
  });
}

createHomeScreen() 函数用于创建一个应用,该应用可在 MaterialApp 中加载要测试的微件,并将其封装到 ChangeNotifierProvider 中。HomePage 微件需要这两个微件在微件树中位于它的上方,以便从这两个微件那里继承并获取对它们所提供的数据的访问权限。此函数会作为参数传递给 pumpWidget() 函数。

接下来,测试框架能否找到屏幕上呈现的 ListView

b2f84ff91b0e1396.png 将以下代码段添加到 home_test.dart

test/home_test.dart

group('Home Page Widget Tests', () {

  // BEGINNING OF NEW CONTENT
  testWidgets('Testing if ListView shows up', (tester) async {
    await tester.pumpWidget(createHomeScreen());
    expect(find.byType(ListView), findsOneWidget);
  });
  // END OF NEW CONTENT

  testWidgets('Testing Scrolling', (tester) async {
    await tester.pumpWidget(createHomeScreen());
    expect(find.text('Item 0'), findsOneWidget);
    await tester.fling(find.byType(ListView), Offset(0, -200), 3000);
    await tester.pumpAndSettle();
    expect(find.text('Item 0'), findsNothing);
  });
});

运行测试

您可以像运行单元测试那样运行微件测试,但使用设备或模拟器可以观察测试的运行情况,也支持使用热重启功能。

b2f84ff91b0e1396.png 为您的设备接通电源或启动模拟器。

b2f84ff91b0e1396.png 在命令行中,转到项目的根目录并输入以下命令:

$ flutter run test/home_test.dart

如果一切正常,您应该会看到类似于以下内容的输出:

Launching test/home_test.dart on Mi A3 in debug mode...
Running Gradle task 'assembleDebug'...
Running Gradle task 'assembleDebug'... Done                        62.7s
✓ Built build/app/outputs/flutter-apk/app-debug.apk.
Installing build/app/outputs/flutter-apk/app.apk...                 5.8s
Waiting for Mi A3 to report its views...                            16ms
I/flutter ( 1616): 00:00 +0: Home Page Widget Tests Testing if ListView shows up
Syncing files to device Mi A3...
I/flutter ( 1616): 00:02 +1: Home Page Widget Tests Testing Scrolling
Syncing files to device Mi A3...                                                 4,008ms (!)

Flutter run key commands.
r Hot reload. 🔥🔥🔥
R Hot restart.
h Repeat this help message.
d Detach (terminate "flutter run" but leave application running).
c Clear the screen
q Quit (terminate the application on the device).
An Observatory debugger and profiler on Mi A3 is available at:
http://127.0.0.1:40433/KOsGesHSxR8=/
I/flutter ( 1616): 00:00 +0: Home Page Widget Tests Testing if ListView shows up
I/flutter ( 1616): 00:02 +1: Home Page Widget Tests Testing Scrolling
I/flutter ( 1616): 00:09 +3: All tests passed!

接下来,您需要更改测试文件,并输入 Shift + R,以重启该应用并重新运行所有测试。

b2f84ff91b0e1396.png 向测试 HomePage 微件的组添加更多测试。将以下测试复制到您的文件中:

test/home_test.dart

testWidgets('Testing IconButtons', (tester) async {
  await tester.pumpWidget(createHomeScreen());
  expect(find.byIcon(Icons.favorite), findsNothing);
  await tester.tap(find.byIcon(Icons.favorite_border).first);
  await tester.pumpAndSettle(Duration(seconds: 1));
  expect(find.text('Added to favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsWidgets);
  await tester.tap(find.byIcon(Icons.favorite).first);
  await tester.pumpAndSettle(Duration(seconds: 1));
  expect(find.text('Removed from favorites.'), findsOneWidget);
  expect(find.byIcon(Icons.favorite), findsNothing);
});

此测试用于验证点按 IconButton 是否会将 Icons.favorite_border(一个空心的心形图标)变为 Icons.favorite(一个实心的心形图标),以及再次点按是否会恢复为 Icons.favorite_border

b2f84ff91b0e1396.png 输入 Shift + R。热重启会重启该应用并重新运行所有测试。

完整的测试文件:test/home_test.dart.

b2f84ff91b0e1396.png 使用相同的过程通过以下代码测试 FavoritesPage。执行相同的步骤并运行即可。

test/favorites_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:provider/provider.dart';
import 'package:testing_app/models/favorites.dart';
import 'package:testing_app/screens/favorites.dart';

Favorites favoritesList;

Widget createFavoritesScreen() => ChangeNotifierProvider<Favorites>(
      create: (context) {
        favoritesList = Favorites();
        return favoritesList;
      },
      child: MaterialApp(
        home: FavoritesPage(),
      ),
    );

void addItems() {
  for (var i = 0; i < 10; i += 2) {
    favoritesList.add(i);
  }
}

void main() {
  group('Favorites Page Widget Tests', () {
    testWidgets('Test if ListView shows up', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      expect(find.byType(ListView), findsOneWidget);
    });

    testWidgets('Testing Remove Button', (tester) async {
      await tester.pumpWidget(createFavoritesScreen());
      addItems();
      await tester.pumpAndSettle();
      var totalItems = tester.widgetList(find.byIcon(Icons.close)).length;
      await tester.tap(find.byIcon(Icons.close).first);
      await tester.pumpAndSettle();
      expect(tester.widgetList(find.byIcon(Icons.close)).length,
          lessThan(totalItems));
      expect(find.text('Removed from favorites.'), findsOneWidget);
    });
  });
}

此测试用于验证在按下某项内容的关闭(移除)按钮后,相应内容是否消失。

如需详细了解微件测试,请访问:

集成测试用于测试应用的各部分如何作为一个整体协同运行。integration_test 软件包用于在 Flutter 中执行集成测试。Flutter 提供 Selenium WebDriver(通用 Web)、Protractor (Angular)、Espresso (Android) 或 Earl Gray (iOS) 版本。该软件包内部使用 flutter_driver 在设备上驱动测试。

对应用进行插桩测试

为了编写集成测试,您必须先对应用进行插桩测试。对应用进行插桩测试是指配置应用,以便驱动程序可以访问其 GUI 和函数,从而创建和运行自动测试。集成测试位于名为 integration_test 的目录下。在此步骤中,您需要添加下列用于集成测试的文件:

  • integration_test/driver.dart - 用于对应用进行插桩测试
  • integration_test/app_test.dart - 用于对应用运行实际测试

b2f84ff91b0e1396.png 在项目的根目录下创建一个名为 integration_test 的目录。在这个新创建的目录下,创建一个 driver.dart 文件并添加以下代码:

integration_test/driver.dart

import 'package:integration_test/integration_test_driver.dart';

Future<void> main() => integrationDriver();

上述代码会启用集成测试驱动程序,然后等待测试运行。运行测试后,响应数据存储在名为 integration_response_data.json 的文件中。

编写测试

b2f84ff91b0e1396.png 创建一个新文件,将其命名为 app_test.dart

integration_test/app_test.dart

import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:testing_app/main.dart';

void main() {
  group('Testing App Performance Tests', () {
    final binding = IntegrationTestWidgetsFlutterBinding.ensureInitialized()
        as IntegrationTestWidgetsFlutterBinding;

    binding.framePolicy = LiveTestWidgetsFlutterBindingFramePolicy.fullyLive;
  });
}

ensureInitialized() 函数会验证集成测试驱动程序是否已初始化,并在必要时重新初始化。在 LiveTestWidgetsFlutterBindingFramePolicy 枚举中设置为 fullyLiveframePolicy 最适合用来测试包含大量动画的场景。

接下来,测试该应用的滚动性能,并使用 watchPerformance() 函数进行记录。

b2f84ff91b0e1396.png 将以下代码粘贴到您刚创建的测试组中:

integration_test/app_test.dart

testWidgets('Scrolling test', (tester) async {
  await tester.pumpWidget(TestingApp());

  final listFinder = find.byType(ListView);

  await binding.watchPerformance(() async {
    await tester.fling(listFinder, Offset(0, -500), 10000);
    await tester.pumpAndSettle();

    await tester.fling(listFinder, Offset(0, 500), 10000);
    await tester.pumpAndSettle();
  }, reportKey: 'scrolling_summary');
});

此测试会在内容列表中快速滚动,然后一直向上滚动。watchPerformance() 函数会记录相应操作并生成时间轴摘要,然后将其作为响应数据发回 driver.dart 文件中的测试驱动程序。

接下来,测试 addremove 操作。

b2f84ff91b0e1396.png 将以下测试粘贴到同一组中:

integration_test/app_test.dart

testWidgets('Favorites operations test', (tester) async {
  await tester.pumpWidget(TestingApp());

  final iconKeys = [
    'icon_0',
    'icon_1',
    'icon_2',
  ];

  for (var icon in iconKeys) {
    await tester.tap(find.byKey(ValueKey(icon)));
    await tester.pumpAndSettle(Duration(seconds: 1));

    expect(find.text('Added to favorites.'), findsOneWidget);
  }

  await tester.tap(find.text('Favorites'));
  await tester.pumpAndSettle();

  final removeIconKeys = [
    'remove_icon_0',
    'remove_icon_1',
    'remove_icon_2',
  ];

  for (final iconKey in removeIconKeys) {
    await tester.tap(find.byKey(ValueKey(iconKey)));
    await tester.pumpAndSettle(Duration(seconds: 1));

    expect(find.text('Removed from favorites.'), findsOneWidget);
  }
});

运行测试

b2f84ff91b0e1396.png 为您的设备接通电源或启动模拟器。

b2f84ff91b0e1396.png 在命令行中,转到项目的根目录并输入以下命令:

$ flutter drive --driver integration_test/driver.dart --target integration_test/app_test.dart --profile

如果一切正常,您应该会看到类似于以下内容的输出:

Running "flutter pub get" in step_07...                            930ms
Running Gradle task 'assembleProfile'...
Running Gradle task 'assembleProfile'... Done                      31.3s
✓ Built build/app/outputs/flutter-apk/app-profile.apk (11.3MB).
Installing build/app/outputs/flutter-apk/app.apk...                277ms
VMServiceFlutterDriver: Connecting to Flutter application at http://127.0.0.1:62862/K6QKjUNab8c=/
VMServiceFlutterDriver: Isolate found with number: 1935648057883071
VMServiceFlutterDriver: Isolate is paused at start.
VMServiceFlutterDriver: Attempting to resume isolate
I/flutter (24385): 00:00 +0: Testing App Performance Tests Scrolling test
VMServiceFlutterDriver: Connected to Flutter application.
I/flutter (24385): 00:08 +1: Testing App Performance Tests Favorites operations
test
I/flutter (24385): 00:17 +2: Testing App Performance Tests (tearDownAll)
I/flutter (24385): 00:17 +3: All tests passed!
All tests passed.

测试成功完成后,项目根目录下的 build 目录应包含一个名为 integration_response_data.json 的文件。它包含该测试在运行 scrolling_summary(在此示例中)时返回的响应数据。使用任意文本编辑器打开该文件即可查看相关信息。通过更高级的设置,您可以在每次测试运行时保存摘要,并生成结果图。

完整的测试文件:integration_test/app_test.dart.

如需详细了解 Flutter 驱动程序(集成)测试,请访问:

您已完成此 Codelab,并学习了测试 Flutter 应用的不同方式。

您学到的内容

  • 如何使用微件测试框架来测试微件
  • 如何使用集成测试来测试应用的界面
  • 如何使用集成测试来测试应用的性能
  • 如何在单元测试的帮助下测试提供器

如需详细了解如何在 Flutter 中进行测试,请访问