翻譯首頁bash
在單元測試的介紹裏,咱們學習到了如何使用test
包測試Dart類,爲了測試Widget類,咱們須要一些由flutter test
包提供的額外工具,這些工具隨Flutter SDK發佈。app
這個flutter_test
包提供瞭如下用於測試Widget的工具:less
testWidgets
函數。這個函數將自動對每一個測試用例建立一個WidgetTester
,並用於替代普通的test
函數。若是上面的內容聽不懂的話,不要緊,讓咱們經過一些例子來將上面的碎片信息串聯到一塊兒。async
步驟:ide
flutter_test
依賴。WidgetTester
build一個WidgetFinder
搜索咱們的Widget。Matcher
驗證咱們的Widget是否工做正常。flutter_test
依賴。在咱們開始寫測試以前,咱們須要在pubspec.yaml
文件的dev_dependencies
行下面添加flutter_test
包。若是你經過命令行或者編譯器建立的Flutter項目,那麼該依賴已經添加好了。函數
dev_dependencies:
flutter_test:
sdk: flutter
複製代碼
下一步,咱們須要建立一個能讓咱們測試的Widget。在這個例子裏,咱們建立了顯示一個標題和一條信息的Widget。工具
class MyWidget extends StatelessWidget {
final String title;
final String message;
const MyWidget({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
),
);
}
}
複製代碼
如今咱們有了一個能夠用來測試的Widget,咱們能夠編寫咱們第一個測試用例了!咱們將會使用flutter_test
包提供的testWidgets
函數完成一個測試用例。這個testWidgets
函數將會容許咱們定義一個Widget測試用例並建立一個WidgetTester
給咱們使用。post
咱們的測試將會驗證MyWidget
類是否正常顯示給定的標題和信息。單元測試
void main() {
// Define a test. The TestWidgets function will also provide a WidgetTester
// for us to work with. The WidgetTester will allow us to build and interact
// with Widgets in the test environment.
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Test code will go here!
});
}
複製代碼
WidgetTester
build一個Widget下一步,咱們將會在測試環境裏build咱們的MyWidget
類。爲了這麼作,咱們將使用WidgetTester
提供的pumpWidget
方法。這個pumpWidget
方法將會build和渲染咱們提供的Widget。學習
在這個示例裏,咱們將會建立一個顯示標題「T」和消息「M」的MyWidget
實例。
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Create the Widget tell the tester to build it
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
});
}
複製代碼
備註: 第一次調用pumpWidget
以後,WidgetTester
提供了從新建立相同Widget的其餘方式。若是你使用StatefulWidget
或者動畫,這將會很是有用。
例如,若是咱們點擊一個按鈕,而且這個按鈕調用了setState
方法,Flutter不會在測試環境裏rebuild你的Widget。咱們須要使用下面的方法之一來告訴Flutter再一次build咱們的Widget。
tester.pump()
在一個給定的時間之後rebuild你的Widget。
tester.pumpAndSettle()
在給定的時間不斷重複調用
pump
方法直到再也不有任何繪製任務。通常用於等待全部動畫完成。
這些方法提供了比build生命週期更細粒度的控制,這在測試的時候特別有用。
Finder
搜索咱們的Widget。如今咱們已經在測試環境構建了咱們的Widget,咱們想要經過使用Finder
在Widget樹裏搜索咱們的title
和message
Widget。這將容許咱們驗證是否正確顯示了那些Widget!
在這個例子裏,咱們將會使用flutter_test
包提供的頂級find
方法去建立咱們的Finder
類。由於咱們知道咱們在尋找Text widget,因此咱們可使用find.text
方法。 有關Finder
類的更多信息,請查看在Widget測試裏查找Widget。
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
// Create our Finders
final titleFinder = find.text('T');
final messageFinder = find.text('M');
});
}
複製代碼
Matcher
驗證咱們的Widget是否工做正常。最後,咱們可使用flutter_test
包提供的Matcher
常量來驗證title和message Text Widgets是否出如今屏幕。 Matcher
類是test
包的核心部分,而且提供了通用的方式去驗證給定的值是否符合咱們的指望。
在這個例子裏,咱們想要咱們的Widgets只在屏幕出現一次。所以,咱們可使用findsOneWidget
這個Matcher
。
void main() {
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
await tester.pumpWidget(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 our
// Text Widgets appear exactly once in the Widget tree
expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}
複製代碼
額外的Matcher
: 在findsOneWidget
之外,flutter_test
爲常見用例提供了額外的Matcher
:
驗證沒有Widget被找到。
驗證一個或者多個Widget被找到。
驗證指定數量的Widget被找到。
完整示例:
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
// Define a test. The TestWidgets function will also provide a WidgetTester
// for us to work with. The WidgetTester will allow us to build and interact
// with Widgets in the test environment.
testWidgets('MyWidget has a title and message', (WidgetTester tester) async {
// Create the Widget tell the tester to build it
await tester.pumpWidget(MyWidget(title: 'T', message: 'M'));
// Create our Finders
final titleFinder = find.text('T');
final messageFinder = find.text('M');
// Use the `findsOneWidget` matcher provided by flutter_test to verify our
// Text Widgets appear exactly once in the Widget tree
expect(titleFinder, findsOneWidget);
expect(messageFinder, findsOneWidget);
});
}
class MyWidget extends StatelessWidget {
final String title;
final String message;
const MyWidget({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
),
);
}
}
複製代碼