上禮拜介紹了一個Widget Test所包含的流程,過程中用到Finder、Tester、和Matcher的部分方法...等,但是實際上這些元件都還有許多不同的操作,今天先介紹Finder的各種方法。
find的方法們
- text:找到一個顯示特定字串的Text Widget dart
find.text("Hello World"); - textContaining:找到一個顯示文字中包含特定字串的Text Widget
- 當文字可能不是固定字串時,例如:在一個棋局中顯示黑棋或白棋獲勝時,因為有可能會是"Black Wins"或"White Wins",此時就會需要使用到textContaining做部分比較
dartfind.textContaining("Wins");- 除了直接使用字串以外,也可使用正規表達式(RegExp)來找尋
dartfind.textContaining(RegExp(r"Wins$")); - widgetWithText:找到一個包含特定字串Text Widget的Widget
- 假設有一個文字按鈕使用FlatButton,在FlatButton的child再放上Text,此時我們就可以用這個方法來找到FlatButton
dartfind.widgetWithText(FlatButton, "Hello World")- 以上面的例子來說,假設畫面中有兩個Widget包含Text("Hello World"),一個是FlatButton,一個是Container,此時就會找到FlatButton,因為它符合第一個參數中的條件。
dartColumn( children: <Widget>[ FlatButton( onPressed: _incrementCounter, child: Text("Hello World"), ), Container( child: Text("Hello World"), ), ], ) - byKey:找到一個符合Key值的Widget dart
find.byKey(ValueKey("First Hello World"))- 以上面的例子來說,假設有兩個一樣的Text,就能正確找到Key值符合的Widget
dartColumn( children: <Widget>[ Text( "Increase", key: ValueKey("First Hello World"), ), Text( "Increase", ), ], )⇒ 如果是用UniqueKey這類的Key,因為無法在測試中產生一模一樣的Key,此時可以考慮使用其他find方法解決或者由外部注入Key的方式解決。
- byIcon:找到一個Icon符合的Icon Widget dart
find.byIcon(Icons.add); - widgetWithIcon:與widgetWithText類似,同樣是找到一個包含特定Icon Widget的Widget dart
find.widgetWithIcon(FlatButton, Icons.add); - byType:找到一個類別符合的Widget dart
find.byType(FlatButton); - byWidget:找到與傳入的Widget傳入Widget同一實例的Widget dart
find.byWidget(Text("Hello World"))- 假設我們想測試MyContainer是否有正常渲染child時,就可以使用byWidget找到預期的Widget並檢查
darttestWidgets('test my container', (WidgetTester tester) async { var text = Text("Hello World"); await tester.pumpWidget( createTestingWidget(MyContainer(child: text)), ); await tester.pump(); expect(find.byWidget(text), findsOneWidget); });dartclass MyContainer extends StatelessWidget { final Widget child; MyContainer({this.child}); @override Widget build(BuildContext context) { return Column( children: [ Text("Header"), child, Text("Footer"), ], ); } } - byWidgetPredicate:找到一個符合predicate回傳true的Widget
- 參數是一個predicate方法,在方法中可以比較很多東西,例如類別或Widget中的資料,透過比較Widget中的屬性,並回傳boolean值表示這個widget是否是目標Widget,是一個十分泛用的方法
dartfind.byWidgetPredicate( (widget) => widget is Text && widget.data == "Hello World") - byTooltip:找到符合message的Tooltip Widget dart
find.byTooltip("Hello World");⇒ 這個方法實際上是透過byWidgetPredicate實作的
- byElementType:與byType相似,不同的這個方法會找的是符合類別的Element dart
find.byElementType(InheritedElement); - byElementPredicate:與byWidgetPredicate相似,不同的是他的predicate參數傳入的是Element
- 這個方法可以用來比較Element中的屬性,例如自己做了一個MyCheckbox的StatefulWidget,就能用這個方法找出已選取的MyCheckbox
dartfind.byElementPredicate((element) { if(element is StatefulElement) { var state = element.state; return state is MyCheckboxState && state.isChecked; } return false; });dartclass MyCheckbox extends StatefulWidget { @override MyCheckboxState createState() => MyCheckboxState(); } class MyCheckboxState extends State<MyCheckbox> { bool isChecked; @override Widget build(BuildContext context) { ... } } - ancestor:在某個Widget的祖先中,找尋符合條件的Widget
- 從符合of參數的Widget開始往祖先找,直到找到符合matching參數的Widget,這兩個參數都可以使用前幾個find方法來決定條件
dartfind.ancestor(of: find.byType(MyContainer), matching: find.byWidget(text));⇒ widgetWithText, widgetWithIcon也是用這個方法實作
- descendant:在某個Widget的子孫中,找尋符合條件的Widget。
- 參數基本上與ancestor相似,只是搜尋的方向不同
dartfind.descendant(of: find.byWidget(text), matching: find.byType(MyContainer));
小結
Finder中有各式各樣的方法,在不同情境下使用不同的方法來找到想要的Widget,然後才能測試中正確的操作或驗證這些Widget,讓測試保護我們的產品代碼。