Uma análise aprofundada de widgets de teste no Flutter. Parte II. Classes Finder e WidgetTester

A tradução do material foi elaborada como parte do curso online Flutter Mobile Developer ”.



Também convidamos todos para um curso intensivo gratuito de dois dias “Criando um aplicativo Flutter para Web, iOS e Android” . No curso intensivo, aprenderemos exatamente como o Flutter permite que você crie aplicativos para a plataforma da Web e por que agora é uma funcionalidade estável; como a web assembly funciona. Vamos escrever um aplicativo com rede. Detalhes e registro aqui .






Esta é uma continuação da primeira parte do artigo sobre como testar widgets no Flutter .





Vamos continuar nossa exploração do processo de teste do widget. 





, testWidgets()



. , , , — . , , , .





:

  1. .





  2. test.





  3. testWidgets()



    , .





.





?

:





  1. .





  2. .





, . :





  1. .





  2. - (, ).





  3. (, ), .





  4. , .





, , . 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



.





  1.  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 Mobile Developer".





« Flutter Web, iOS Android».








All Articles