$30 off During Our Annual Pro Sale. View Details »

Write tests for Provider

Write tests for Provider

"Flutter Meetup Tokyo #9"でのLT資料です。
https://flutter-jp.connpass.com/event/126419/

Hiroki Matsue

May 22, 2019
Tweet

More Decks by Hiroki Matsue

Other Decks in Technology

Transcript

  1. Write tests for Provider
    Hiroki Matsue (@macs_6)
    May 22th, 2019
    Flutter Meetup Tokyo #9

    View Slide

  2. This talk is about
    How to test Provider classes

    View Slide

  3. What is Provider
    Google I/O 2019ͷFlutterʹ͓͚Δ࣮ફతͳstate؅ཧͷൃදͰ
    ঺հ͞Εͨύοέʔδ
    Pragmatic State Management in Flutter (Google I/O'19)
    https://youtu.be/d_m5csmrf7I

    View Slide

  4. A dependency injection system built with widgets for widgets.
    provider is mostly syntax sugar for InheritedWidget, to make
    common use-cases straightforward.
    https://github.com/rrousselGit/provider
    • ΄΅InheritedWidgetͷγϯλοΫεγϡΨʔ
    • BLoCΛ࢖͏࣌ʹ΋ࣗલͰProvider૬౰ͷ΋ͷΛ࣮૷͍ͯͨ͠
    ͸ͣ

    View Slide

  5. BLoC޲͚ʹॻ͍͍ͯͨInheritedWidgetΛ࢖ͬͨProvider
    class CartProvider extends InheritedWidget {
    final CartBloc cartBloc;
    CartProvider({
    Key key,
    CartBloc cartBloc,
    Widget child,
    }) : cartBloc = cartBloc ?? CartBloc(),
    super(key: key, child: child);
    @override
    bool updateShouldNotify(InheritedWidget oldWidget) => true;
    static CartBloc of(BuildContext context) =>
    (context.inheritFromWidgetOfExactType(CartProvider) as CartProvider)
    .cartBloc;
    }
    final cartBloc = CartProvider.of(context);
    https://github.com/filiph/stateexperiments/blob/19c321bbc62ac10855751124e3ea9701e583d6ea/shared/lib/src/bloc/cartprovider.dart

    View Slide

  6. ProviderύοέʔδΛ࢖͏ͱ͜͏ͳΔ
    Provider(
    builder: (_) => ExampleBloc(),
    dispose: (_, value) => value.dispose(),
    child: ExampleBloc(),
    );
    final bloc = Provider.of(context)

    View Slide

  7. શ෦BLoCͰॻͭ͘΋ΓͳΒbloc_providerύοέʔδ
    bloc is disposed automatically
    https://pub.dev/packages/bloc_provider
    BlocProvider(
    creator: (_context, _bag) => ExampleBloc(),
    child: Example(),
    )

    View Slide

  8. ProviderΛ࢖͏ͱ
    • stream΍RxDartΛ࢖Θͣʹෳ਺WidgetؒͷstateΛ؅ཧͰ͖
    ֶͯशίετ͕௿͍
    • ඞཁʹԠͯ͡BLoC΋ಋೖͰ͖Δ

    View Slide

  9. How to write tests?

    View Slide

  10. class Counter with ChangeNotifier {
    Counter(
    this._number,
    );
    factory Counter.withInitialValues({
    int number = 0,
    }) {
    return Counter(number);
    }
    int _number;
    int get number => _number;
    void increment() {
    _number++;
    notifyListeners();
    }
    }

    View Slide

  11. notifyListeners()Λແࢹ͢ΔͳΒ
    test('increment', () {
    final counter = Counter.withInitialValues();
    expect(counter.number, 0);
    counter.increment();
    expect(counter.number, 1);
    });

    View Slide

  12. ֤छύοέʔδͷςετͰ͸testWidgetsΛ࢖͍ͬͯΔ

    View Slide

  13. UIςετͱ͸෼཭ͯ͠
    widgetΛςετ޲͚ʹॳظԽ͢Δ

    View Slide

  14. testWidgets("increment", (tester) async {
    final key = GlobalKey();
    await tester.pumpWidget(
    ChangeNotifierProvider(
    builder: (context) => Counter.withInitialValues(),
    child: MaterialApp(
    home: Consumer(
    builder: (context, counter, child) => FlatButton(
    key: key,
    onPressed: () => counter.increment(),
    child: Text(counter.number.toString())),
    ),
    ),
    ),
    );
    expect(find.text('0'), findsOneWidget);
    expect(find.text('1'), findsNothing);
    await tester.tap(find.byKey(key));
    await tester.pumpAndSettle();
    expect(find.text('0'), findsNothing);
    expect(find.text('1'), findsOneWidget);
    });

    View Slide

  15. ֤छύοέʔδͷςετͰݟΒΕΔ޻෉

    View Slide

  16. ࢖͍ճ͢widgetΛอଘ͓ͯ͘͠
    final tree = ChangeNotifierProvider(
    builder: (context) => Counter.withInitialValues(),
    child: MaterialApp(
    home: Consumer(
    builder: (context, counter, child) => FlatButton(
    key: key,
    onPressed: () => counter.increment(),
    child: Text(counter.number.toString())),
    ),
    ),
    );

    View Slide

  17. ஋ʹରͯ͠௚઀ݕূΛߦ͏
    testWidgets("increment", (tester) async {
    final key = GlobalKey();
    int number;
    await tester.pumpWidget(
    ChangeNotifierProvider(
    builder: (context) => Counter.withInitialValues(),
    child: MaterialApp(
    home: Consumer(builder: (context, counter, child) {
    number = counter.number;
    return FlatButton(
    key: key,
    onPressed: () => counter.increment(),
    child: Container(),
    );
    }),
    ),
    ),
    );
    });

    View Slide

  18. notifierΛcontext͔Βऔಘͯ͠ݕূ͢Δ
    testWidgets('works with MultiProvider', (tester) async {
    final key = GlobalKey();
    var notifier = ChangeNotifier();
    await tester.pumpWidget(MultiProvider(
    providers: [
    ChangeNotifierProvider.value(notifier: notifier),
    ],
    child: Container(key: key),
    ));
    expect(Provider.of(key.currentContext), notifier);
    });
    https://github.com/rrousselGit/provider/blob/fe778651565f7563dc4a1b2afb513119c5424761/test/changenotifierprovider_test.dart#L11-

    View Slide

  19. ·ͱΊ
    • testWidgets Λ࢖ͬͯςετ͸ॻ͘
    • ֤छύοέʔδΛݟΔͱςετͷهड़ΛݮΒ͢޻෉͕৭ʑݟ
    ΒΕΔ
    • ର৅ͷwidgetΛ࢖͍ճ͢
    • ม਺ʹೖΕͯݕূ͢Δ
    • notifierΛऔಘ͢Δ

    View Slide

  20. References
    • Developer Questͷςετ: https://github.com/2d-inc/
    developerquest/blob/master/test/worldtest.dart
    • Providerύοέʔδͷςετ: https://github.com/
    rrousselGit/provider/blob/
    fe778651565f7563dc4a1b2afb513119c5424761/test/
    changenotifierprovider_test.dart
    • FlutterຊମͷChangeNotifierςετ: https://github.com/
    flutter/flutter/blob/

    View Slide

  21. Thanks

    View Slide