上回書對 Flutter 中 Widget 測試的官方 Demo 進行了簡單的講解,這篇文章咱們對本身的項目進行 Widget 測試。less
就拿 「想吃啥」APP 來進行測試吧。async
在首頁中,咱們能夠看到有 6 個 Widget,有:ide
由於平時咱們寫APP的時候,確定會封裝一些 Widget 來進行復用,因此首頁中 選個菜吧 & Button 都被我封裝成了一個 Widget。測試
下面咱們就先針對這兩個 Widget 進行測試。ui
首先咱們也是根據步驟來,先編寫 Widget,而後編寫 Widget 測試。(說得好像是廢話🌝)this
其中 「選個菜吧」是封裝了一個 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
StreamBuilder
的 stream 參數,在本APP中是用來隨機菜單IconButton
的點擊事件這樣咱們就封裝成了一個 Widget,能夠在編寫 UI 的時候複用了,那既然寫完了 Widget,下面就要對他進行測試了。cdn
在編寫測試代碼以前,咱們要明確該 Widget 的做用。(因爲我是在寫文章,可能不少人沒仔細看前面的代碼,因此這裏仍是解釋一下該 Widget的邏輯):blog
因此咱們在寫測試的時候,也應該按照上述的邏輯來寫,我寫的測試代碼以下:
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();
}
});
}
複製代碼
上述邏輯大體以下:
MenuWidget
,其中須要兩個參數,一個是 stream,一個是 VoidCallback
。finally
中釋放 stream。Icons.refresh
的按鈕。運行測試代碼,結果以下:
能夠看到確實是經過了,那就證實,咱們組合的這個 Widget 不存在邏輯的問題,也就是該 Widget 可用。
在開發中,對於 Button
樣式的一致性你們確定是有了解的,那既然如此,就要封裝好一個通用的Button。
一個 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 的測試。
Button 的測試邏輯仍是很是簡單的,咱們只須要判斷:
以上兩個條件就 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);
});
複製代碼
上述代碼邏輯爲:
運行結果以下:
能夠看到上述有兩個 test 都完成了。
在 Flutter 中,一切皆爲 Widget。
相信各位學 Flutter 的也都知道這個概念,那就能夠看得出來,Widget 測試是 Flutter 中最重要的測試。
一個好的程序,測試覆蓋率應該也要很高。