The translation of the material was prepared as part of the online course " Flutter Mobile Developer ".
We also invite everyone to a free two-day intensive "Creating a Flutter App for Web, iOS and Android" . On the intensive course, we will learn exactly how Flutter allows you to create applications for the Web platform, and why it is now stable functionality; how the web assembly works. Let's write an application with networking. Details and registration here .
This is a continuation of the first part of the article on testing widgets in Flutter .
Let's continue our exploration of the widget testing process.
, testWidgets()
. , , , β . , , , .
:
.
test.
testWidgets()
, .
.
?
:
.
.
, . :
.
- (, ).
(, ), .
, .
, , . test:
void main() {
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
},
);
}
, WidgetTester
, . .
, pumpWidget()
:
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
),
),
);
},
);
( await
, .)
.
WidgetTester
, .
-
, «» , .
, , , β , . .
, ? -, Finder
. ( , .)
, - β , , . .
:
find.byType()
Text:
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Text('Hi there!'),
),
),
),
);
var finder = find.byType(Text);
},
);
- CommonFinders
find
. byType()
. , , . , Text
, , :
find.text()
Text, find.text()
:
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Text('Hi there!'),
),
),
),
);
var finder = find.text('Hi there!');
},
);
EditableText
, TextField
.
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
var controller = TextEditingController.fromValue(TextEditingValue(text: 'Hi there!'));
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: TextField(controller: controller,),
),
),
),
);
var finder = find.text('Hi there!');
},
);
find.byKey()
β :
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
child: Icon(
Icons.add,
key: Key('demoKey'),
),
),
),
),
);
var finder = find.byKey(Key('demoKey'));
},
);
find.descendant() find.ancestor()
, , ( -).
, , Center, . :
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
key: Key('demoKey'),
child: Icon(Icons.add),
),
),
),
);
var finder = find.descendant(
of: find.byKey(Key('demoKey')),
matching: find.byType(Icon),
);
},
);
, Center ( of
) , -.
find.ancestor()
, , , , of
.
Center, :
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
key: Key('demoKey'),
child: Icon(Icons.add),
),
),
),
);
var finder = find.ancestor(
of: find.byType(Icon),
matching: find.byKey(Key('demoKey')),
);
},
);
-
find.xxxx()
Finder
. ?
, , -, , . BadlyWrittenWidgetFinder
.
MatchFinder
.
class BadlyWrittenWidgetFinder extends MatchFinder {
@override
// TODO: implement description
String get description => throw UnimplementedError();
@override
bool matches(Element candidate) {
// TODO: implement matches
throw UnimplementedError();
}
}
2. matches()
, . , null
:
class BadlyWrittenWidgetFinder extends MatchFinder {
BadlyWrittenWidgetFinder({bool skipOffstage = true})
: super(skipOffstage: skipOffstage);
@override
String get description => 'Finds icons with no key';
@override
bool matches(Element candidate) {
final Widget widget = candidate.widget;
return widget is Icon && widget.key == null;
}
}
3. , - CommonFinders
( find
):
extension BadlyWrittenWidget on CommonFinders {
Finder byBadlyWrittenWidget({bool skipOffstage = true }) => BadlyWrittenWidgetFinder(skipOffstage: skipOffstage);
}
4. - , :
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: Center(
key: Key('demoKey'),
child: Icon(Icons.add),
),
),
),
);
var finder = find.byBadlyWrittenWidget();
},
);
, -, WidgetTester
.
, WidgetTester
, , .
WidgetTester
. , , . :
setState()
, .
setState()
, , . ? pump
.
pump
:
pump()
( ),pumpWidget()
,pumpAndSettle()
pump()
, ( ).
pumpWidget()
, pumpWidget()
. runApp()
, , pump()
. .
pump()
pump()
, . , :
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
var count = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Text('$count'),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
count++;
});
},
),
),
);
}
}
FloatingActionButton
, -.
: , , 1:
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(CounterWidget());
var finder = find.byIcon(Icons.add);
await tester.tap(finder);
// Ignore this line for now
// It just verifies that the value is what we expect it to be
expect(find.text('1'), findsOneWidget);
},
);
:
, Text
, , setState()
, . pump()
:
testWidgets(
'Test description',
(WidgetTester tester) async {
// Write your test here
await tester.pumpWidget(CounterWidget());
var finder = find.byIcon(Icons.add);
await tester.tap(finder);
await tester.pump();
// Ignore this line for now
// It just verifies that the value is what we expect it to be
expect(find.text('1'), findsOneWidget);
},
);
:
, pump()
β :
await tester.pump(Duration(seconds: 1));
, , .
pump
: . EnginePhase
:
enum EnginePhase {
/// The build phase in the widgets library. See [BuildOwner.buildScope].
build,
/// The layout phase in the rendering library. See [PipelineOwner.flushLayout].
layout,
/// The compositing bits update phase in the rendering library. See
/// [PipelineOwner.flushCompositingBits].
compositingBits,
/// The paint phase in the rendering library. See [PipelineOwner.flushPaint].
paint,
/// The compositing phase in the rendering library. See
/// [RenderView.compositeFrame]. This is the phase in which data is sent to
/// the GPU. If semantics are not enabled, then this is the last phase.
composite,
/// The semantics building phase in the rendering library. See
/// [PipelineOwner.flushSemantics].
flushSemantics,
/// The final phase in the rendering library, wherein semantics information is
/// sent to the embedder. See [SemanticsOwner.sendSemanticsUpdate].
sendSemanticsUpdate,
}
await tester.pump(Duration.zero, EnginePhase.paint);
. , . .
pumpAndSettle()
pumpAndSettle()
β , , pump, , . .
( ), β -, .
await tester.pumpAndSettle(
Duration(milliseconds: 10),
EnginePhase.paint,
Duration(minutes: 1),
);
WidgetTester
Β« + Β». :
tester.drag()
, - . , X Y:
var finder = find.byIcon(Icons.add);
var moveBy = Offset(100, 100);
var slopeX = 1.0;
var slopeY = 1.0;
await tester.drag(finder, moveBy, touchSlopX: slopeX, touchSlopY: slopeY);
, tester.timedDrag()
:
var finder = find.byIcon(Icons.add);
var moveBy = Offset(100, 100);
var dragDuration = Duration(seconds: 1);
await tester.timedDrag(finder, moveBy, dragDuration);
, -, tester.dragFrom()
, .
var dragFrom = Offset(250, 300);
var moveBy = Offset(100, 100);
var slopeX = 1.0;
var slopeY = 1.0;
await tester.dragFrom(dragFrom, moveBy, touchSlopX: slopeX, touchSlopY: slopeY);
β tester.timedDragFrom()
.
var dragFrom = Offset(250, 300);
var moveBy = Offset(100, 100);
var duration = Duration(seconds: 1);
await tester.timedDragFrom(dragFrom, moveBy, duration);
. ,
tester.fling()
tester.drag()
.
: «» .
:
var dragFrom = Offset(250, 300);
var gesture = await tester.startGesture(dragFrom);
, .
:
var dragFrom = Offset(250, 300);
var gesture = await tester.startGesture(dragFrom);
await gesture.moveBy(Offset(50.0, 0));
await gesture.moveBy(Offset(0.0, -50.0));
await gesture.moveBy(Offset(-50.0, 0));
await gesture.moveBy(Offset(0.0, 50.0));
await gesture.up();
, , . , , , , , ( , β , - , ).
Finder
WidgetTester
. β .
Β« Flutter Web, iOS AndroidΒ».