跳至主要內容

小工具測試簡介

單元測試簡介範例中,您學會如何使用 test 套件測試 Dart 類別。若要測試小工具類別,您需要 Flutter SDK 隨附的flutter_test套件提供的其他工具。

flutter_test 套件提供下列工具來測試小工具

  • WidgetTester 可讓您在測試環境中建構小工具並與之互動。
  • testWidgets() 函式會自動為每個測試案例建立新的 WidgetTester,並取代一般的 test() 函式。
  • Finder 類別可讓您在測試環境中搜尋小工具。
  • 特定小工具的 Matcher 常數可協助驗證 Finder 是否在測試環境中找到小工具或多個小工具。

如果您覺得資訊量太大,請別擔心。在本範例中,您將了解所有這些組件如何組合在一起,其中使用下列步驟

  1. 新增 flutter_test 相依性。
  2. 建立要測試的小工具。
  3. 建立 testWidgets 測試。
  4. 使用 WidgetTester 建構小工具。
  5. 使用 Finder 搜尋小工具。
  6. 使用 Matcher 驗證小工具。

1. 新增 flutter_test 相依性

#

在撰寫測試之前,請將 flutter_test 相依性包含在 pubspec.yaml 檔案的 dev_dependencies 區段中。如果使用命令列工具或程式碼編輯器建立新的 Flutter 專案,則此相依性應該已經存在。

yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

2. 建立要測試的小工具

#

接下來,建立一個小工具以供測試。在此範例中,請建立一個顯示 titlemessage 的小工具。

dart
class MyWidget extends StatelessWidget {
  const MyWidget({
    super.key,
    required this.title,
    required this.message,
  });

  final String title;
  final String message;

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

3. 建立 testWidgets 測試

#

有了要測試的小工具後,請從撰寫您的第一個測試開始。使用 flutter_test 套件提供的 testWidgets() 函式來定義測試。testWidgets 函式可讓您定義小工具測試,並建立一個 WidgetTester 來使用。

此測試會驗證 MyWidget 是否顯示指定的標題和訊息。它會據此命名,並將在下一節中填入內容。

dart
void main() {
  // Define a test. The TestWidgets function also provides a WidgetTester
  // to work with. The WidgetTester allows you to build and interact
  // with widgets in the test environment.
  testWidgets('MyWidget has a title and message', (tester) async {
    // Test code goes here.
  });
}

4. 使用 WidgetTester 建構小工具

#

接下來,使用 WidgetTester 提供的 pumpWidget() 方法,在測試環境中建構 MyWidgetpumpWidget 方法會建構並呈現提供的小工具。

建立一個 MyWidget 執行個體,以顯示「T」作為標題,「M」作為訊息。

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    // Create the widget by telling the tester to build it.
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
  });
}

關於 pump() 方法的注意事項

#

在第一次呼叫 pumpWidget() 之後,WidgetTester 會提供其他方法來重建相同的小工具。如果您使用 StatefulWidget 或動畫,這會很有用。

例如,點擊按鈕會呼叫 setState(),但 Flutter 不會在測試環境中自動重建您的小工具。請使用下列其中一個方法,要求 Flutter 重建小工具。

tester.pump(Duration duration)
排程影格並觸發小工具的重建。如果指定了 Duration,它會將時鐘向前推進該量,並排程影格。即使持續時間長於單一影格,它也不會排程多個影格。
tester.pumpAndSettle()
使用指定的持續時間重複呼叫 pump(),直到沒有排程的影格為止。這實質上會等待所有動畫完成。

這些方法可對建構生命週期進行精細控制,這在測試時特別有用。

5. 使用 Finder 搜尋我們的小工具

#

在測試環境中有小工具時,使用 Finder 搜尋小工具樹狀結構中的 titlemessage 文字小工具。這樣可以驗證小工具是否正確顯示。

為此,請使用 flutter_test 套件提供的最上層 find() 方法來建立 Finders。由於您知道您要尋找 Text 小工具,請使用 find.text() 方法。

如需 Finder 類別的詳細資訊,請參閱在小工具測試中尋找小工具範例。

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));

    // Create the Finders.
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');
  });
}

6. 使用 Matcher 驗證小工具

#

最後,使用 flutter_test 提供的 Matcher 常數驗證標題和訊息 Text 小工具是否顯示在螢幕上。Matcher 類別是 test 套件的核心部分,提供一種驗證指定值是否符合期望的常用方法。

請務必確保小工具在螢幕上僅出現一次。為此,請使用 findsOneWidget Matcher

dart
void main() {
  testWidgets('MyWidget has a title and message', (tester) async {
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');

    // Use the `findsOneWidget` matcher provided by flutter_test to verify
    // that the Text widgets appear exactly once in the widget tree.
    expect(titleFinder, findsOneWidget);
    expect(messageFinder, findsOneWidget);
  });
}

其他 Matcher

#

除了 findsOneWidget 之外,flutter_test 還針對常見案例提供其他匹配器。

findsNothing
驗證找不到任何小工具。
findsWidgets
驗證找到一個或多個小工具。
findsNWidgets
驗證找到特定數目的小工具。
matchesGoldenFile
驗證小工具的彩現是否與特定的點陣圖影像(「黃金檔案」測試)相符。

完整範例

#
dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  // Define a test. The TestWidgets function also provides a WidgetTester
  // to work with. The WidgetTester allows building and interacting
  // with widgets in the test environment.
  testWidgets('MyWidget has a title and message', (tester) async {
    // Create the widget by telling the tester to build it.
    await tester.pumpWidget(const MyWidget(title: 'T', message: 'M'));

    // Create the Finders.
    final titleFinder = find.text('T');
    final messageFinder = find.text('M');

    // Use the `findsOneWidget` matcher provided by flutter_test to
    // verify that the Text widgets appear exactly once in the widget tree.
    expect(titleFinder, findsOneWidget);
    expect(messageFinder, findsOneWidget);
  });
}

class MyWidget extends StatelessWidget {
  const MyWidget({
    super.key,
    required this.title,
    required this.message,
  });

  final String title;
  final String message;

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