單元測試簡介 教學中, 你已經學會如何使用 test 套件來測試 Dart 類別。 若要測試元件(Widget)類別,你還需要一些由 flutter_test 套件(隨 Flutter SDK 一同提供)所提供的額外工具。

flutter_test 套件為元件(Widget)測試提供了以下工具:

  • [WidgetTester][WidgetTester] 可在測試環境中建立並互動操作元件(Widget)。
  • testWidgets() 函式會自動為每個測試案例建立新的 WidgetTester, 並取代一般的 test() 函式使用。
  • Finder 類別可用於在測試環境中搜尋元件(Widget)。
  • 元件專用的 Matcher 常數有助於驗證 Finder 是否能在測試環境中定位到一個或多個元件(Widget)。

如果你覺得這些內容有些複雜,別擔心。你將會在本教學中學會這些工具如何整合運作,步驟如下:

  1. 新增 flutter_test 相依套件。
  2. 建立要測試的元件(Widget)。
  3. 建立 testWidgets 測試。
  4. 使用 WidgetTester 建立元件(Widget)。
  5. 使用 Finder 搜尋元件(Widget)。
  6. 使用 Matcher 驗證元件(Widget)。

1. 新增 flutter_test 相依套件

#

在撰寫測試之前,請在 pubspec.yaml 檔案的 dev_dependencies 區段中 加入 flutter_test 相依套件。 如果你是透過命令列工具或程式碼編輯器建立新的 Flutter 專案,這個相依套件應該已經自動加入。

yaml
dev_dependencies:
  flutter_test:
    sdk: flutter

2. 建立要測試的元件(Widget)

#

接下來,建立一個用於測試的元件。針對本教學範例, 請建立一個會顯示 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測試

#

有了要測試的元件(Widget)後,首先可以撰寫你的第一個測試。 使用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 建立元件(Widget)

#

接下來,請利用 WidgetTester 所提供的 pumpWidget() 方法,在測試環境中建立 MyWidgetpumpWidget 方法會建立並渲染所提供的元件(Widget)。

建立一個 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 提供了額外的方法來重新建構同一個元件(Widget)。這在你處理 StatefulWidget 或動畫(Animation)時特別有用。

例如,點擊按鈕會呼叫 setState(),但在測試環境中 Flutter 不會自動重新建構你的元件。你可以使用以下其中一種方法,要求 Flutter 重新建構元件。

tester.pump(Duration duration)
排程一個 frame 並觸發元件的重新建構。如果有指定 Duration,則會將時鐘推進該段時間並排程一個 frame。即使 duration 超過單一 frame 的長度,也不會排程多個 frame。
tester.pumpAndSettle()
會以指定的 duration 重複呼叫 pump(),直到沒有任何 frame 被排程。基本上,這會等待所有動畫(Animation)完成。

這些方法讓你能夠細緻地控制建構生命週期,在測試時特別實用。

5. 使用 Finder 搜尋我們的元件(Widget)

#

將元件放入測試環境後,可以透過元件樹搜尋 titlemessage 文字元件(Text Widgets),方法是使用 Finder。這可以驗證元件是否正確顯示。

為此,請使用 flutter_test 套件提供的頂層 [find()][find()] 方法來建立 Finders。由於你知道要找的是 Text 元件(Widgets),因此可以使用 find.text() 方法。

如需關於 Finder 類別的更多資訊,請參閱 Finding widgets in a widget test 教學。

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 驗證元件(Widget)

#

最後,請使用 Matcher 常數(由 flutter_test 提供)來驗證標題與訊息 Text 元件(Widgets)是否出現在螢幕上。
Matcher 類別是 test 套件的核心組成部分,並提供一種通用方式來驗證指定的值是否符合預期。

請確保這些元件(Widgets)在螢幕上僅出現一次
為此,請使用 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);
  });
}

其他比對器(Matchers)

#

除了 findsOneWidget 之外,flutter_test 還提供了其他常見情境下可用的比對器(matchers)。

findsNothing
驗證沒有找到任何元件(Widgets)。
findsWidgets
驗證至少找到一個元件(Widgets)。
findsNWidgets
驗證找到特定數量的元件(Widgets)。
matchesGoldenFile
驗證元件(Widget)的渲染結果是否與特定的點陣圖圖片(即「golden file」測試)相符。

完整範例

#
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)),
      ),
    );
  }
}

(https://docs.flutter.dev/testing) [find()]: https://api.flutter.dev/flutter/flutter_test/find-constant.html

Widget 測試簡介

在開發 Flutter 應用程式時,撰寫測試可以幫助你確保元件(Widget)如預期般運作,並且在未來修改程式碼時,能夠快速發現潛在問題。

Flutter 提供了多種測試類型,包括單元測試、元件(Widget)測試,以及整合測試。本章將重點介紹元件(Widget)測試,這類測試可以驗證單一元件或多個元件之間的互動。

元件(Widget)測試(有時也稱為元件測試)介於單元測試和整合測試之間。它們比單元測試更全面,因為可以驗證多個元件之間的互動;但又比整合測試更輕量,因為它們只會測試應用程式中的一小部分。

在元件(Widget)測試中,你可以模擬使用者與元件互動,例如點擊按鈕、輸入文字,並檢查畫面上的變化是否正確。

這些測試會在虛擬環境(不需實際裝置或模擬器)中執行,因此速度非常快,適合在開發過程中頻繁執行。

要撰寫元件(Widget)測試,請使用 Flutter 的 flutter_test 套件。該套件提供了許多工具和 API,協助你建立和驗證元件(Widget)。

以下章節將介紹如何建立基本的元件(Widget)測試,包括:

  • 建立測試檔案
  • 使用 WidgetTester 操作元件(Widget)
  • 驗證元件(Widget)的狀態與外觀

你將學會如何:

  • 測試元件(Widget)是否正確顯示
  • 模擬使用者互動
  • 驗證狀態變化

這些技巧將幫助你撰寫更可靠且可維護的 Flutter 應用程式。

提示:除了元件(Widget)測試外,請考慮也撰寫單元測試與整合測試,以全面覆蓋你的應用程式。

更多元件(Widget)測試的詳細資訊,請參考 Flutter 官方文件

接下來,讓我們開始撰寫第一個元件(Widget)測試。