整合測試介紹

Unit tests 和 Widget tests 在測試獨立的類、函式或者元件時非常方便。然而,它們並不能夠測試單獨的模組形成的整體或者獲取真實裝置上應用執行狀態。這些任務需要整合測試 (integration tests) 來處理。

整合測試由 SDK 直接提供支援,使用 integration_test 這個 package 實現。

在這個章節中,我們將會學習如何去測試一個計數器應用,包括如何設定整合測試、如何驗證指定文字能否在應用內正常顯示、如何模擬點選指定元件和如何執行整合測試。

本教程將包含以下步驟:

  1. 建立一個應用用於測試。

  2. 新增 integration_test 依賴。

  3. 建立測試檔案。

  4. 編寫整合測試。

  5. 執行整合測試。

1. 建立一個應用用於測試

首先,我們需要建立一個應用用於測試。在這個範例中,我們將會測試一個由 flutter create 指令建立的計數器應用。這個應用允許使用者點選按鈕增加計數。

import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: 'Counter App',
      home: MyHomePage(title: 'Counter App Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        // Provide a Key to this button. This allows finding this
        // specific button inside the test suite, and tapping it.
        key: const Key('increment'),
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ),
    );
  }
}

2. 新增 integration_test 依賴

接著,我們需要用到 integration_testflutter_test package 來編寫整合測試,把依賴新增到應用pubspec.yaml 檔案的 dev_dependencies 區域。

$ flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'  'dev:integration_test:{"sdk":"flutter"}'
"flutter_test" is already in "dev_dependencies". Will try to update the constraint.
Resolving dependencies... 
  collection 1.17.2 (1.18.0 available)
+ file 6.1.4 (7.0.0 available)
+ flutter_driver 0.0.0 from sdk flutter
+ fuchsia_remote_debug_protocol 0.0.0 from sdk flutter
+ integration_test 0.0.0 from sdk flutter
  material_color_utilities 0.5.0 (0.8.0 available)
  meta 1.9.1 (1.10.0 available)
+ platform 3.1.0 (3.1.2 available)
+ process 4.2.4 (5.0.0 available)
  stack_trace 1.11.0 (1.11.1 available)
  stream_channel 2.1.1 (2.1.2 available)
+ sync_http 0.3.1
  test_api 0.6.0 (0.6.1 available)
+ vm_service 11.7.1 (11.10.0 available)
+ webdriver 3.0.2
Changed 9 dependencies!

3. 建立測試檔案

建立一個名為 integration_test 的新檔案夾,並在資料夾中建立一個空的 app_test.dart 檔案:

counter_app/
  lib/
    main.dart
  integration_test/
    app_test.dart

4. 編寫整合測試檔案

現在我們可以來寫測試檔案了,步驟如下列三項:

  1. 初始化一個單例 IntegrationTestWidgetsFlutterBinding,這將用於在物理裝置上執行測試;

  2. 使用 WidgetTester 類測試並與 widget 發生互動;

  3. 測試重要的應用場景。

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

void main() {
  IntegrationTestWidgetsFlutterBinding.ensureInitialized();

  group('end-to-end test', () {
    testWidgets('tap on the floating action button, verify counter',
        (tester) async {
      // Load app widget.
      await tester.pumpWidget(const MyApp());

      // Verify the counter starts at 0.
      expect(find.text('0'), findsOneWidget);

      // Finds the floating action button to tap on.
      final fab = find.byKey(const Key('increment'));

      // Emulate a tap on the floating action button.
      await tester.tap(fab);

      // Trigger a frame.
      await tester.pumpAndSettle();

      // Verify the counter increments by 1.
      expect(find.text('1'), findsOneWidget);
    });
  });
}

5. 執行整合測試

整合測試的執行情況會根據需要進行測試的平台不同而不盡相同,你可以針對行動平台或者 Web 平台進行測試。

5a. 行動平台

在 iOS 或 Android 平台進行真機測試的時候,首先需要連線裝置並在工程的根目錄執行下面的指令:

$ flutter test integration_test/app_test.dart

或者你可以在指定目錄下執行所有的整合測試:

$ flutter test integration_test

這個指令可以在目標裝置上執行應用並執行整合測試,更多相關訊息,請參閱文件:整合測試 頁面。

5b. Web 平台

在網頁瀏覽器裡開始進行整合測試,首先要下載 ChromeDriver

接下來,新建一個資料夾,命名為 test_driver,幷包含一個新的檔案,命名為 integration_test.dart

import 'package:integration_test/integration_test_driver.dart';

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

執行 chromedriver,執行如下指令:

$ chromedriver --port=4444

在工程的根目錄下,執行如下指令:

$ flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=integration_test/app_test.dart \
  -d chrome

如需 Headless 測試體驗,你同樣可以執行 flutter drive 指令,並加入 web-server 作為目標裝置,參考如下指令:

flutter drive \
  --driver=test_driver/integration_test.dart \
  --target=integration_test/app_test.dart \
  -d web-server