Flutter測試(二):在項目中進行 Widget 測試

上回書對 Flutter 中 Widget 測試的官方 Demo 進行了簡單的講解,這篇文章咱們對本身的項目進行 Widget 測試。less

就拿 「想吃啥」APP 來進行測試吧。async

在首頁中,咱們能夠看到有 6 個 Widget,有:ide

  1. 葷菜 & 素菜:
  2. 選個菜吧 ×2
  3. Button ×2

由於平時咱們寫APP的時候,確定會封裝一些 Widget 來進行復用,因此首頁中 選個菜吧 & Button 都被我封裝成了一個 Widget。測試

下面咱們就先針對這兩個 Widget 進行測試。ui

選個菜吧

首先咱們也是根據步驟來,先編寫 Widget,而後編寫 Widget 測試。(說得好像是廢話🌝)this

編寫Widget

其中 「選個菜吧」是封裝了一個 Row,裏面包含了一個 Text & IconButton ,具體代碼以下:spa

class MenuWidget extends StatelessWidget {

  final Stream stream;
  final VoidCallback callback;
  
  MenuWidget(this.stream, this.callback);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        StreamBuilder(
          stream: stream,
          initialData: "選個菜吧",
          builder: (context, snapshot) {
            return Text(
              snapshot.data,
              style: TextStyle(fontSize: 34, color: Colors.black87),
            );
          },
        ),
        IconButton(
          icon: Icon(Icons.refresh),
          onPressed: callback,
        ),
      ],
    );
  }
}

複製代碼

參數有兩個:code

  1. Stream:用於 StreamBuilder 的 stream 參數,在本APP中是用來隨機菜單
  2. VoidCallback:用於 IconButton 的點擊事件

這樣咱們就封裝成了一個 Widget,能夠在編寫 UI 的時候複用了,那既然寫完了 Widget,下面就要對他進行測試了。cdn

編寫 Widget 測試

在編寫測試代碼以前,咱們要明確該 Widget 的做用。(因爲我是在寫文章,可能不少人沒仔細看前面的代碼,因此這裏仍是解釋一下該 Widget的邏輯):blog

  1. 該 Widget 是由兩個 Widget 組合而成。一個是 Text, 一個是 IconButton。
  2. Text 用來展現菜譜。
  3. IconButton 用來點擊調用隨機菜譜的方法。

因此咱們在寫測試的時候,也應該按照上述的邏輯來寫,我寫的測試代碼以下:

void main() {
  testWidgets('MenuWidget test', (WidgetTester tester) async {
    StreamController<String> _controller = StreamController();
    try {
      await tester.pumpWidget(MaterialApp(
        home: Material(
          child: MenuWidget(
            _controller.stream, 
                () => _controller.sink.add("111"),
          ),
        ),
      ));
      expect(find.text('選個菜吧'), findsOneWidget);

      await tester.tap(find.byIcon(Icons.refresh));
      await tester.pump();
      expect(find.text('111'), findsOneWidget);

      
    } finally {
      _controller.close();
    }
  });
}
複製代碼

上述邏輯大體以下:

  1. 建立測試的 Widget,也就是咱們的 MenuWidget,其中須要兩個參數,一個是 stream,一個是 VoidCallback
  2. 因爲 Stream 必需要 close,因此套了一層異常捕獲,在 finally 中釋放 stream。
  3. 定義好 Widget 後,查找,是否有「選個菜吧」 的Widget。
  4. 若是有的話,則點擊一個 Icon 爲 Icons.refresh 的按鈕。
  5. 而後刷新頁面
  6. 查找是否有文字爲「111」的 Widget。

運行測試代碼,結果以下:

能夠看到確實是經過了,那就證實,咱們組合的這個 Widget 不存在邏輯的問題,也就是該 Widget 可用。

Button

在開發中,對於 Button 樣式的一致性你們確定是有了解的,那既然如此,就要封裝好一個通用的Button。

編寫Widget

一個 Button 須要的參數無非也就兩個:

  1. Button 上顯示的文案
  2. Button 點擊回調

代碼以下:

class CommonButton extends StatelessWidget {
  
  final String text;
  final VoidCallback callback;

  CommonButton(this.text, this.callback);

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.all(Radius.circular(10))),
      color: Theme.of(context).accentColor,
      textColor: Colors.white,
      padding: EdgeInsets.symmetric(horizontal: 50, vertical: 10),
      onPressed: callback,
      child: Text(
        text,
        style: TextStyle(fontSize: 18),
      ),
    );
  }
}
複製代碼

這裏封裝的 Button 就是一個 RaisedButton,用了圓角,設定了文字的大小,這樣就封裝好了。

下面就寫該 Button 的測試。

編寫 Widget 測試

Button 的測試邏輯仍是很是簡單的,咱們只須要判斷:

  1. 文字是否正常顯示
  2. 點擊回調是否走得通

以上兩個條件就 ok 了。

測試代碼以下:

testWidgets('CommonButton test', (WidgetTester tester) async {
  bool flag = false;
  await tester.pumpWidget(MaterialApp(
    home: Material(
      child: CommonButton(
        '我是CommonButton',
        () => flag = true,
      ),
    ),
  ));
  expect(find.text('我是CommonButton'), findsOneWidget);
  expect(flag, isFalse);
  await tester.tap(find.byType(CommonButton));
  expect(flag, isTrue);
});
複製代碼

上述代碼邏輯爲:

  1. 定義一個 flag,用來測試 Button 的點擊回調
  2. 建立 Widget,定義好參數
  3. 判斷 Button 的文案是否正常顯示
  4. 判斷 flag 是否爲開始定義的值
  5. 點擊該 Button
  6. 判斷 flag 是否已經更改

運行結果以下:

能夠看到上述有兩個 test 都完成了。

總結

在 Flutter 中,一切皆爲 Widget。

相信各位學 Flutter 的也都知道這個概念,那就能夠看得出來,Widget 測試是 Flutter 中最重要的測試。

一個好的程序,測試覆蓋率應該也要很高。

相關文章
相關標籤/搜索