Flutter 測(cè)試應(yīng)用

2020-08-27 14:48 更新

介紹

應(yīng)用的功能越多,手動(dòng)測(cè)試的難度就越大。一套完整的自動(dòng)化測(cè)試將幫助您確保您的應(yīng)用在發(fā)布之前正確執(zhí)行,同時(shí)保留您的功能和錯(cuò)誤修復(fù)速度。

有很多種自動(dòng)化測(cè)試。這些總結(jié)如下:

  • 單元測(cè)試:測(cè)試單一功能、方法或類。例如,被測(cè)單元的外部依賴性通常被模擬出來,如package:mockito。 單元測(cè)試通常不會(huì)讀取/寫入磁盤、渲染到屏幕,也不會(huì)從運(yùn)行測(cè)試的進(jìn)程外部接收用戶操作。單元測(cè)試的目標(biāo)是在各種條件下驗(yàn)證邏輯單元的正確性。
  • widget 測(cè)試:(在其它UI框架稱為 組件測(cè)試) 測(cè)試的單個(gè)widget。測(cè)試widget涉及多個(gè)類,并且需要提供適當(dāng)?shù)膚idget生命周期上下文的測(cè)試環(huán)境。 例如,它應(yīng)該能夠接收和響應(yīng)用戶操作和事件,執(zhí)行布局并實(shí)例化子widget。widget測(cè)試因此比單元測(cè)試更全面。 然而,就像一個(gè)單元測(cè)試一樣,一個(gè)widget測(cè)試的環(huán)境被一個(gè)比完整的UI系統(tǒng)簡(jiǎn)單得多的實(shí)現(xiàn)所取代。小部件測(cè)試的目標(biāo)是驗(yàn)證小部件的UI如預(yù)期的那樣的外觀和交互。
  • 集成測(cè)試: 測(cè)試一個(gè)完整的應(yīng)用程序或應(yīng)用程序的很大一部分。通常,集成測(cè)試可以在真實(shí)設(shè)備或OS仿真器上運(yùn)行,例如iOS Simulator或Android Emulator。 被測(cè)試的應(yīng)用程序通常與測(cè)試驅(qū)動(dòng)程序代碼隔離,以避免結(jié)果偏差。集成測(cè)試的目標(biāo)是驗(yàn)證應(yīng)用程序作為一個(gè)整體正確運(yùn)行,它所組成的所有widget如預(yù)期的那樣相互集成。 您還可以使用集成測(cè)試來驗(yàn)證應(yīng)用的性能。

這里是一個(gè)表格,總結(jié)了在不同類型測(cè)試之間進(jìn)行選擇的權(quán)衡:

 單元測(cè)試widget測(cè)試集成測(cè)試
ConfidenceLowHigherHighest
維護(hù)成本LowHigherHighest
依賴FewMoreLots
執(zhí)行速度QuickSlowerSlowest
    

提示: 作為一個(gè)經(jīng)驗(yàn)法則,經(jīng)過充分測(cè)試的應(yīng)用程序具有非常多的單元和widget測(cè)試,通過代碼覆蓋(code coverage)進(jìn)行跟蹤,以及覆蓋所有重要使用場(chǎng)景的大量集成測(cè)試。


單元測(cè)試

某些Flutter庫,如dart:ui在獨(dú)立的Dart VM附帶的Dart SDK的中是不可用。該flutter test命令允許您在本地Dart VM中運(yùn)行測(cè)試,使用無頭版(不會(huì)顯示UI)的Flutter引擎。 使用這個(gè)命令你可以運(yùn)行任何測(cè)試,不管它是否依賴于Flutter的庫。

使用package:test,編寫一個(gè)Flutter單元測(cè)試。編寫單元測(cè)試使用的package:test文檔在這里。

例如:

將此文件添加到 test/unit_test.dart:

import 'package:test/test.dart';

void main() {
  test('my first unit test', () {
    var answer = 42;
    expect(answer, 42);
  });
}

另外,您必須將以下內(nèi)容添加到您的pubspec.yaml:

dev_dependencies:
  flutter_test:
    sdk: flutter

即使你的測(cè)試本身沒有明確導(dǎo)入flutter_test,也需要這樣做 ,因?yàn)闇y(cè)試框架本身在后臺(tái)也使用了它。

要運(yùn)行測(cè)試,從您的項(xiàng)目目錄(而不是從test子目錄)運(yùn)行 flutter test test/unit_test.dart

要運(yùn)行所有測(cè)試,請(qǐng)從項(xiàng)目目錄運(yùn)行flutter test


Widget 測(cè)試

您以類似于單元測(cè)試的方式實(shí)現(xiàn)widget測(cè)試。要在測(cè)試中執(zhí)行與widget的交互,請(qǐng)使用Flutter提供的WidgetTester。 例如,您可以發(fā)送點(diǎn)擊和滾動(dòng)手勢(shì)。您還可以使用WidgetTester在widget樹中查找子widget、讀取文本、驗(yàn)證widget屬性的值是否正確。

例子:

將此文件添加到test/widget_test.dart:

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

void main() {
  testWidgets('my first widget test', (WidgetTester tester) async {
    // You can use keys to locate the widget you need to test
    var sliderKey = new UniqueKey();
    var value = 0.0;

    // Tells the tester to build a UI based on the widget tree passed to it
    await tester.pumpWidget(
      new StatefulBuilder(
        builder: (BuildContext context, StateSetter setState) {
          return new MaterialApp(
            home: new Material(
              child: new Center(
                child: new Slider(
                  key: sliderKey,
                  value: value,
                  onChanged: (double newValue) {
                    setState(() {
                      value = newValue;
                    });
                  },
                ),
              ),
            ),
          );
        },
      ),
    );
    expect(value, equals(0.0));

    // Taps on the widget found by key
    await tester.tap(find.byKey(sliderKey));

    // Verifies that the widget updated the value correctly
    expect(value, equals(0.5));
  });
}

運(yùn)行 flutter test test/widget_test.dart.

查看所有可用于widget測(cè)試的package:flutter_test API

為了幫助調(diào)試widget測(cè)試,您可以使用debugDumpApp() 函數(shù)來可視化測(cè)試的UI狀態(tài), 或者只是簡(jiǎn)單的在您的首選運(yùn)行時(shí)環(huán)境(例如模擬器或設(shè)備)中運(yùn)行flutter run test/widget_test.dart以查看您的測(cè)試運(yùn)行。 在運(yùn)行flutter run的測(cè)試的會(huì)話期間,您還可以交互式地點(diǎn)擊Flutter工具的部分屏幕來打印建議的Finder。


集成測(cè)試

如果您熟悉Selenium/WebDriver(web),Espresso(Android)或UI Automation(iOS),那么Flutter Driver就是Flutter與這些集成測(cè)試工具的等價(jià)物。 此外,F(xiàn)lutter Driver還提供API以記錄測(cè)試執(zhí)行的操作的性能跟蹤(又名時(shí)間軸)。

Flutter的Driver是:

  • 一個(gè)命令行工具 flutter drive
  • 一個(gè)包 package:flutter_driver (API)

這兩者允許你:

  • 為集成測(cè)試創(chuàng)建指令化的應(yīng)用程序
  • 寫一個(gè)測(cè)試
  • 運(yùn)行測(cè)試

添加flutter_driver依賴項(xiàng)

要使用flutter_driver,您必須將以下塊添加到您的pubspec.yaml:

dev_dependencies:
  flutter_driver:
    sdk: flutter

創(chuàng)建指令化的Flutter應(yīng)用程序

一個(gè)指令化的應(yīng)用程序是一個(gè)Flutter應(yīng)用程序,它啟用了Flutter Driver 擴(kuò)展。啟用擴(kuò)展請(qǐng)調(diào)用enableFlutterDriverExtension()。

例:

假設(shè)你有一個(gè)入口點(diǎn)的應(yīng)用程序my_app/lib/main.dart。要?jiǎng)?chuàng)建它的指令化版本,請(qǐng)?jiān)趍y_app/test_driver/下創(chuàng)建一個(gè)Dart文件。 在您正在測(cè)試的功能之后命名它; 接下來定位到my_app/test_driver/user_list_scrolling.dart:

// 這一行導(dǎo)入擴(kuò)展
import 'package:flutter_driver/driver_extension.dart';

void main() {
  // 啟用擴(kuò)展
  enableFlutterDriverExtension();

  // Call the `main()` of your app or call `runApp` with whatever widget
  // you are interested in testing.
}

編寫集成測(cè)試

集成測(cè)試是一個(gè)簡(jiǎn)單的package:test測(cè)試,它使用Flutter Driver API告訴應(yīng)用程序執(zhí)行什么操作,然后驗(yàn)證應(yīng)用程序是否執(zhí)行了此操作。

例子:

為了有意思起見,我們也讓我們的測(cè)試記錄下性能跟蹤(performance timeline)。我們創(chuàng)建一個(gè)user_list_scrolling_test.dart測(cè)試文件位于my_app/test_driver/下:

import 'dart:async';

// Imports the Flutter Driver API
import 'package:flutter_driver/flutter_driver.dart';
import 'package:test/test.dart';

void main() {
  group('scrolling performance test', () {
    FlutterDriver driver;

    setUpAll(() async {
      // 連接app
      driver = await FlutterDriver.connect();
    });

    tearDownAll(() async {
      if (driver != null) {
        // 關(guān)閉連接
        driver.close();
      }
    });

    test('measure', () async {
      // 記錄閉包中的performance timeline
      Timeline timeline = await driver.traceAction(() async {
        // Find the scrollable user list
        SerializableFinder userList = find.byValueKey('user-list');

        // Scroll down 5 times
        for (int i = 0; i < 5; i++) {
          // Scroll 300 pixels down, for 300 millis
          await driver.scroll(
              userList, 0.0, -300.0, new Duration(milliseconds: 300));

          // Emulate a user's finger taking its time to go back to the original
          // position before the next scroll
          await new Future<Null>.delayed(new Duration(milliseconds: 500));
        }

        // Scroll up 5 times
        for (int i = 0; i < 5; i++) {
          await driver.scroll(
              userList, 0.0, 300.0, new Duration(milliseconds: 300));
          await new Future<Null>.delayed(new Duration(milliseconds: 500));
        }
      });

      // The `timeline` object contains all the performance data recorded during
      // the scrolling session. It can be digested into a handful of useful
      // aggregate numbers, such as "average frame build time".
      TimelineSummary summary = new TimelineSummary.summarize(timeline);
      summary.writeSummaryToFile('stocks_scroll_perf', pretty: true);
      summary.writeTimelineToFile('stocks_scroll_perf', pretty: true);
    });
  });
}

運(yùn)行集成測(cè)試

要在Android設(shè)備上運(yùn)行測(cè)試,請(qǐng)通過USB將設(shè)備連接到計(jì)算機(jī)并啟用USB調(diào)試。然后運(yùn)行以下命令:

flutter drive --target=my_app/test_driver/user_list_scrolling.dart

該命令將:

  • 構(gòu)建 --target 應(yīng)用,并將其安裝在設(shè)備上
  • 啟動(dòng)應(yīng)用
  • 運(yùn)行my_app/test_driver/下的user_list_scrolling_test.dart

您可能想知道該命令如何找到正確的測(cè)試文件。flutter drive 命令使用一種約定來查找與--target應(yīng)用程序在同一目錄中具有相同文件名但是具有_test后綴的測(cè)試文件。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)